關於最原始的RC4在ARM中的運用

RC4加密算法是大名鼎鼎的RSA三人組中的頭號人物Ronald Rivest在1987年設計的密鑰長度可變的流加密算法簇。之所以稱其爲簇,是由於其核心部分的S-box長度可爲任意,但一般爲256字節。該算法的速度可以達到DES加密的10倍左右,且具有很高級別的非線性。RC4起初是用於保護商業機密的。但是在1994年9月,它的算法被髮布在互聯網上,也就不再有什麼商業機密了。RC4也被叫做ARC4(Alleged RC4——所謂的RC4),因爲RSA從來就沒有正式發佈過這個算法。

RC4算法的原理很簡單,包括初始化算法(KSA)和僞隨機子密碼生成算法(PRGA)兩大部分。假設S-box的長度爲256,密鑰長度爲Len。

在初始化的過程中,祕鑰的主要功能是將S-box攪亂,i確保S-box的每個元素都得到處理,j保證S-box的攪亂是隨機的。而不同的S-box在經過僞隨機子密碼生成算法的處理後可以得到不同的子祕鑰序列,將S-box和明文進行xor運算,得到密文,解密過程也完全相同。

程序:(將ARM的指定文件的明文按行加密成密文,再次運行密文將按行解爲明文)

#include<stdio.h>
#include<memory.h>
#include<string.h>
#include<stdlib.h>
#define buf_size 1024		//讀取明文的最大字節數
typedef struct rc4_key		//存放密鑰序列
{     
   	unsigned char state[256];      
   	unsigned char x;       
   	unsigned char y;
} rc4_key;
typedef struct rc4_mkey		//備份密鑰序列
{     
   	unsigned char state[256];      
   	unsigned char x;       
   	unsigned char y;
} rc4_mkey;
#define swap_byte(x,y) t = *(x); *(x) = *(y); *(y) = t
void prepare_key(unsigned char *key_data_ptr, int key_data_len, rc4_key *key)	//初始化函數
{
  	int i;
  	unsigned char t;
  	unsigned char swapByte;
  	unsigned char index1;
  	unsigned char index2;
  	unsigned char* state;
  	short counter;
  	state = &key->state[0];
  	for(counter = 0; counter < 256; counter++)
	{
  		state[counter] = counter;
	}
  	key->x = 0;
  	key->y = 0;
  	index1 = 0;
  	index2 = 0;
  	for(counter = 0; counter < 256; counter++)
  	{
    	index2 = (key_data_ptr[index1] + state[counter] + index2) % 256;
    	swap_byte(&state[counter], &state[index2]);
    	index1 = (index1 + 1) % key_data_len;
  	}
}
void rc4(unsigned char *buffer_ptr, int buffer_len, rc4_key *key)				//加解密
{
  	unsigned char t;
  	unsigned char x;
  	unsigned char y;
  	unsigned char* state;
  	unsigned char xorIndex;
  	short counter;
  	x = key->x;
  	y = key->y;
  	state = &key->state[0];
  	for(counter = 0; counter < buffer_len; counter++)
  	{
    	x = (x + 1) % 256;
    	y = (state[x] + y) % 256;
    	swap_byte(&state[x], &state[y]);
    	xorIndex = (state[x] + state[y]) % 256;
    	buffer_ptr[counter] ^= state[xorIndex];
  	}
  	key->x = x;
  	key->y = y;
}
void coding_rc4()
{
  	char seed[256];     														
  	char data[512] = {"just123"};						//密鑰
  	char fname[512] = {"/mnt/key.txt"};					//加密文件路徑
  	char *tn;
  	char buf[buf_size];
	char num[10];
  	char digit[5];
  	int hex, rd,i;
  	int n;
  	rc4_key key;										//密鑰序列結構體			
	rc4_mkey mkey;										//備份密鑰序列結構體
  	FILE *fp,*des;
  	n = strlen(data);									//讀取密鑰長度
  	if(n>512)											//對密鑰進行處理使之更好的可是別
  	{
       	fprintf(stderr,"can't tolerate key longer than 512 characters./n");
       	exit(1);
  	}
  	if (n&1)     										//n is odd number
  	{
    	strcat(data,"0");
    	n++;     										//convert n to even number
  	}
  	n/=2;
  	memset(digit,0,5*sizeof(char));
  	strcpy(digit,"AA");
  	for (i=0;i<n;i++)
  	{
    	digit[2] = data[i*2];
    	digit[3] = data[i*2+1];
    	sscanf(digit,"%x",&hex);     					//characters in the file key.txt are better to be recognizable hex numbers
    	seed[i] = hex;     								//only reserve the two lower hex numbers in varible 'hex'
  	}
  	prepare_key(seed,n,&key);							//將我們設定好的祕鑰對state數組進行攪亂,得到祕鑰序列。
	strcpy(mkey.state,key.state);						//備份密鑰序列,後面加密時密鑰序列將被打亂
	mkey.x = key.x;
	mkey.y = key.y;
  	if((fp=fopen(fname,"r"))==NULL)						//打開加密文件
	{
       	exit(1);
	}
  	tn=strdup(fname);
  	strcat(fname,".en");
  	if((des=fopen(fname,"w"))==NULL)					//打開備份加密文件
    {
   		exit(1);
	} 
  	fgets(buf,60,fp);									//讀取明文第一行
	rd = strlen(buf);									//讀取第一行長度,便於後面的處理
	if(buf[rd-2]=='\r')									//win7下換行爲\r\n  linux下爲\n
	{
		rd = rd - 1;
	}
	buf[rd-1] = '\0';
    rc4(buf,rd-1,&key);									//加密第一行明文
	fgets(num,60,fp);									//讀取第二行明文
	rd = strlen(num);
	if(num[rd-1]!='\n')									//同上處理
	{
		rd = rd + 1;
	}
	num[rd-1] = '\0';
	strcpy(key.state,mkey.state);						//回覆被打亂的密鑰序列
	key.x = mkey.x;
	key.y = mkey.y;
    rc4(num,rd-1,&key);									//加密第二行明文
	strcat(buf,"\n");
	strcat(buf,num);
	strcat(buf,"\n");
    fwrite(buf,1,60,des);								//將加密的一二行寫入備份文件
  	fclose(fp);
  	fclose(des);
  	sprintf(fname,"rm %s",tn);							//刪除原明文文件,用密文文件替代
  	system(fname);
  	sprintf(fname,"mv %s.en %s",tn,tn);
  	system(fname);
}
int main()
{
	coding_rc4();
}


