RC4 加密算法

RC4 加密算法

RC4 是一种对称加密算法,使用的密钥为单钥。RC4 是用字节流的方式依次加密明文中的每一个字节,解密的时候也是依次对密文中的每一个字节进行解密。用密钥生成与明文一样长短的密码流对明文进行加密,加解密使用相同的密钥。

RC4 算法中几个关键变量:

  1. 密钥流:RC4 算法的关键是根据明文和密钥生成相应的密钥流,密钥流的长度和明文的长度是对应的,密文第 i 字节 = 明文第 i 字节 ^ 密钥流第 i 字节;
  2. 状态向量 S:长度为 256,S[0], S[1] ….. S[255]。每个单元都是一个字节,算法运行的任何时候,S 都包括 0-255 的 8 比特数的排列组合,只不过值的位置发生了变换;
  3. 临时向量 T:长度也为 256,每个单元也是一个字节。如果密钥的长度是256 字节,就直接把密钥的值赋给 T,否则,轮转地将密钥的每个字节赋给 T;
  4. 密钥 K:长度为 1-256 字节,注意密钥的长度 keylen 与明文长度、密钥流的长度没有必然关系,通常密钥的长度取为 16 字节(128 比特)。

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

RC4 首先使用密钥调度算法(KSA)来完成对大小为 256 的字节数组 S(S-box) 初始化及替换。在替换时使用密钥。首先用 0~255 初始化数组 S,然后使用密钥进行替换。如下:

1
2
3
4
5
6
7
8
9
10
11
12
for (int i = 0; i < 256; ++i)
{
S[i] = i;
T[i] = K[i % keylen];
}

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

在初始化的过程中,密钥的主要功能是将 S-box 搅乱,i 确保 S-box 的每个元素都得到处理,j 保证 S-box 的搅乱是随机的。而不同的 S-box 在经过 PRGA 的处理后可以得到不同的子密钥序列,并且,该序列是随机的:

1
2
3
4
5
6
7
8
9
10
11
int i = 0, j = 0, t;
while (len--)
{
i = (i + 1) % 256;
j = (j + S[i]) % 256;

swap(S[i], S[j]);

t = (S[i] + S[j]) % 256;
keyStream.push_back(S[t]);
}

得到的子密码 keyStream 用以和明文进行 xor 运算,得到密文,解密过程也完全相同。

完整示例代码:

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <ostream>
#include <time.h>
#include <stdlib.h>

using namespace std;

class RC4
{
public:
RC4(); // 构造函数
void setKey(string key); // 设置密钥
void encrypt(const string &, const string &); // 加密调用函数,明文路径以及密文路径
void decrypt(const string &, const string &); // 解密调用函数,密文路径以及解密文件路径
private:
unsigned char S[256]; // 状态向量,共256字节
unsigned char T[256]; // 暂时向量,共256字节
int keylen; // 密钥长度,keylen个字节,取值范围为1-256
string K; // 可变长度密钥
vector<char> keyStream;// 密钥流,变换后的S盒

void initial(); // 初始化
void rangeS(); // 打乱S盒
void generateKeyStream(int len); // 生成密钥流
};

RC4::RC4()
{
}

void RC4::setKey(string k)
{
K = k;
keylen = k.length();
}

void RC4::generateKeyStream(int len)
{
initial();
rangeS();

int i = 0, j = 0, t;
while (len--)
{
i = (i + 1) % 256;
j = (j + S[i]) % 256;

swap(S[i], S[j]);

t = (S[i] + S[j]) % 256;
keyStream.push_back(S[t]);
}
}

void RC4::initial()
{
for (int i = 0; i < 256; ++i)
{
S[i] = i;
T[i] = K[i % keylen];
}
}

void RC4::rangeS()
{
int j = 0;
for (int i = 0; i < 256; ++i)
{
j = (j + S[i] + T[i]) % 256;
swap(S[i], S[j]);
}
}

void RC4::encrypt(const string &plaintext, const string &ciphertext)
{
ifstream in;
ofstream out;

in.open(plaintext, ios::binary);

// 获取输入流的长度
in.seekg(0, ios::end);
int lenFile = in.tellg();
in.seekg(0, ios::beg);

// 产生密钥流
generateKeyStream(lenFile);

// 明文内容读入bits中
unsigned char *bits = new unsigned char[lenFile];
in.read((char *)bits, lenFile);
in.close();

out.open(ciphertext, ios::binary);
// 将明文按字节依次与密钥流异或后输出到密文文件中
for (int i = 0; i < lenFile; ++i)
{
out << (unsigned char)(bits[i] ^ keyStream[i]);
}
out.close();

delete[] bits;
keyStream.clear();
}

void RC4::decrypt(const string &ciphertext, const string &deciphertext)
{
ifstream in;
ofstream out;

in.open(ciphertext, ios::binary);

// 计算密文长度
in.seekg(0, ios::end);
int lenFile = in.tellg();
in.seekg(0, ios::beg);

// 产生密钥流
generateKeyStream(lenFile);

// 读入密文
unsigned char *bitCip = new unsigned char[lenFile];
in.read((char *)bitCip, lenFile);
in.close();

//解密后结果输出到解密文件
out.open(deciphertext, ios::out | ios::binary);
for (int i = 0; i < lenFile; ++i)
out << (unsigned char)(keyStream[i] ^ bitCip[i]);

// out.open(deciphertext, ios::binary);

// unsigned char *res = new unsigned char[lenFile];
// for (int i = 0; i < lenFile; ++i)
// res[i] = (unsigned char)(key[i] ^ bitCip[i]);

// out.write(reinterpret_cast<char *>(res), lenFile);
out.close();

delete[] bitCip;
keyStream.clear();
}

int main() {
string rc4Key = "This is rc4 key";
RC4 rc4 = RC4(); //密钥长16字节
rc4.setKey(rc4Key);
rc4.encrypt("plaintext.txt", "ciphertext.txt");
rc4.decrypt("ciphertext.txt", "deciphertext.txt");
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×