前言:RC4对称流加密算法笔记

 

什么是RC4对称流加密算法

RC4算法是Ron Rivest为RSA公司在1987年设计的一种流密码,作为RSA的商业机密直到1994年才被匿名公布于Internet。

该算法是一个可变密钥长度、面向字节操作的流密码。该算法以随机置换作为基础,其密码周期很可能大于10100,且该算法的运行速度很快。

RC4被用于为网络浏览器和服务器间通信而制定的SSL/TLS(安全套接字协议/传输层安全协议)标准中,以及作为IEEE 801.11无线局域网标准一部分的WEP(Wired Equivalent Privacy)协议和新的WiFi受保护访问协议(WAP)中。从这些应用来看,RC4构成了当今网络通信的非常重要的部分,因此这个算法非常重要。

RC4是一个流密码是对称密码算法,从明文输入流逐位或逐字节产生密文输出。

它是可变密钥长度,面向字节操作的流密码,也就是加密的时候它是对每个字节进行的加密操作,同样的解密的操作也是如此,如下图所示,加密和解密的时候都需要重新初始化一遍生成一次密钥流来进行解密

rc4 aes_rc4 aes

其密钥流由两部分组成,分别是KSA和PRGA

RC4的相关的名词

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

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

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

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

RC4加密过程

RC4算法其中包括初始化算法(KSA)和伪随机子密码生成算法(PRGA)两大部分

S和T的初始状态(KSA调度算法)

首先是一个S数组,按照升序,给S数组中的每个字节赋值0,1,2,3,4,5,6.....,254,255,对应到图中的也就是如下

rc4 aes_数组_02

再接着创建一个临时向量T,也就是一个数组,将密钥的值(你自己定义的密钥)循环复制到T向量中

rc4 aes_rc4 aes_03

用T密钥数组对S数组的初始变换,对应到图中的也就是如下

rc4 aes_数组_04

rc4 aes_数组_05

其置换的流程的代码如下所示

j = 0;

for (i = 0 ; i < 256 ; i++){
  j = (j + S[i] + T[i]) mod 256;
  swap(S[i] , S[j]);
}

这里需要注意下,就是这里看到看到对S的操作交换,S仍然包含所有值为0-255的元素,只是顺序调换了

这样处理的话,此时状态向量S几乎是带有一定的随机性了,保证了一定的安全

密钥流的生成(PRGA)

密钥流生成的过程对应到图中所示

rc4 aes_初始化_06

加密中,将k的值与明文的下一字节异或,解密时将k的值与密文的下一字节异或。伪码如下所示

i , j = 0;
while (true){
  i = (i + 1) mod 256;
  j = (j + S[i]) mod 256;
  swap(S[i] , S[j]);
  t = (S[i] + S[j]) mod 256;
  k = S[t];
}

这里的话比如我的明文字节长度为1024个字节,那么此时执行次数也就是1024次,

i=0;
j=0;
while(datalength--){//相当于执行1024次,这样生成的秘钥流也是1024个字节
  i = (i + 1) mod 256;
  j = (j + S[i]) mod 256;
  swap(S[i] , S[j]);
  t = (S[i] + S[j]) mod 256;
  k = S[t];这里的K就是当前生成的一个秘钥流中的一位
  //可以直接在这里进行加密,当然也可以将密钥流保存在数组中,最后进行异或就ok
  data[]=data[]^k; //进行加密,"^"是异或运算符
}

下面的图中还少了一步,就是加解密的操作,下面的图中最后一行就只是生成了一个字节的密钥流,但是并没有进行异或加密或者解密的操作,如果要加密或者解密的操作还需要执行这一步data[]=data[]^k; //进行加密,"^"是异或运算符

rc4 aes_数组_07

整体密钥流生成的过程图如下所示

rc4 aes_rc4 aes_08

RC4对称流加密解密算法代码实现

#include<stdio.h>
#include<string.h>
typedef unsigned long ULONG;

// 生成s-box 1-255升序排列,然后通过配合密钥来打乱s-box使其带有一定的随机性,接着再将s-box的顺序继续打乱一次
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]; // t-box使用key来进行填充的
	}
	
	for (i = 0; i<256; i++)
	{
		j = (j + s[i] + k[i]) % 256; // j = 取一个s[i]+k[i]+j的索引
		//交换s[i]和s[j]
		tmp = s[i];
		s[i] = s[j];
		s[j] = tmp;
	}
}

// 加解密
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;
		//交换s[x]和s[y]
		tmp = s[i];
		s[i] = s[j];
		s[j] = tmp;
		// 再去一个0-255的索引
		t = (s[i] + s[j]) % 256;
		Data[k] ^= s[t]; // 取出来的一个索引在对应的s-box盒中对数据进行异或操作,异或的次数取决于要明文加密的长度
	}
}

void main()
{
	unsigned char s[256] = { 0 }, s2[256] = { 0 };    //S-box
	char key[] = { "just for test" };
	char pData[512] = "这是一个用来加密的数据Data";
	ULONG len = strlen(pData);
	int i;
	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");
	
	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(s, (unsigned char *)pData, len);//解密
	printf("pData = %s\n\n", pData);
	return 0;
}