文章目录
  1. 1. 0x01 口胡
  2. 2. 0x02 正片
    1. 2.1. main函数
    2. 2.2. rc4_init函数
    3. 2.3. rc4_crypt函数
  3. 3. 0x03 rc4在现实中的具体应用
  4. 4. 0x04 尾声

0x01 口胡

RC4加密算法是大名鼎鼎的RSA三人组中的头号人物Ronald Rivest在1987年设计的密钥长度可变的流加密算法簇。之所以称其为簇,是由于其核心部分的S-box长度可为任意,但一般为256字节。该算法的速度可以达到DES加密的10倍左右,且具有很高级别的非线性。RC4起初是用于保护商业机密的。但是在1994年9月,它的算法被发布在互联网上,也就不再有什么商业机密了。RC4也被叫做ARC4(Alleged RC4——所谓的RC4),因为RSA从来就没有正式发布过这个算法。

一切的口胡都是苍白无力的,话不多说,都在代码里,直接进正片看代码。

0x02 正片

由于RC4算法的代码很少,所以下面会直接贴代码来说明RC4加密流程:

main函数

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
void main()
{

unsigned char s[256] = {0},s2[256] = {0}; //S-box

char key[256] = {"just for test"};

char pData[512] = "Data";
int i=0;

ULONG len = strlen(pData);

printf("pData = %s\n",pData);

printf("key = %s, length = %d\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("%-3d ",s[i]);

}

printf("\n\n");

for(i=0;i<256;i++)//用s2[i]暂时保留经过初始化的s[i],很重要的!!!
//这里之所以做保留是因为s在经过初始化后需要做一个备份,以保证在加解密的时候经过crypt函数生成的密钥流一样,只要使用相同的密钥流才能够保证数据在加密之后能够被正常解密,这也是流密码的一大特性
{

s2[i]=s[i];

}

printf("已经初始化,现在加密:\n\n");

rc4_crypt(s,(unsigned char *)pData,len);//加密

printf("pData = %s\n\n",pData);

printf("已经加密,现在解密:\n\n");

rc4_init(s,(unsigned char *)key, strlen(key)); //初始化密钥

rc4_crypt(s2,(unsigned char *)pData,len);//解密

printf("pData = %s\n\n",pData);

}

main的流程:

  1. 声明两个S盒,两个S盒的大小都是256字节,并都被定义为0;
  2. 声明并定义密钥(key);
  3. 声明并定义要加密的数据,即明文,这里的长度是随意的,长度范围为[0,255];
  4. 进入初始化函数rc4_init,我们来看下初始化函数的代码:

rc4_init函数

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
void rc4_init(unsigned char *s, unsigned char *key, unsigned long Len) //初始化函数
//初始化过程只是根据秘钥打乱了s这个0-255数组的顺序,具体怎么打乱的不需要知道
{


int i =0, j = 0;

char k[256] = {0};

unsigned char tmp = 0;

for(i=0;i<256;i++)

{

s[i]=i; //s是0-255的数组

k[i]=key[i%Len]; //k是根据秘钥生成的一个秘钥循环数组

}

for (i=0; i<256; i++)

{

j=(j+s[i]+k[i])%256; //根据秘钥去初始化(打乱)s数组的顺序

tmp = s[i];

s[i] = s[j]; //交换s[i]和s[j]

s[j] = tmp;

}

}

rc4_init的流程:

  1. 非常简单的一个函数。首先要明确参数,main传进来的参数是S盒,密钥以及密钥的长度;
  2. 第一个循环是对S盒进行初始赋值,将S盒赋值为0-255,然后根据密钥循环生成一个大小为256字节的密钥循环数组;
  3. 第二个循环是根据密钥去打乱S盒的顺序,具体的打乱规则如代码所示,针对每一个s[i],s[i]与k[i]混淆后产生一个要交换的索引j,然后s[i]与s[j]交换

其实具体的交换规则我们不需要知道,没什么意思,我们只需要知道S盒经过rc4_init之后,生成了一个很乱的S盒,且这个S盒的生成与循环密钥数组有关,可以这样理解,将这个函数看做一个黑盒,全0的S盒和密钥循环数组k(由给定的密钥生成)被放进这个黑盒中,按下黑盒的搅拌开关,搅拌成功后黑盒吐出来一个面目全非的S盒,这个S盒会用于接下来的加密与解密操作。

书接上文,接着来看main的流程:

  1. S盒经过rc4_init之后,得到一个全新的S盒,然后这个S盒会被copy一份存储在S2中,S2是新S盒的一个副本,S用于加密操作,S2用于解密操作,以保证在加解密的时候经过crypt函数生成的密钥流一样。
  2. 进入rc4_crypt进行加密;

rc4_crypt函数

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
void rc4_crypt(unsigned char *s, unsigned char *Data, unsigned long Len) //加解密
//打乱之后,在对s进行一系列的变换后当做密钥流
{


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];

}

}

rc4_crypt的流程:

函数就一个循环,该循环完成加密操作,这个循环对S盒又进行了一系列变换操作,然后才作为加密明文的密钥流,这里需要注意的是,对于每一次循环,明文只在最后一步跟S盒进行了异或操作,体现出流密码的特性.

到这里rc4算法的加密过程就结束了,我们可以这样理解,不管是rc4_init还是rc4_crypt,这两个函数所做的很多工作都是根据给定的密钥经过一系列杂七杂八的操作去生成较为安全的密钥流,然后明文只需要跟密钥流异或一下就生成了明文

书接上文,接着看main的流程:

  1. 加密之后,解密操作就顺其自然了。还记得前面保存的S盒的副本S2吗,解密的过程就是通过S2产生相同的密钥流,然后与密文进行异或,由于异或的可逆性,所以相同的密钥流在与密文异或后会得到相应的明文。

这就是rc4算法的整体流程


0x03 rc4在现实中的具体应用

是使用最广泛的软件流密码之一,并且广泛应用在SSL和WEP层协议中。

让我们来看一下RC4算法在手机和AP的通信中应用:

  1. 客户发出验证请求
  2. AP接到请求后AP产生一个随机数,该随机数会以明文方式发送给客户端
  3. 客户端使用WEP密钥(该密钥是用户连入AP时需要输入的,是连入AP的凭证)用RC4算法(此时RC4算法的密钥就是用的前面的WEP密钥,该密钥为用户和AP共享的)加密数据包(携带着经过加密的随机数)并且将它发回
  4. AP 解密数据包(用共享密钥+rc4算法解密)并且同原始随机数比较
  5. AP 向客户端发出成功信息

在SSL中的应用已经被废弃掉了,在今年9月份,三大浏览器厂商明确明年将放弃RC4加密支持,所以SSL中的应用就不说了

0x04 尾声

对于rc4的破解,看到过一篇还不错的帖子,没来得及细看,先放着,留着以后看——RC4算法暴力破解的尝试


关于流密码,就打算写到这了,下面开始转战分组密码。。。

文章目录
  1. 1. 0x01 口胡
  2. 2. 0x02 正片
    1. 2.1. main函数
    2. 2.2. rc4_init函数
    3. 2.3. rc4_crypt函数
  3. 3. 0x03 rc4在现实中的具体应用
  4. 4. 0x04 尾声