-
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互通。
网友评论