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

解密文件:我愛小兔子。


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM