算法简介
RC4 算法也称为 “Rivest Cipher 4”, 是使用最广泛的流加密之一。
它以字节流的方式依次对明文、密文进行加密、解密。
它的特点就是算法简单,运行速度快,且密钥长度可变(256 byte 内)
加密原理
加密原理如下图所示:
由于异或运算的特性,所以RC4加密解密使用同一套算法
加密过程
第一步: 先初始化状态向量 S,S 为 256 个字节,用来作为密钥流生成的种子,按照升序,给每个字节从 0 开始赋值,一直到 255。
extern uint8_t S[256];
// 初始化向量S
for (i = 0; i < 256; i++)
{
S[i] = i;
}
第二步: 定义临时向量 T,T 为 256 字节, 初始密钥由用户输入,长度任意(不得高于256个字节),把密钥赋值给 T, 如果密钥不足 256 字节,则将其进行轮转,直到填满 T 向量。
extern uint8_t T[256];
// 轮转密钥赋值给 T
for (int i = 0; i < 256; i++)
{
T[i] = K[i % K_len]
}
第三步: 对向量 S 进行置换操作,用来打乱初始种子,置换规则如下:
int j = 0;
for (int i = 0 ; i < 256 ; i++)
{
j = (j + S[i] + T[i]) %256;
swap(S[i] , S[j]);
}
第四步: 生成加密、解密的密钥流
i , j = 0;
for (int l = 0; l < data_len; l++)
{
i = (i + 1) %256;
j = (j + S[i]) %256;
swap(S[i] , S[j]);
// 这里 k 则是当前密钥流中的一位,数据与其进行异或
t = (S[i] + S[j]) %256;
k = S[t];
// 对相应下标的数据进行异或,则完成一个字节的加、解密
data[l] = data[l]^k;
}
代码实现(C语言)
#include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef struct
{
uint8_t i;
uint8_t j;
uint8_t S[256];
}rc4_ctx;
void rc4_init(rc4_ctx* ctx, uint8_t* key, uint32_t keylen)
{
uint32_t i;
uint32_t j;
uint8_t T[256];
uint8_t tmp;
//初始化向量 S 和 向量 T
for (i = 0; i < 256; i++)
{
ctx->S[i] = i;
T[i] = key[i % keylen];
}
for (i = 0, j = 0; i < 256; i++)
{
// i 从 0 开始一直到255下标结束. j 是 S[i] 与 T[i] 组合得出的下标
j = (j + ctx->S[i] + T[i]) % 256;
// 交换 S[i] 与 S[j]
tmp = ctx->S[i];
ctx->S[i] = ctx->S[j];
ctx->S[j] = tmp;
}
ctx->i = 0;
ctx->j = 0;
}
// 因为 rc4 加密是取当前下标的一个字节与密钥流中的一位进行异或的,每次修改到的只会是当前下标所指向的一个字节
// 所以这里的输入 in 和 输出 out 可以是一个缓冲区,当然也可以是不同的缓冲区
void rc4_crypt(rc4_ctx* ctx, uint8_t* in, uint32_t inlen, uint8_t* out)
{
uint32_t i = 0;
uint32_t v = 0;
uint8_t tmp;
for (i = 0; i < inlen; i++)
{
// i 确保 S 中的每个元素都得到处理, j 确保 S 的搅乱是随机的
ctx->i = (ctx->i + 1) % 256;
ctx->j = (ctx->j + ctx->S[ctx->i]) % 256;
// 交换 S[i] 与 S[j]
tmp = ctx->S[ctx->i];
ctx->S[ctx->i] = ctx->S[ctx->j];
ctx->S[ctx->j] = tmp;
// 交换完之后 再把 S[i] + S[j] 的组合当做下标再去异或.
v = (ctx->S[ctx->i] + ctx->S[ctx->j]) % 256;
v = ctx->S[v];
out[i] = in[i] ^ v;
}
}
int main()
{
// 分别定义加密、解密的密钥流
rc4_ctx rc4_encrypt;
rc4_ctx rc4_dectypt;
// 定义 key
uint8_t * key = (uint8_t*)"abcd1234.";
// 定义要解密的数据
char buff1[] = "Hello World";
char buff2[] = "你好 世界";
// 分别对其进行初始化
rc4_init(&rc4_encrypt, key, strlen((char *)key));
rc4_init(&rc4_dectypt, key, strlen((char *)key));
// 加密
rc4_crypt(&rc4_encrypt, (uint8_t *)buff1, strlen(buff1), (uint8_t *)buff1);
printf("Hello World 加密后 ===> %s\n", buff1);
// 解密
rc4_crypt(&rc4_dectypt, (uint8_t*)buff1, strlen(buff1), (uint8_t*)buff1);
printf("Hello World 解密后 ===> %s\n", buff1);
// 加密
rc4_crypt(&rc4_encrypt, (uint8_t*)buff2, strlen(buff2), (uint8_t*)buff2);
printf("你好 世界 加密后 ===> %s\n", buff2);
// 解密
rc4_crypt(&rc4_dectypt, (uint8_t*)buff2, strlen(buff2), (uint8_t*)buff2);
printf("你好 世界 解密后 ===> %s\n", buff2);
return 0;
}
代码的执行结果如下:
Hello World 加密后 ===> y鴽Z泆}塛?
Hello World 解密后 ===> Hello World
你好 世界 加密后 ===> 鋁鎎G屭]b
你好 世界 解密后 ===> 你好 世界