RC4(Rivest Cipher 4)加密原理——(C++描述)

抓包后无意间看到了 rc4coded 的字样,很是好奇,于是上网查找,得知是一个很有名气的加密算法。在学习算法原理的时候,我发现很多资料都是相仿的,表示本菜鸡很不理解算法过程。最终在wiki找到了出处,于是在此做下笔记。


首先摘一段wiki上对rc4的描述:

RC4 generates a pseudorandom stream of bits (a keystream). As with any stream cipher, these can be used for encryption by combining it with the plaintext using bit-wise exclusive-or; decryption is performed the same way (since exclusive-or with given data is an involution). This is similar to the one-time pad except that generated pseudorandom bits, rather than a prepared stream, are used.

大致翻译是这样的:该算法首先生成一串伪随机数(keystream),这样就可以像其他的流密码一样,将keystream和明文通过亦或操作来加密。解码也是一样,因为亦或操作是一种复归操作(involution),即做两次又变成原来的形态。除了运用生成的伪随机序列而不是一个准备好的流之外,该算法和 OTP 算法一样。


参照其他博客的方法,首先介绍下面要是用的一些变量,以方便理解。

根据 wiki 的介绍:

  • 一组 0-255 组合的序列用 S 表示;
  • 用来生成伪随机数序列的密码用 key 表示;
  • key 的长度为 keylength;
  • i,j 为两个 8bit 的索引指针;

我们在自己设一个 T 装伪随机数序列。

有了这些准备,开始介绍算法原理:

The permutation is initialized with a variable length key, typically between 40 and 2048 bits, using the key-scheduling algorithm (KSA). Once this has been completed, the stream of bits is generated using the pseudo-random generation algorithm (PRGA).

大致翻译:序列 S 用一个可变长度的 key 来初始化,一般 key 的长度在 40-2048bits (5Byte-256Byte)之间。初始化使用 KSA 算法。一旦完成这一步,用 PRGA 算法来用这一段序列生成伪随机数序列。

而有了伪随机数序列后,剩下要做的就是将明文和该序列以字节为单位执行亦或操作(生成的伪随机数序列的长度同明文长度相同)。所以 rc4 的最大难点就在于 KSA 和 PRGA 这两个算法了。我们来看一下:

 

  • Key-scheduling algorithm (KSA)

The key-scheduling algorithm is used to initialize the permutation in the array "S". "keylength" is defined as the number of bytes in the key and can be in the range 1 ≤ keylength ≤ 256, typically between 5 and 16, corresponding to a key length of 40 – 128 bits. First, the array "S" is initialized to the identity permutation. S is then processed for 256 iterations in a similar way to the main PRGA, but also mixes in bytes of the key at the same time.

大致翻译:该算法用来初始化 S 中的序列。keylength 用来表示 key 的字节长度,改长度可以在 1-256 之间取值,通常在5-16之间,对应 key length 的 40-128bits。首先,S 被初始化为有序序列(0-255)。然后,用和 PRGA 主题类似的循环处理 S,但 key 的内容也将加入处理(这一段有点难于理解,大致的过程是将 key 中的内容和 S 中的内容相加对以256取模,以其结果作为数组索引调换 S 中的元素,目的是将有序的 S 打乱)。

下面是算法的伪代码:

for i from 0 to 255
    S[i] := i
endfor
j := 0
for i from 0 to 255
    j := (j + S[i] + key[i mod keylength]) mod 256
    swap values of S[i] and S[j]
endfor

 

  •             Pseudo-random generation algorithm (PRGA)

​​​​​​​

For as many iterations as are needed, the PRGA modifies the state and outputs a byte of the keystream. In each iteration, the PRGA:

  • increments i
  • looks up the ith element of S, S[i], and adds that to j
  • exchanges the values of S[i] and S[j] then uses the sum S[i] + S[j] (modulo 256) as an index to fetch a third element of S (the keystream value K below)
  • then bitwise exclusive ORed (XORed) with the next byte of the message to produce the next byte of either ciphertext or plaintext.

Each element of S is swapped with another element at least once every 256 iterations.

这一段就不做翻译了,总的方向是通过算法将 S 的每个元素至少移动一次,即再次打乱 S 序列。再伪随机抽取其中的元素,组成伪随机数序列 T(原文是直接将提取的元素 k 作为 keystream[i] 直接同明文对应的字节进行亦或)。

伪代码:

i := 0
j := 0
while GeneratingOutput:
    i := (i + 1) mod 256
    j := (j + S[i]) mod 256
    swap values of S[i] and S[j]
    K := S[(S[i] + S[j]) mod 256]
    output K
endwhile

算法中最关键的两个部分完成,下面就是将明文和 T 以字节为单位亦或了。由于亦或的复归性质,解码的原理同加密原理相同,不在讨论。

下面贴上自己的代码(C++实现),其中 S 用 state_arr 表示,T 用 temp_arr 表示,keystream 存放伪随机数序列,key 为密钥,content 为明文或密文。

用户需要在自己的源码中加入 #include "RC4.h" 来包含 rc4 类的声明和一些其他必要元素。通过默认初始化,用户需要通过 get_info() 成员添加密钥和待处理文本,再调用 rc4_encrypt/rc4decrypt() 进行加密解密。使用传值初始化的用户可以直接加密解密。

RC4.h

#ifndef RC4
#define RC4
#define SIZE_MAX_RC4 256
using uchar_t=unsigned char;
class rc4;
#include 
#include 
class rc4{
	friend void swap_rc4(uchar_t&,uchar_t&);
	public:
		rc4()=default;
		rc4(const std::string&,const std::string&);
		void get_info(const std::string&,const std::string&);
		std::string rc4_encrypt();
		std::string rc4_decrypt();
		//void debug();
	private:
		uchar_t state_arr[SIZE_MAX_RC4];
		uchar_t temp_arr[SIZE_MAX_RC4];
		std::string keystream;
		std::string key;
		std::string content;
		void initialize();
		void spawn_stream();
};
void swap_rc4(uchar_t&,uchar_t&);
#include "RC4.cpp"
#endif

 

RC4.cpp

void swap_rc4(uchar_t &a,uchar_t &b){
	uchar_t temp=a;
	a=b;
	b=temp;
}
void rc4::initialize(){
	int len=key.length();
	for(int i=0;i

 

你可能感兴趣的:(C++)