RC4加密算法的原理及實現

       RC4於1987年提出,和DES算法同樣。是一種對稱加密算法,也就是說使用的密鑰爲單鑰(或稱爲私鑰)。ios

但不一樣於DES的是。RC4不是對明文進行分組處理,而是字節流的方式依次加密明文中的每一個字節。解密的時候也是依次對密文中的每一個字節進行解密。算法

       RC4算法的特色是算法簡單,執行速度快。而且密鑰長度是可變的,可變範圍爲1-256字節(8-2048比特),在如今技術支持的前提下,當密鑰長度爲128比特時,用暴力法搜索密鑰已經不太可行,因此可以預見RC4的密鑰範圍任然可以在從此至關長的時間裏抵禦暴力搜索密鑰的攻擊。實際上,如今也沒有找到對於128bit密鑰長度的RC4加密算法的有效攻擊方法。數組

在介紹RC4算法原理以前。先看看算法中的幾個關鍵變量:安全

       一、密鑰流:RC4算法的關鍵是依據明文和密鑰生成相應的密鑰流,密鑰流的長度和明文的長度是相應的。也就是說明文的長度是500字節,那麼密鑰流也是500字節。固然,加密生成的密文也是500字節。因爲密文第i字節=明文第i字節^密鑰流第i字節;網絡

       二、狀態向量S:長度爲256。S[0],S[1].....S[255]。每個單元都是一個字節。算法執行的不論何時。S都包含0-255的8比特數的排列組合,僅僅只是值的位置發生了變換;函數

       三、暫時向量T:長度也爲256,每個單元也是一個字節。加密

假設密鑰的長度是256字節。就直接把密鑰的值賦給T,不然,輪轉地將密鑰的每個字節賦給T。spa

       四、密鑰K:長度爲1-256字節。注意密鑰的長度keylen與明文長度、密鑰流的長度沒有一定關係。一般密鑰的長度趣味16字節(128比特)。code


RC4的原理分爲三步:blog

一、初始化S和T

for i=0 to 255 do

   S[i]=i;

   T[i]=K[ imodkeylen ];

二、初始排列S

j=0;

for i=0 to 255 do

   j= ( j+S[i]+T[i])mod256;

   swap(S[i],S[j]);

三、產生密鑰流

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

解密文件:我愛小兔子。


這是第一篇網絡安全方面的博客。若有錯誤,歡迎指正!

相關文章
相關標籤/搜索