赞
踩
在密码学中,RC4(来自Rivest Cipher 4的缩写)是一种流加密算法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法。RC4是有线等效加密(WEP)中采用的加密算法,也曾经是TLS可采用的算法之一。
RC4序列密码是美国RSA数据安全公司设计的一种序列密码。其实最开始这家公司并没有公布RC4算法的设计细节,在人们已经通过逆向分析得到了算法之后,在97年RSA公司才公布了RC4密码算法。
RC4算法的优点就是算法简单、高效,适合软件实现。
RC4加解密相当于是对合运算,所以只要输入密钥相同,那么执行相同的操作即可对数据实现加密和解密。
而RC4和基于以为寄存器的序列密码不同,它是基于非线性数据表变换的序列密码,它以一个足够大的数据表为基础,对表进行非线性变化,从而产生非线性的密钥序列。
基本流程如下:
首先,RC4取一个256字节构成的S表,并引入一个256字节的辅助表R
对S表进行线性填充
即初始化S表,另,S[n] = n; (0<=n<=255)
for(int i = 0;i < ROOM;i++)//初始化S表
S[i] = i;
用种子密钥填充R表,如果种子密钥的长度小于R表的长度(256),则依次重复填充,直至将R表填满
其实依次重复填充的弊端十分明显:
例如用户输入了密钥a,那么重复填充之后R表中全部为a
而用户输了密钥aa,那么重复填充之后R表也是全部为a
这样显然不是一个好的结果
还有一种做法是做Padding,即若密钥长度小于R表长度时,用固定格式的 padding来填充剩下的部分。
用R表对S表进行随机化处理
其操作算法如下:
①J = 0;
②对于I = 0 : 255
J = J + S[i] + R[j] mod 256;
swap(S[i],S[j]);//交换S[i]与S[j]
代码实现:
void random(unsigned char *S,std::string R,int length)//随机化S表 {
int i;
unsigned char temp;
unsigned char j = 0;
//R表长度肯定小于等于256,注意模其长度使得不超过其下标并达到重复效果
for( i = 0 ; i < ROOM ; i++ ){
j = j + S[i] + R[i % length];
temp = S[j];
S[j] = S[i];
S[i] = temp;
}
}
加密解密核心功能
生成了随机化S表之后,就可以对数据执行加密或解密算法了。
RC4在加密解密时可以看成一个有限状态自动机,通过不断产生新的状态来产生出密钥字节。
RC4的下一状态函数定义如下:
①I = 0 ,J = 0;//初始化状态
②I = I + 1 mod 256;
③J = J + S[i] mod 256
④swap(S[i],S[j]);//交换S[i]与S[j]
而RC4的输出函数定义为:
①h = S[i] + S[j] mod 256;
②k = S[h];
输出函数的输出k即产生出的密钥字节,让RC4有限状态自动机一个一个运转,便输出密钥字节序列。
在加密时,将密钥字节k与明文字节模二加便完成了加密,解密时将密钥字节k与密文字节模二加就完成了解密。
代码实现:
for( num = 0 , i = 0 , j = 0 ; num < size ; num++ ) //逐位生成序列
{
temp = S[i];
j = j + temp;
S[i] = S[j];
S[j] = temp;
temp = temp + S[i];
data[num] ^= S[temp];//data即加密或解密出的结果
i += 1;
}
通过以上流程,RC4算法就基本完成了,而我们对一些功能和流程进行稍许加工,例如读取文件大小,满足用户加密解密的流程控制等。
最后一个小demo如下:
#include <string> #include <stdlib.h> #include <iostream> #include <windows.h> #define ROOM 256 void random(unsigned char *S,std::string R,int length);//随机化S表 bool Encryption(unsigned char *S,long size,char *file_name,int mode); //加解密文件 因为是对合运算,所以只需要一个函数,用mode控制加密还是解密 long file_size(char* filename); //读取文件长度 int main (int argc, char *argv[]) { int Option; //功能选择 unsigned char S[ROOM]; //S核心表 long file_length; //文件字节大小 char R_temp[ROOM + 1]; //R表的备份表,预留一个'\0' std::string R; //R表 while(1) { R.clear(); //清空数据 file_length = 0; R_temp[0] = '\0'; Option = -1; std::cout << "Welcome! Please choose the Option below:" << std::endl;//模式选择 std::cout << "input 1:encrption;" << std::endl; std::cout << "input 2:decrption;" << std::endl; std::cout << "input 0:exit." << std::endl; std::cin >> Option; while( std::cin.fail() )//输入出错处理 { std::cin.clear(); //复位标志位 std::cout << "数据类型不对,请重新输入:"; fflush(stdin); //清空缓冲区 std::cin >> Option; } if(Option == 0) break; //0则直接退出 else if(Option != 1 && Option != 2) { std::cout << "输入选择有误,请重新输入:" << std::endl; //其他数字 continue; } for(int i = 0;i < ROOM;i++)//初始化S表 S[i] = i; std::cout << "请输入您的种子密钥" <<std::endl; fflush(stdin); //清空之前的输入缓冲区 std::cin.get(R_temp,ROOM); //保证忽略输入中的空格 R = R_temp; int R_length = R.length(); //定义length为R表中字符个数 random(S,R,R_length); //随机化S表 if(Option == 1) { char file_name[16]; //定义加密文件名 std::cout << "请输入您要加密的文件" << std::endl; fflush(stdin); //清空之前的输入缓冲区 std::cin.get(file_name,16); //保证忽略输入中的空格 file_length = file_size(file_name);//计算文件字节大小 if(Encryption(S,file_length,file_name,Option)) //加密成功 { std::cout << "退出请输入0,输入其他将回到初始界面" << std::endl; std::cin >> Option; } else //加密失败,3s后返回主页面 { std::cout << "加密失败!" << std::endl; for( int temp = 3 ; temp > 0 ; temp-- ) { std::cout << temp << "s后将回到初始界面" << std::endl; Sleep(1000); } } } else if(Option == 2) { char file_name[16]; //定义解密文件名 std::cout << "请输入您要解密的文件" <<std::endl; fflush(stdin); //清空之前的输入缓冲区 std::cin.get(file_name,16); //保证忽略输入中的空格 file_length = file_size(file_name);//计算文件字节大小 if(Encryption(S,file_length,file_name,Option)) //解密成功 { std::cout << "退出请输入0,输入其他将回到初始界面" << std::endl; std::cin >> Option; } else //解密失败,3s后返回主页面 { std::cout << "解密失败!" << std::endl; for( int temp = 3 ; temp > 0 ; temp-- ) { std::cout << temp << "s后将回到初始界面" << std::endl; Sleep(1000); } } } if(Option == 0) break; } std::cout << "Thanks" << std::endl; return 0; } void random(unsigned char *S,std::string R,int length)//随机化S表 { int i; unsigned char temp; unsigned char j = 0; //R表长度肯定小于等于256,注意模其长度使得不超过其下标并达到重复效果 for( i = 0 ; i < ROOM ; i++ ) { j = j + S[i] + R[i % length]; temp = S[j]; S[j] = S[i]; S[i] = temp; } } bool Encryption(unsigned char *S,long size,char *file_name,int mode)//加解密文件 因为是对合运算,所以只需要一个函数,用mode控制加密还是解密 { FILE *pr; //定义读文件指针pr pr = fopen(file_name,"rb"); //只读 if(pr == NULL) //如果打开文件错误,则退出 { std::cout << "用户输入文件打开失败!" << std::endl; return false; } FILE *pw; //定义写文件指针pw unsigned char *data; //存储原始文件数据,并在运算过程中充当输出序列与原序列的异或结果 unsigned char i,j,temp; long num; data = (unsigned char *)malloc(size * sizeof(unsigned char));//分配内存 if(mode == 1) pw = fopen("encryption.txt","wb"); //模式为只写且刷新文件 else pw = fopen("decryption.txt","wb"); //模式为只写且刷新文件 if(pw == NULL) //如果打开文件错误,则退出 { std::cout << "输出文件时出错!" << std::endl; return false; } fread(data,sizeof(char),size,pr);//读取二进制流(需要加/解密的文件) for( num = 0 , i = 0 , j = 0 ; num < size ; num++ ) //逐位生成序列 { temp = S[i]; j = j + temp; S[i] = S[j]; S[j] = temp; temp = temp + S[i]; data[num] ^= S[temp]; i += 1; } if(mode == 1) std::cout << "功能完成,生成encryption.txt文件" << std::endl; else std::cout << "功能完成,生成decryption.txt文件" << std::endl; fwrite(data,sizeof(unsigned char),size,pw);//写入二进制流 fclose(pw);//关闭文件流 fclose(pr); free(data);//释放内存 return true; } long file_size(char *filename) //读取文件长度 { FILE *fp = fopen(filename,"r"); if(!fp) return -1; fseek(fp,0L,SEEK_END); //利用fseek函数将指针定位在文件结尾的位置 long size = ftell(fp); //利用ftell函数返回指针相对于文件开头的位置,以字节计算 fclose(fp); return size; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。