RC4加密算法的原理及实现
RC4于1987年提出,和DES算法一样。是一种对称加密算法,也就是说使用的密钥为单钥(或称为私钥)。
但不同于DES的是。RC4不是对明文进行分组处理,而是字节流的方式依次加密明文中的每个字节。解密的时候也是依次对密文中的每个字节进行解密。
RC4算法的特点是算法简单,执行速度快。并且密钥长度是可变的,可变范围为1-256字节(8-2048比特),在现在技术支持的前提下,当密钥长度为128比特时,用暴力法搜索密钥已经不太可行,所以能够预见RC4的密钥范围任然能够在今后相当长的时间里抵御暴力搜索密钥的攻击。实际上,现在也没有找到对于128bit密钥长度的RC4加密算法的有效攻击方法。
在介绍RC4算法原理之前。先看看算法中的几个关键变量:
1、密钥流:RC4算法的关键是依据明文和密钥生成相应的密钥流,密钥流的长度和明文的长度是相应的。也就是说明文的长度是500字节,那么密钥流也是500字节。当然,加密生成的密文也是500字节。由于密文第i字节=明文第i字节^密钥流第i字节;
2、状态向量S:长度为256。S[0],S[1].....S[255]。每一个单元都是一个字节。算法执行的不论什么时候。S都包含0-255的8比特数的排列组合,仅仅只是值的位置发生了变换;
3、暂时向量T:长度也为256,每一个单元也是一个字节。
假设密钥的长度是256字节。就直接把密钥的值赋给T,否则,轮转地将密钥的每一个字节赋给T。
4、密钥K:长度为1-256字节。注意密钥的长度keylen与明文长度、密钥流的长度没有必定关系。通常密钥的长度趣味16字节(128比特)。
RC4的原理分为三步:
1、初始化S和T
for i=0 to 255 do
S[i]=i;
T[i]=K[ imodkeylen ];
2、初始排列S
j=0;
for i=0 to 255 do
j= ( j+S[i]+T[i])mod256;
swap(S[i],S[j]);
3、产生密钥流
i,j=0;
for r=0 to len do //r为明文长度,r字节
i=(i+1) mod 256;
j=(j+S[i])mod 256;
swap(S[i],S[j]);
t=(S[i]+S[j])mod 256;
k[r]=S[t];
以下给出RC4加密解密的C++实现:
加密类:
/* 加密类 */ class RC4 { public: /* 构造函数。參数为密钥长度 */ RC4(int kl):keylen(kl) { srand((unsigned)time(NULL)); for(int i=0;i<kl;++i){ //随机生产长度为keylen字节的密钥 int tmp=rand()%256; K.push_back(char(tmp)); } } /* 由明文产生密文 */ void encryption(const string &,const string &,const string &); private: unsigned char S[256]; //状态向量,共256字节 unsigned char T[256]; //暂时向量,共256字节 int keylen; //密钥长度,keylen个字节,取值范围为1-256 vector<char> K; //可变长度密钥 vector<char> k; //密钥流 /* 初始化状态向量S和暂时向量T,供keyStream方法调用 */ void initial() { for(int i=0;i<256;++i){ S[i]=i; T[i]=K[i%keylen]; } } /* 初始排列状态向量S。供keyStream方法调用 */ void rangeS() { int j=0; for(int i=0;i<256;++i){ j=(j+S[i]+T[i])%256; //cout<<"j="<<j<<endl; S[i]=S[i]+S[j]; S[j]=S[i]-S[j]; S[i]=S[i]-S[j]; } } /* 生成密钥流 len:明文为len个字节 */ void keyStream(int len); }; void RC4::keyStream(int len) { initial(); rangeS(); int i=0,j=0,t; while(len--){ i=(i+1)%256; j=(j+S[i])%256; S[i]=S[i]+S[j]; S[j]=S[i]-S[j]; S[i]=S[i]-S[j]; t=(S[i]+S[j])%256; k.push_back(S[t]); } } void RC4::encryption(const string &plaintext,const string &ks,const string &ciphertext) { ifstream in; ofstream out,outks; in.open(plaintext); //获取输入流的长度 in.seekg(0,ios::end); int lenFile=in.tellg(); in.seekg(0, ios::beg); //生产密钥流 keyStream(lenFile); outks.open(ks); for(int i=0;i<lenFile;++i){ outks<<(k[i]); } outks.close(); //明文内容读入bits中 unsigned char *bits=new unsigned char[lenFile]; in.read((char *)bits,lenFile); in.close(); out.open(ciphertext); //将明文按字节依次与密钥流异或后输出到密文文件里 for(int i=0;i<lenFile;++i){ out<<(unsigned char)(bits[i]^k[i]); } <span style="white-space:pre"> </span>out.close(); delete []bits; }解密类:
/* 解密类 */ class RC4_decryption{ public: /* 构造函数。參数为密钥流文件和密文文件 */ RC4_decryption(const string ks,const string ct):keystream(ks),ciphertext(ct) {} /* 解密方法,參数为解密文件名称 */ void decryption(const string &); private: string ciphertext,keystream; }; void RC4_decryption::decryption(const string &res){ ifstream inks,incp; ofstream out; inks.open(keystream); incp.open(ciphertext); //计算密文长度 inks.seekg(0,ios::end); const int lenFile=inks.tellg(); inks.seekg(0, ios::beg); //读入密钥流 unsigned char *bitKey=new unsigned char[lenFile]; inks.read((char *)bitKey,lenFile); inks.close(); //读入密文 unsigned char *bitCip=new unsigned char[lenFile]; incp.read((char *)bitCip,lenFile); incp.close(); //解密后结果输出到解密文件 out.open(res); for(int i=0;i<lenFile;++i) out<<(unsigned char)(bitKey[i]^bitCip[i]); out.close(); }
程序实现时,须要注意的是,状态向量数组S和暂时向量数组T的类型应设为unsigned char,而不是char。由于在一些机器下,将char默认做为signed char看待,在算法中计算下标i,j的时候,会涉及char转int。假设是signed的char。那么将char的8位复制到int的低8位后,还会依据char的符号为,在int的高位补0或1。由于密钥是随机产生的,假设遇到密钥的某个字节的高位为1的话,那么计算得到的数组下标为负数,就会越界。
程序执行演示样例
main函数:
int main(){ RC4 rc4(16); //密钥长16字节 rc4.encryption("明文.txt","密钥流.txt","密文.txt"); RC4_decryption decrypt("密钥流.txt","密文.txt"); decrypt.decryption("解密文件.txt"); }
明文:我爱小兔子!
密文:'柀L&t餥6洲
密钥流:镈膺嚬3屽u
解密文件:我爱小兔子。
这是第一篇网络安全方面的博客。如有错误,欢迎指正!