在密码学中,RC4(来自Rivest Cipher 4的缩写)是一种流加密算法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法。RC4是有线等效加密(WEP)中采用的加密算法,也曾经是TLS可采用的算法之一。
参数 | 作用 |
---|---|
S-box(S) | 256长度的char型数组,定义为: unsigned char sBox[256] |
Key(K) | 自定义的密钥,用来打乱 S-box |
pData | 用来加密的数据 |
初始化 S (256字节的char型数组),key 是我们自定义的密钥,用来打乱 S ,i 确保 S-box 的每个元素都得到处理, j 保证 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; // 赋值 S
k[i] = key[i%Len]; // 赋值 K
}
for (i = 0; i < 256; i++)
{
j = (j + s[i] + k[i]) % 256; // 开始混淆
tmp = s[i];
s[i] = s[j]; // 交换s[i]和s[j]
s[j] = tmp;
}
}
加密过程将 S-box 和明文进行 xor 运算,得到密文,解密过程也完全相同
/*加解密*/
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;
tmp = s[i];
s[i] = s[j]; // 交换s[x]和s[y]
s[j] = tmp;
t = (s[i] + s[j]) % 256;
Data[k] ^= s[t];
}
}
下面是 C 实现的代码
#include
#include
typedef unsigned longULONG;
/*初始化函数*/
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];
}
for (i = 0; i < 256; i++)
{
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j]; // 交换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;
tmp = s[i];
s[i] = s[j]; // 交换s[x]和s[y]
s[j] = tmp;
t = (s[i] + s[j]) % 256;
Data[k] ^= s[t];
}
}
int main()
{
unsigned char s[256] = { 0 }, s2[256] = { 0 }; // S-box
char key[256] = { "justfortest" };
char pData[512] = "这是一个用来加密的数据Data";
unsigned long 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("%02X", s[i]);
if (i && (i + 1) % 16 == 0)putchar('\n');
}
printf("\n\n");
for (i = 0; i < 256; i++) // 用s2[i]暂时保留经过初始化的s[i],很重要的!!!
{
s2[i] = s[i];
}
printf("已经初始化,现在加密:\n\n");
rc4_crypt(s, (unsigned char*)pData, len); // 加密
printf("pData=%s\n\n", pData);
printf("已经加密,现在解密:\n\n");
rc4_crypt(s2, (unsigned char*)pData, len); // 解密
printf("pData=%s\n\n", pData);
return 0;
}
运行结果如下
C:\Users\thunder>"D:\AlgorithmTest.exe"
pData=这是一个用来加密的数据Data
key=justfortest,length=11
完成对S[i]的初始化,如下:
21E0944A8CAA5C851A95374358840E32
EE3AF7C8F67F898BFF52235F3B51CAE6
31E2A570C698C046CE836EB91EBC9235
FD6B1CB62C2D69B565631B933EA60762
13EAE7775BA159DD745491C181B7FB49
66037D2E47331538F8A820AE22D2345A
64FA3F87714DFCBF2490D32ADF9EB85E
0A2780E40CAD1497E3D8C7F2F4424176
DC8D45A9789DE1B0D9044F0F36C3C5BE
4C7AEB6C4B8640E59A7919B39BABAFE8
C4AC8EFE963CEDEF0B091202BAB1D001
CB60D4F91D557BCC7544D750F17E67C9
88DB111826F0B299B4BB482BA41FF58A
C2E9A0CF5DDA6FCD57003D0830A2A316
9F0D6AF36D682F8FBD28A7DE4ED15373
7C2956D51706058225EC617210399CD6
已经初始化,现在加密:
pData=?獤 5Ws?g&W鋟覈?T?
已经加密,现在解密:
pData=这是一个用来加密的数据Data
C:\Users\thunder>
上面的代码是rc4加密字符串这是一个用来加密的数据Data
,key = justfortest
,我们放入IDA观察,初始化函数如下
void __cdecl rc4_init(char *s, char *key, unsigned int Len)
{
char tmp; // STDF_1
char k[256]; // [esp+DCh] [ebp-120h]
int j; // [esp+1E4h] [ebp-18h]
int i; // [esp+1F0h] [ebp-Ch]
j = 0;
k[0] = 0;
j__memset(&k[1], 0, 0xFFu);
for ( i = 0; i < 256; ++i )
{
s[i] = i;
k[i] = key[i % Len];
}
for ( i = 0; i < 256; ++i )
{
j = (k[i] + j + (unsigned __int8)s[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}
加密函数如下
void __cdecl rc4_crypt(char *s, char *Data, unsigned int Len)
{
char tmp; // STD3_1
unsigned int k; // [esp+DCh] [ebp-2Ch]
int j; // [esp+F4h] [ebp-14h]
int i; // [esp+100h] [ebp-8h]
i = 0;
j = 0;
for ( k = 0; k < Len; ++k )
{
i = (i + 1) % 256;
j = (j + (unsigned __int8)s[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
Data[k] ^= s[((unsigned __int8)s[j] + (unsigned __int8)s[i]) % 256];
}
}
从IDA中可以看到有很多的 %256 操作,因为 s 盒的长度为256,所以这里很好判断,如果在CTF逆向过程中看到有多次 %256 的操作最后又有异或的话那可以考虑是否是RC4密码
python实现如下
# -*- coding: utf-8 -*-
import random, base64
from hashlib import sha1
def crypt(data, key):
"""RC4 algorithm"""
x = 0
box = range(256)
for i in range(256):
x = (x + box[i] + ord(key[i % len(key)])) % 256
box[i], box[x] = box[x], box[i]
x = y = 0
out = []
for char in data:
x = (x + 1) % 256
y = (y + box[x]) % 256
box[x], box[y] = box[y], box[x]
out.append(chr(ord(char) ^ box[(box[x] + box[y]) % 256]))
return ''.join(out)
def tencode(data, key, encode=base64.b64encode, salt_length=16):
"""RC4 encryption with random salt and final encoding"""
salt = ''
for n in range(salt_length):
salt += chr(random.randrange(256))
data = salt + crypt(data, sha1(key + salt).digest())
if encode:
data = encode(data)
return data
def tdecode(data, key, decode=base64.b64decode, salt_length=16):
"""RC4 decryption of encoded data"""
if decode:
data = decode(data)
salt = data[:salt_length]
return crypt(data[salt_length:], sha1(key + salt).digest())
if __name__ == '__main__':
# 需要解密的数据
data = 'UUyFTj8PCzF6geFn6xgBOYSvVTrbpNU4OF9db9wMcPD1yDbaJw=='
# 密钥
key = 'welcometoicqedu'
# 解码
decoded_data = tdecode(data=data, key=key)
print("明文是:")
print decoded_data
输出如下
[Running] python -u "/home/thunder/Desktop/CTF/crypt/example/rc4_example/test.py"
明文是:
flag{rc4_l_keepgoing}
[Done] exited with code=0 in 0.14 seconds
在线解密网站:https://www.sojson.com/encrypt_rc4.html
参考链接:
https://blog.csdn.net/Fly_hps/article/details/79918495
https://baike.baidu.com/item/RC4/3454548?fr=aladdin