要注意的是,如果用該程序的RC4()函數那祕鑰序列要先進行備份,調用RC4()後祕鑰序列將會被打亂,導致下次的祕鑰序列和這次的不同,所以備份後下次再調用RC4()函數時進行恢復,使每次加密的祕鑰序列相同。

按行加密要注意的是提取出行信息後要去掉換行符,換行符在win7下是\r\n、在linux下爲\n。去掉換行符後對行裏的內容進行加解密,這樣才能更準確。

漏洞:(摘錄於百度百科)

由於RC4算法加密是採用的xor,所以,一旦子密鑰序列出現了重複,密文就有可能被破解。關於如何破解xor加密,請參看Bruce Schneier的Applied Cryptography一書的1.4節Simple XOR,在此我就不細說了。那麼,RC4算法生成的子祕鑰序列是否會出現重複呢?由於存在部分弱密鑰,使得子密鑰序列在不到100萬字節內就發生了完全的重複,如果是部分重複,則可能在不到10萬字節內就能發生重複,因此,推薦在使用RC4算法時,必須對加密密鑰進行測試,判斷其是否爲弱密鑰。其不足主要體現於,在無線網絡中IV(初始化向量)不變性漏洞。
                                                                                                                                                                                                                         --------------------------------------------------------------海魚

發佈了54 篇原創文章 · 獲贊 2 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章