RC4 的算法原理

RC4算法的特点是算法简单,运行速度快,而且密钥长度是可变的,可变范围为1-256字节(8-2048比特),在如今技术支持的前提下,当密钥长度为128比特时,用暴力法搜索密钥已经不太可行,所以可以预见 RC4的密钥范围任然可以在今后相当长的时间里抵御暴力搜索密钥的攻击。实际上,如今也没有找到对于128bit密钥长度的RC4加密算法的有效攻击方法。

在这里插入图片描述

基本概念

RC4算法有4个关键的变量

密钥流:RC4 算法的关键是根据明文和密钥生成相应的密钥流,密钥流的长度和明文的长度是对应的,也就是说明文的长度是 500 字节,那么密钥流也是 500 字节。当然,加密生成的密文也是 500 字节,因为密文第 i 字节 = 明文第 i 字节 ^ 密钥流第 i 字节;

状态向量 S:长度为 256Byte,S[0],S[1]…S[255]。每个单元都是一个 Byte,算法运行的任何时候,S 都包括 0-255 的 8Bit 的排列组合,只不过值的位置发生了变换;

临时向量 T:长度也为 256Byte,每个单元也是一个 Byte。如果密钥的长度是 256Byte,就直接把密钥的值赋给 T,否则,轮转地将密钥的每个 Byte 赋给 T;

密钥 K:长度为 1-256Byte,注意密钥的长度(keylen)与明文长度、密钥流的长度没有必然关系,通常密钥的长度为 16Byte(128Bit)。

加密原理

img

1.初始 S 和 T

先初始化状态向量 S(256 个字节,用来作为密钥流生成的种子 1):按照升序,给每个字节赋值 0,1,2,3,4,5,6…,254,255。
再初始化临时向量 T(初始密钥 K,由用户输入):长度任意,如果输入长度小于 256Byte,则进行轮转,直到填满。例如:输入密钥的是 1,2,3,4,5,那么填入的是 1,2,3,4,5,1,2,3,4,5,1,2,3,4,5…。由上述轮转过程得到 256 个字节的临时向量 T(用来作为密钥流生成的种子 2)

2.初始排列S

开始对状态向量 S 进行置换操作(用来打乱初始种子 1),按照下列规则进行,从第零个字节开始,执行 256 次,保证每个字节都得到处理这样处理后的状态向量 S 几乎是带有一定的随机性了。

3.产生密钥流

算法实现

c语言实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include<stdio.h>
#include<string.h>

typedef unsigned longULONG;

/* 初始化算法(KSA)函数
* 参数 1: 一个 256 长度的 char 型数组,定义为: unsigned char sBox[256];
* 参数 2: 密钥,其内容可以随便定义:char key[256];
* 参数 3: 密钥的长度,Len = strlen(key);
*/
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len)
{
int i = 0, j = 0;
char k[256] = { 0 };
unsigned char tmp = 0;
for (i = 0; i < 256; i++)
{
s[i] = i;
k[i] = key[i%Len];
}
for (i = 0; i < 256; i++)
{
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j]; // 交换 s[i] 和 s[j]
s[j] = tmp;
}
}

/* 伪随机子密码生成算法(PRGA)函数完成加、解密。
* 过程中,密钥的主要功能是将 S 搅乱,i 确保 S 的每个元素都得到处理,j 保证 S 的搅乱是随机的。
* 由此,不同的 S 在经过 PRGA 处理后可以得到不同的子密钥序列,将 S 和明文进行 xor 运算,得到密文,解密过程也完全相同。
* 参数 1:是上边 rc4_init 函数中,被搅乱的 S;
* 参数 2:是需要加密的 Data 数据;
* 参数 3:是 Data 的长度。
*/
void rc4_crypt(unsigned char* s, unsigned char* Data, unsigned long Len)
{
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for (k = 0; k < Len; k++)
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j]; // 交换 s[x] 和 s[y]
s[j] = tmp;
t = (s[i] + s[j]) % 256;
Data[k] ^= s[t];
}
}

int main()
{
unsigned char s[256] = { 0 }, s2[256] = { 0 }; // S
char key[256] = { "justfortest" };
char pData[512] = "这是一个用来加密的数据 Data";
unsigned long len = strlen(pData);
int i;

printf("pData=%s\n", pData);
printf("key=%s, length=%zu\n\n", key, strlen(key));

rc4_init(s, (unsigned char*)key, strlen(key)); // 已经完成了初始化
printf("完成对 S[i] 的初始化,如下:\n\n");
for (i = 0; i<256; i++)
{
printf("%02X", s[i]);
if (i && (i + 1) % 16 == 0)putchar('\n');
}
printf("\n\n");
for (i = 0; i<256; i++) // 用 s2[i] 暂时保留经过初始化的 s[i],很重要!
{
s2[i] = s[i];
}

printf("已经初始化,现在加密: \n\n");
rc4_crypt(s, (unsigned char*)pData, len); // 加密
printf("pData=%s\n\n", pData);

printf("已经加密,现在解密: \n\n");
rc4_crypt(s2, (unsigned char*)pData, len); // 解密
printf("pData=%s\n\n", pData);

return 0;
}

python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# RC4的Python实现
def S_box(R): # S盒
S = [x for x in range(256)]
j = 0
#S盒打乱顺序
for i in range(256):
j = (j + S[i] + K[i]) % 256
S[i], S[j] = S[j], S[i]
return S


def gen_K(key):
#将字符串转换为ASCII码
temp = list(bytes(key, encoding='utf-8'))
#print('密钥的ASCII码:', temp)
len_key = len(temp)
#填充密钥
K = [temp[i % len_key] for i in range(256)]
return K

#根据密文长度生成密钥流
def key_box(S, length):
j = 0
keys = []
length = int(length)
for i in range(length):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
t = (S[j] + S[i]) % 256
k = S[t]
keys.append(k)
return keys

while(1):
choose = input('加密输入1,解密输入2,退出输入3:')
if choose == '1':
key = input('请输入密钥:')
K = gen_K(key)
S = S_box(K)
# print('S:',S)
message = input('输入明文:')
secret = ''
keys = key_box(S, len(message))
print("十进制密钥流:",keys)
for i in range(len(message)):
secret = secret + '%02x' % (keys[i] ^ ord(message[i]))
print('加密后十六进制密文为:', secret)
if choose == '2':
key = input('请输入密钥:')
K = gen_K(key)
S = S_box(K)
# print('S:',S)
secret = input('请输入密文:')
message = ''
keys = key_box(S, len(secret) / 2)
for i in range(int(len(secret) / 2)):
message = message + chr(int(secret[0:2], 16) ^ keys[i])
secret = secret[2:]
print('解密后明文为:', message)