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互通。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容

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