介绍
在密码学中,RC4(Rivest Cipher 4,也称为ARC4或ARCFOUR,意为所谓的RC4)是一种流密码。尽管它以简单性和软件速度着称,但在RC4中发现了多个漏洞,使其不安全。当不丢弃输出密钥流的开头或使用非随机或相关密钥时,它特别容易受到攻击。RC4的使用特别有问题,导致协议非常不安全,例如WEP。
参数介绍
参数名 | 说明 |
S | S-box,长度为256的char型数组,char S[256] |
K | 密钥Key,用户自定义,长度在1~256,用来打乱S-box |
T | 临时变量,长度为256的char型数组 |
D | 保存加密前/后数据 |
基本流程
- 初始化 S 和 T 数组。
- 初始化置换 S。
- 生成密钥流。
初始化S和T数组+初始化置换S
void RC4_Init(unsigned char* S, unsigned char* K, unsigned int len) { int i, j = 0; unsigned char ch_tmp, T[256] = { 0 };//临时变量 for (i = 0; i < 256; ++i) { S[i] = i;//初始化S-box T[i] = K[i % len];//密钥填充临时数组 } //打乱S-box for (i = 0; i < 256; ++i) { j = (j + S[i] + T[i]) % 256; ch_tmp = S[i]; S[i] = S[j]; S[j] = ch_tmp; } }
生成密钥流
void RC4_Crypt(unsigned char* S, unsigned char* D, unsigned int len) { int i = 0, j = 0, int_tmp; unsigned int n; unsigned char ch_tmp; for (n = 0; n < len; ++n) { i = (i + 1) % 256; j = (j + S[i]) % 256; ch_tmp = S[i]; S[i] = S[j]; S[j] = ch_tmp; int_tmp = (S[i] + S[j]) % 256; D[n] ^= S[n]; } }
完整代码实现
C语言
#include <bits/stdc++.h> #pragma warning(disable:4996) void RC4_Init(unsigned char* S, unsigned char* K, unsigned int len) { int i, j = 0; unsigned char ch_tmp, T[256] = { 0 };//临时变量 for (i = 0; i < 256; ++i) { S[i] = i;//初始化S-box T[i] = K[len % 256];//密钥填充临时数组 } //打乱S-box for (i = 0; i < 256; ++i) { j = (j + S[i] + T[i]) % 256; ch_tmp = S[i]; S[i] = S[j]; S[j] = ch_tmp; } } void RC4_Crypt(unsigned char* S, unsigned char* D, unsigned int len) { int i = 0, j = 0, int_tmp; unsigned int n; unsigned char ch_tmp; for (n = 0; n < len; ++n) { i = (i + 1) % 256; j = (j + S[i]) % 256; ch_tmp = S[i]; S[i] = S[j]; S[j] = ch_tmp; int_tmp = (S[i] + S[j]) % 256; D[n] ^= S[n]; } } int main(void) { unsigned char S_box[256] = { 0 }; unsigned char Key[] = { "helloworld" }; unsigned char Data[] = { "youareso" }; int i; printf("加密前数据:%s\n\n", Data); printf("密钥:%s\n\n", Key); RC4_Init(S_box, Key, strlen((char*)Key)); printf("S-box:\n"); for (i = 0; i < 256; ++i) { printf("%02x", S_box[i]); if ((i + 1) % 16 == 0) printf("\n"); } RC4_Crypt(S_box, Data, strlen((char*)Data)); printf("\n加密后数据:%s\n", Data); system("PAUSE"); return 0; }
RC4+Base64
不过在实际做题中,往往会将RC4与变表Base64结合起来考(先后顺序)
#include <bits/stdc++.h> #pragma warning(disable:4996) void RC4_Init(unsigned char* S, unsigned char* K, unsigned int len) { int i, j = 0; unsigned char ch_tmp, T[256] = { 0 };//临时变量 for (i = 0; i < 256; ++i) { S[i] = i;//初始化S-box T[i] = K[len % 256];//密钥填充临时数组 } //打乱S-box for (i = 0; i < 256; ++i) { j = (j + S[i] + T[i]) % 256; ch_tmp = S[i]; S[i] = S[j]; S[j] = ch_tmp; } } void RC4_Crypt(unsigned char* S, unsigned char* D, unsigned int len) { int i = 0, j = 0, int_tmp; unsigned int n; unsigned char ch_tmp; for (n = 0; n < len; ++n) { i = (i + 1) % 256; j = (j + S[i]) % 256; ch_tmp = S[i]; S[i] = S[j]; S[j] = ch_tmp; int_tmp = (S[i] + S[j]) % 256; D[n] ^= S[n]; } } unsigned char* base64_encode(unsigned char* str) { long len; long str_len; unsigned char* res = { 0 }; int i, j; unsigned char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; //unsigned char base64_table[] = "0123456789+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; str_len = strlen((char*)str); if (str_len % 3 == 0) len = str_len / 3 * 4; else len = (str_len / 3 + 1) * 4; res = (unsigned char*)malloc(sizeof(unsigned char) * len + 1); res[len] = '\0'; for (i = 0, j = 0; i < len - 2; j += 3, i += 4) { res[i] = base64_table[str[j] >> 2]; res[i + 1] = base64_table[(str[j] & 0x3) << 4 | (str[j + 1] >> 4)]; res[i + 2] = base64_table[(str[j + 1] & 0xf) << 2 | (str[j + 2] >> 6)]; res[i + 3] = base64_table[str[j + 2] & 0x3f]; } switch (str_len % 3) { case 1: res[i - 2] = '='; res[i - 1] = '='; break; case 2: res[i - 1] = '='; break; } return res; } unsigned char* base64_decode(unsigned char* code) { //根据base64表,以字符找到对应的十进制数据 int table[] = { 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,62,0,0,0, 63,52,53,54,55,56,57,58, 59,60,61,0,0,0,0,0,0,0,0, 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,0,0,0,0,0,0,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 }; long len; long str_len; unsigned char* res; int i, j; //计算解码后的字符串长度 len = strlen((char*)code); //判断编码后的字符串后是否有= if (strstr((char*)code, "==")) str_len = len / 4 * 3 - 2; else if (strstr((char*)code, "=")) str_len = len / 4 * 3 - 1; else str_len = len / 4 * 3; res = (unsigned char*)malloc(sizeof(unsigned char) * str_len + 1); res[str_len] = '\0'; //以4个字符为一位进行解码 for (i = 0, j = 0; i < len - 2; j += 3, i += 4) { res[j] = ((unsigned char)table[code[i]]) << 2 | (((unsigned char)table[code[i + 1]]) >> 4); //取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的后2位进行组合 res[j + 1] = (((unsigned char)table[code[i + 1]]) << 4) | (((unsigned char)table[code[i + 2]]) >> 2); //取出第二个字符对应base64表的十进制数的后4位与第三个字符对应bas464表的十进制数的后4位进行组合 res[j + 2] = (((unsigned char)table[code[i + 2]]) << 6) | ((unsigned char)table[code[i + 3]]); //取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合 } return res; } int main(void) { unsigned char S_box[256] = { 0 }, S_box2[256] = { 0 }; unsigned char Key[] = { "helloworld" }; unsigned char Data[] = { "youareso" }; char tmp[256] = { 0 }; int i; printf("加密前数据:%s\n\n",Data); printf("密钥:%s\n\n", Key); RC4_Init(S_box, Key, strlen((char*)Key)); printf("S-box:\n"); for (i = 0; i < 256; ++i) { printf("%02x", S_box[i]); S_box2[i] = S_box[i]; if ((i + 1) % 16 == 0) printf("\n"); } RC4_Crypt(S_box, Data, strlen((char*)Data)); strcpy(tmp, (const char*)base64_encode(Data)); printf("\n加密后数据:%s\n", tmp); strcpy((char*)Data, (char*)base64_decode((unsigned char*)tmp)); RC4_Crypt(S_box2, Data, strlen((char*)Data)); printf("\n解密后数据:%s\n", Data); system("PAUSE"); return 0; }
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 = 'JcckEQrhrmVawW9p+KRI7pDZ81VbpkVU30RQ7pskkaZh+tWh' key = 'Biub1uBIv' decoded_data = tdecode(data=data, key=key) print("明文是:") print decoded_data
在线解密
http://ctf.ssleye.com/rc4.html
http://www.ssleye.com/rc4_cipher.html
http://tool.chacuo.net/cryptrc4
参考
https://en.wikipedia.org/wiki/RC4
https://blog.csdn.net/CharlesGodX/article/details/90065683
https://www.ctfwp.com/articals/2019xihulunjian.html?h=rc4
https://blog.csdn.net/qq_26093511/article/details/78836087
https://ctf-wiki.github.io/ctf-wiki/crypto/streamcipher/special/rc4-zh/
https://github.com/BjdsecCA/BJDCTF2020
https://blog.csdn.net/huangyimo/article/details/82970903
来源:https://www.cnblogs.com/Mayfly-nymph/p/12363117.html