美文网首页
RC4加解密

RC4加解密

作者: 客昂康 | 来源:发表于2019-05-10 18:42 被阅读0次
    • RC4算法
      rc4是流式加密算法,加密和解密都是按字节逐个处理。设明文是in、密文是out、密钥流是s,对于加密,out[n] = in[n] ^ s[n],对于解密,in[n] = out[n] ^ s[n]。也就是说,明文、密文、密钥流的长度都相同,加密和解密的过程也完全相同。用伪代码举例:
    //假设有如下明文、密钥、缓存区
    unsigned char data[100];     //100字节的明文
    unsigned char stream[100];   //100字节的密钥流
    unsigned char buffer1[100];  //明文加密后的密文的储存区
    unsigned char buffer2[100];  //密文解密后的明文的储存区
    
    //加密过程
    for(i=0; i<100; i++){
      buffer1[i] = data[i] ^ stream[i];
    }
    
    //解密过程
    for(i=0; i<100; i++){
      buffer2[i] = buffer1[i] ^ stream[i];
    }
    

    如何生成密钥流呢?分以下3步生成密钥流(伪代码):

    //第一步,初始化一个大小为256的状态数组,其值依次是 0、1、2、...、254、255。
    unsigned char state[256] = {0, 1, 2, 3, ..., 253, 254, 255};
    
    //第二步,用密码搅乱状态数组,假设密码是key[],密码长度是keyLen。
    int j = 0;                                    //j初始值为0。
    for(i=0; i<256; i++){
      j = (j + state[i] + key[i%keyLen]) % 256;   //修改j。如果密码的长度不够256,那就循环使用密码。
      SWP(state[i], state[j]);                    //交换 state[i] 和 state[j]。
    }
    
    //第三步,生成密钥流。例如生成100字节密钥流,密钥流叫做 stream[]。
    int i = 0;                                    //i初始值为0。
    int j = 0;                                    //j初始值为0。
    for(n=0; n<100; n++){
      i = (i + 1) % 256;                          //修改i
      j = (j + state[i]) % 256;                   //修改j
      sum = state[i] + state[j];                  //计算 state[i] 和 state[j] 的和。
      SWP(state[i], state[j]);                    //交换 state[i] 和 state[j]。
      stream[n] = state[sum % 256];               //生成密钥流。
    }
    
    • C代码实现
      实际工程应用中,不会提前计算好密钥流,因为明文或密文的长度不确定,少则一两个字节,多则几千兆字节,所以密钥流长度也不确定。实际工程应用中是一个一个地计算,一个一个地用,见代码。
      RC4.h
    //==============================================================================
    //  Copyright (C) 2019 王小康. All rights reserved.
    //
    //  作者: 王小康
    //  描述: RC4加解密
    //  日期: 2019-05-10
    //
    //==============================================================================
    
    #ifndef _RC4_H_
    #define _RC4_H_
    
    typedef struct rc4Ctx {
        unsigned int  i;
        unsigned int  j;
        unsigned char S[256];
    } RC4_CTX;
    
    int rc4_init(RC4_CTX *ctx, unsigned char *key, unsigned int keyLen);
    int rc4_run(RC4_CTX *ctx, unsigned char *output, unsigned char *input, unsigned int length);
    int rc4_keyStream (RC4_CTX *ctx, unsigned char *keyStream, unsigned int length);
    
    #endif
    
    

    RC4.c

    //==============================================================================
    //  Copyright (C) 2019 王小康. All rights reserved.
    //
    //  作者: 王小康
    //  描述: RC4加解密
    //  日期: 2019-05-10
    //
    //==============================================================================
    
    
    #include "RC4.h"
    
    //初始化
    int rc4_init(RC4_CTX *ctx, unsigned char *key, unsigned int keyLen){
        unsigned int  i;
        unsigned int  j;
        unsigned char swp;
        
        for(i=0; i<256; i++){
            ctx->S[i] = i;
        }
        
        for(i=j=0; i<256; i++){
            j = (j + ctx->S[i] + key[i%keyLen]) % 256;
            swp = ctx->S[i];
            ctx->S[i] = ctx->S[j];
            ctx->S[j] = swp;
        }
        
        ctx->i = 0;
        ctx->j = 0;
        return 0;
    }
    
    //加密或解密
    int rc4_run(RC4_CTX *ctx, unsigned char *output, unsigned char *input, unsigned int length){
        unsigned int n;
        unsigned int sum;
        unsigned char swp;
        
        for(n=0; n<length; n++){
            //计算新的 i 和 j。
            ctx->i = (ctx->i + 1) % 256;
            ctx->j = (ctx->j + ctx->S[ctx->i]) % 256;
            
            //交换 S[i] 和 S[j],并计算 S[i]+S[j] 的和。
            sum  = (swp = ctx->S[ctx->i]);
            sum += (ctx->S[ctx->i] = ctx->S[ctx->j]);
            ctx->S[ctx->j] = swp;
            
            //加解密一个字节。
            output[n] = input[n] ^ (ctx->S[sum % 256]);
        }
        return length;
    }
    
    //仅仅输出秘钥流
    int rc4_keyStream(RC4_CTX *ctx, unsigned char *keyStream, unsigned int length){
        unsigned int n;
        unsigned int sum;
        unsigned char swp;
        
        for(n=0; n<length; n++){
            //计算新的 i 和 j。
            ctx->i = (ctx->i + 1) % 256;
            ctx->j = (ctx->j + ctx->S[ctx->i]) % 256;
            
            //交换 S[i] 和 S[j],并计算 S[i]+S[j] 的和。
            sum  = (swp = ctx->S[ctx->i]);
            sum += (ctx->S[ctx->i] = ctx->S[ctx->j]);
            ctx->S[ctx->j] = swp;
            
            //输出秘钥流。
            keyStream[n] = ctx->S[sum % 256];
        }
        
        return length;
    }
    
    
    • 测试程序
      主要测试两项内容:1.密文解密后是否与明文相同;2.和openSSL对比,看相同的密码和相同的明文情况下,两者的密文是否相同。
    //==============================================================================
    //
    //  作者: 王小康
    //  描述: RC4加解密测试
    //  日期: 2019-05-10
    //
    //==============================================================================
    
    #include <stdio.h>
    #include <string.h>
    #include <openssl/rc4.h>
    #include "RC4.h"
    
    static void help(char *name){
        printf("Usage  : %s KEY STRING\n", name);
        printf("Example: %s 123456 \"I have a dream\"\n", name);
    }
    
    static void hex16(unsigned char *data, int len){
        printf("hex  =");
        while(len-- > 0){
            printf(" %02x", *data);
            data++;
        }
        putchar('\n');
    }
    
    //测试自己实现的rc4
    static void rc4Test(char *key, char *data){
        unsigned char buffer1[128];
        char          buffer2[128];
        int dataLen = strlen(data);
        RC4_CTX ctx;
        
        //
        printf("my rc4:\n");
        printf("data = \"%s\"\n", data);
        
        //加密
        rc4_init(&ctx, (void*)key, strlen(key));          //初始化
        rc4_run(&ctx, buffer1, (void*)data, dataLen);     //加密
        hex16(buffer1, dataLen);                          //16进制输出
        
        //解密
        rc4_init(&ctx, (void*)key, strlen(key));          //初始化
        rc4_run(&ctx, (void*)buffer2, buffer1, dataLen);  //解密
        buffer2[dataLen] = 0;
        printf("data = \"%s\"\n", buffer2);
    }
    
    //用openSSL的rc4做对比
    static void rc4Test_openssl(char *key, char *data){
        unsigned char buffer1[128];
        char          buffer2[128];
        int dataLen = strlen(data);
        RC4_KEY s_table;
        
        //
        printf("\nopenSSL:\n");
        printf("data = \"%s\"\n", data);
        
        //加密
        RC4_set_key(&s_table, strlen(key), (void*)key);   //初始化
        RC4(&s_table, dataLen, (void*)data, buffer1);     //加密
        hex16(buffer1, dataLen);                          //16进制输出
        
        //解密
        RC4_set_key(&s_table, strlen(key), (void*)key);   //初始化
        RC4(&s_table, dataLen, buffer1, (void*)buffer2);  //解密
        buffer2[dataLen] = 0;
        printf("data = \"%s\"\n", buffer2);
    }
    
    int main(int argc, char *argv[]){
        if(argc < 3){
            help(argv[0]);
            return 0;
        }
        
        //限制被加密的字串长度不超过120字节。
        int len = strlen(argv[2]);
        if(len > 120){
            len = 120;
            argv[2][120] = 0;
        }
        
        rc4Test(argv[1], argv[2]);
        rc4Test_openssl(argv[1], argv[2]);
        
        return 0;
    }
    
    
    • 运行效果

      看上图两个红色框,明文和解密后的明文完全相同,说明这个RC4的实现至少可以单独使用。
      再看上图两个绿色框,第二个绿色框是openssl的RC4加密后的密文,两者也完全一样,说明这个RC4的实现也可以和openssl互通。

    相关文章

      网友评论

          本文标题:RC4加解密

          本文链接:https://www.haomeiwen.com/subject/rwwaoqtx.html