zoukankan      html  css  js  c++  java
  • RC4加密与解密

    介绍

    在密码学RC4(Rivest Cipher 4,也称为ARC4ARCFOUR,意为所谓的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
    
    ", Data);
        printf("密钥:%s
    
    ", Key);
    
        RC4_Init(S_box, Key, strlen((char*)Key));
        printf("S-box:
    ");
        for (i = 0; i < 256; ++i) {
            printf("%02x", S_box[i]);
            if ((i + 1) % 16 == 0) printf("
    ");
        }
    
        RC4_Crypt(S_box, Data, strlen((char*)Data));
    
        printf("
    加密后数据:%s
    ", 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] = '';
    
        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] = '';
    
        //以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
    
    ",Data);
        printf("密钥:%s
    
    ", Key);
    
        RC4_Init(S_box, Key, strlen((char*)Key));
        printf("S-box:
    ");
        for (i = 0; i < 256; ++i) {
            printf("%02x", S_box[i]);
            S_box2[i] = S_box[i];
            if ((i + 1) % 16 == 0) printf("
    ");
        }
    
        RC4_Crypt(S_box, Data, strlen((char*)Data));
    
        strcpy(tmp, (const char*)base64_encode(Data));
        printf("
    加密后数据:%s
    ", tmp);
    
        strcpy((char*)Data, (char*)base64_decode((unsigned char*)tmp));
        RC4_Crypt(S_box2, Data, strlen((char*)Data));
        printf("
    解密后数据:%s
    ", 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

    拓展

    流密码一般逐字节或者逐比特处理信息。一般来说

    • 流密码的密钥长度会与明文的长度相同。
    • 流密码的密钥派生自一个较短的密钥,派生算法通常为一个伪随机数生成算法。

    需要注意的是,流加密目前来说都是对称加密。

  • 相关阅读:
    利用scanf函数修改内存中任意位置内容
    TSql
    完整性约束及其违约处理
    实现关机、重启、注销
    建立索引的原则
    我只想安静的大便
    格式化GridView特定的值
    SELECT语句执行顺序解析
    CPU对存储器的读写
    Linux常用97条命令
  • 原文地址:https://www.cnblogs.com/Mayfly-nymph/p/12363117.html
Copyright © 2011-2022 走看看