RC4加解密

  • 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互通。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 序列密码又称流密码,原理是明文流和密钥流按顺序逐位异或运算,从而产出密文流,序列密码属于对合运算。 以下是典型的序...
    Frank1901s阅读 2,605评论 0 0
  • [TOC] 前端加解密 参考文档:SubtleCrypto:https://developer.mozilla.o...
    johnzhu12阅读 681评论 0 0
  • 本文主要是了解加解密的基础知识,首先我们了解什么是加解密及分类,然后我们谈到加解密的系统组成,接着我们看对称加密...
    搬砖人1314阅读 936评论 0 0
  • Rc4: 在密码学中,RC4(来自Rivest Cipher 4的缩写)是一种流加密算法,密钥长度可变。它加解密使...
    麦田夕阳阅读 2,546评论 0 0
  • 加密技术包括两个元素:算法和密钥。 算法是将普通的信息或者可以理解的信息与一串数字(密钥)结合,产生不可理解的密文...
    赵客缦胡缨v吴钩霜雪明阅读 1,208评论 0 16