RC4流加密算法特点及逆向识别方法

        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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值