RC4(Rivest Cipher 4)是一种流加密算法,密钥长度可变,它加解密使用相同的密钥, 因此也属于对称加密算法。
补充说明:序列密码(流密码)也属于对称密码,但与分组加密算法不同的是,流密码不对明文数据进行分组,而是用密钥生成 与明文一样长短的密码流对明文进行加密,加解密使用相同的密钥。也就是说,RC4不是对明文进行分组处理,而是以字节流的方式依次加密明文中的每一个字节,解密的时候也是依次对密文中的每一个字节进行解密。
加密过程:
1.S盒初始化(密钥调度算法 KSA,Key Scheduling Algorithm)
void rc4_init(uint8_t *s, uint8_t *key, uint32_t len) {
int i;
int j = 0;
char k[256];
uint8_t 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[j] = tmp;
}
}
首先初始化S盒(全部置0),k[]依key[]循环排列,初始化流密钥,然后根据密钥k[]打乱S盒:
循环256次,根据j,s[i],k[i]计算出索引j,然后调换s[i]与s[j]的值
2.生成流密钥
(伪随机数生成算法 PRGA, Pseudo-Random Generation Algorithm)
//s为s盒,buf为plain,len为len(buf)
void rc4_crypt(uint8_t *s, uint8_t *buf, uint32_t len)
{
int i = 0, j = 0, t = 0;
uint32_t k = 0;
uint8_t tmp;
for(k = 0; k < len; k++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
t = (s[i] + s[j]) % 256;
buf[k] ^= s[t];
}
}
进一步打乱S盒:从被打乱的S盒的第二个数字开始,利用j与s[i]生成索引j(相比于S盒初始化少了初始流密钥k[i]),然后调换s[i]与s[j]的位置(在生成流密钥的过程中会进一步打乱S盒)
生成流密钥:根据s[i]与s[j]计算出索引t,得到流密钥 k[i]=s[t] (i=0,i++)
3.加密
根据流密钥k[i]逐位与明文plain异或,得到cipher。由此也可以看出其为对称加密算法,加解密使用同一套密钥,即
密文[i] = 明文[i] XOR 密钥流[i]
明文[i] = 密文[i] XOR 密钥流[i]
如需解密,按照加密的流程再走一遍即可,因为S盒的状态仅与key有关,RC4_init初始化时置乱了一次(KSA),生成密钥流的时候也置换了一次(PRGA),所以首先得依照key拿到KSA后的S盒,然后将cipher与密钥流异或,即得到plain
rc4_init(S, key, sizeof(key) - 1);
rc4_crypt(S, data, sizeof(data) - 1);
c语言加密实现
#include <stdio.h>
#include <stdint.h>
void rc4_init(uint8_t *s, uint8_t *key, uint32_t len) {
int i;
int j = 0;
char k[256];
uint8_t 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[j] = tmp;
}
}
void rc4_crypt(uint8_t *s, uint8_t *buf, uint32_t len)
{
int i = 0, j = 0, t = 0;
uint32_t k = 0;
uint8_t tmp;
for(k = 0; k < len; k++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
t = (s[i] + s[j]) % 256;
buf[k] ^= s[t];
}
}
int main() {
uint8_t S[256];
uint8_t key[] = "test_key";
uint8_t data[] = "Hello World!";
rc4_init(S, key, sizeof(key) - 1);
rc4_crypt(S, data, sizeof(data) - 1);
for (int i = 0; i < sizeof(data) - 1; i++)
printf("%02X ", data[i]);
printf("\n");
}
return 0;
}
python脚本解密实现
from Crypto.Cipher import ARC4
key = b"test_key"
cipher = bytes.fromhex("A0 E2 BA F4 B5 02 ED 9B 41 2F E6 23")
rc4 = ARC4.new(key)
plain = rc4.decrypt(cipher)
print(plain)
由于rc4是对称加密算法,所以代码中rc4.decrypt换成rc4.encrypt结果一样
识别特征
该算法在初始化 s 盒的时候有一个循环次数为 256 次的 for 循环
之后根据密钥打乱 s 盒
最后遍历输入明文的每个字节,从 s 盒中取一个字节与之异或,完成加密
example:
先RC4后Base64加密的解密脚本,主要是要熟悉格式转换
import base64
from Crypto.Cipher import ARC4
encoded = "Z`TzzTrD|fQP[_VVL|yneURyUmFklVJgLasJroZpHRxIUlH\\vZE="
old = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
new = "=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|"
mapper = str.maketrans(new, old)
tmp = encoded.translate(mapper)
cipher_data = base64.b64decode(tmp)
print(type(cipher_data))
key = bytes.fromhex("1020303020201040") # 这就是 0x10 0x20 0x30 ... 0x40
rc4 = ARC4.new(key)
plain = rc4.decrypt(cipher_data)
print(plain)
3211

被折叠的 条评论
为什么被折叠?



