zoukankan      html  css  js  c++  java
  • RC4算法

    文章转载自http://blog.chinaunix.net/uid-15446172-id-2772536.html点击打开链接

    RC4加密算法

      RC4加密算法是大名鼎鼎的RSA三人组中的头号人物Ron Rivest在1987年设计的密钥长度可变的流加密算法簇。之所以称其为簇,是由于其核心部分的S-box长度可为任意,但一般为256字节。该算法的速度可以达到DES加密的10倍左右。

      RC4算法的原理很简单,包括初始化算法和伪随机子密码生成算法两大部分。假设S-box长度和密钥长度均为为n。先来看看算法的初始化部分(用类C伪代码表示):

      for (i=0; i<n; i++)

      s=i;

      j=0;

      for (i=0; i<n; i++)

      {

      j=(j+s+k)%256;

      swap(s, s[j]);

      }

      在初始化的过程中,密钥的主要功能是将S-box搅乱,i确保S-box的每个元素都得到处理,j保证S-box的搅乱是随机的。而不同的S-box在经过伪随机子密码生成算法的处理后可以得到不同的子密钥序列,并且,该序列是随机的:

      i=j=0;

      while (明文未结束)

      {

      ++i%=n;

      j=(j+s)%n;

      swap(s, s[j]);

      sub_k=s((s+s[j])%n);

      }

      得到的子密码sub_k用以和明文进行xor运算,得到密文,解密过程也完全相同。

      由于RC4算法加密是采用的xor,所以,一旦子密钥序列出现了重复,密文就有可能被破解。关于如何破解xor加密,请参看Bruce Schneier的Applied Cryptography一书的1.4节Simple XOR,在此我就不细说了。那么,RC4算法生成的子密钥序列是否会出现重复呢?经过我的测试,存在部分弱密钥,使得子密钥序列在不到100万字节内就发生了完全的重复,如果是部分重复,则可能在不到10万字节内就能发生重复,因此,推荐在使用RC4算法时,必须对加密密钥进行测试,判断其是否为弱密钥。

      但在2001年就有以色列科学家指出RC4加密算法存在着漏洞,这可能对无线通信网络的安全构成威胁。

      以色列魏茨曼研究所和美国思科公司的研究者发现,在使用“有线等效保密规则”(WEP)的无线网络中,在特定情况下,人们可以逆转RC4算法的加密过程,获取密钥,从而将己加密的信息解密。实现这一过程并不复杂,只需要使用一台个人电脑对加密的数据进行分析,经过几个小时的时间就可以破译出信息的全部内容。

      专家说,这并不表示所有使用RC4算法的软件都容易泄密,但它意味着RC4算法并不像人们原先认为的那样安全。这一发现可能促使人们重新设计无线通信网络,并且使用新的加密算法

     

    ------------------------------------------------------------------------------

    RC4是由RSA Security的Ron Rivest 在1987年开发出来的,虽然它的官方名是“Rivest Cipher 4”,但是首字母缩写RC也可以理解为Ron's Code。RC4开始时是商业密码,没有公开发表出来,但是在94年9月份的时候,它被人匿名公开在了Cypherpunks 邮件列表上,很快它就被发到了sci.crypt 新闻组上,随后从这儿传播到了互联网的许多站点。随之贴出的代码后来被证明是很有水平的,因为它的输出跟取得了RC4版权的私有软件的输出是完全的。由于算法已经公开,rc4也就不再是商业秘密了,只是它的名字“RC4”仍然是一个注册商标。RC4经常被称作是“ARCFOUR”或者"ARC4"(A lleged  RC4,所谓的RC4,因为RSA从来没有官方公布这个算法),这样来避免商标使用的问题。它已经成为一些广泛使用的协议和标准的一部分,比如,包括WEP和WPA的无线网卡和TLS。


    让它如此广泛分布和使用的主要因素是它不可思议的简单和速度,不管是软件还是硬件,实现起来都十分容易。

    --------------------------------------------------------------------------

    RC4加密算法在C++中的实现

    在一些场合,常需要用到一些简单的加密算法,这里的RC4就可以说是最简单的一种。只要设置一个足够强的密码,就可以适用于一些非常简单的场合了。我是用来加密HTTP传送的数据的。

    RC4函数(加密/解密)    其实,RC4只有加密,将密文再加密一次,就是解密了。

    GetKey函数   随机字符串产生器,呵呵,为了方便,大多数加密算法都有一个随机密码产生器,我也就附带一个了。

    ByteToHex函数   把字节码转为十六进制码,一个字节两个十六进制。研究发现,十六进制字符串非常适合在HTTP中传输,Base64中的某些字符会造成转义,挺麻烦的。

    HexToByte函数   把十六进制字符串,转为字节码。服务器也按照十六进制字符串的形式把数据传回来,这里就可以解码啦。同时,使用十六进制字符串传输,避开了传输过程中多国语言的问题。

    Encrypt函数    把字符串经RC4加密后,再把密文转为十六进制字符串返回,可直接用于传输。

    Decrypt函数    直接密码十六进制字符串密文,再解密,返回字符串明文。

    源码如下:

    Encrypt.h文件:

    #ifndef _ENCRYPT_RC4_
    #define _ENCRYPT_RC4_
    
    #include <string.h>
    
    #define BOX_LEN 256
    
    int GetKey(const unsigned char* pass, int pass_len, unsigned char *out);
    int RC4(const unsigned char* data, int data_len, const unsigned char* key, int key_len, unsigned char* out, int* out_len);
    static void swap_byte(unsigned char* a, unsigned char* b);
    
    char* Encrypt(const char* szSource, const char* szPassWord); // 加密,返回加密结果
    char* Decrypt(const char* szSource, const char* szPassWord); // 解密,返回解密结果
    
    char* ByteToHex(const unsigned char* vByte, const int vLen); // 把字节码pbBuffer转为十六进制字符串,方便传输
    unsigned char* HexToByte(const char* szHex); // 把十六进制字符串转为字节码pbBuffer,解码
    
    #endif // #ifndef _ENCRYPT_RC4_
    
    Encrypt.cpp文件:
    
    #include "Encrypt.h"
    
    char* Encrypt(const char* szSource, const char* szPassWord) // 加密,返回加密结果
    {
    if(szSource == NULL || szPassWord == NULL) return NULL;
    
    unsigned char* ret = new unsigned char[strlen(szSource)];
    
    int ret_len = 0;
    
    if(RC4((unsigned char*)szSource,
        strlen(szSource),
        (unsigned char*)szPassWord,
        strlen(szPassWord),
        ret,
        &ret_len) == NULL)
       return NULL;
    
    char* ret2 = ByteToHex(ret, ret_len);
    
    delete[] ret;
    return ret2;
    }
    
    char* Decrypt(const char* szSource, const char* szPassWord) // 解密,返回解密结果
    {
    if(szSource == NULL || (strlen(szSource)%2 != 0) || szPassWord == NULL)
       return NULL;
    
    unsigned char* src = HexToByte(szSource);
    
    unsigned char* ret = new unsigned char[strlen(szSource) / 2 + 1];
    
    int ret_len = 0;
    
    memset(ret, strlen(szSource) / 2 + 1,0);
    
    if(RC4(src, strlen(szSource) / 2, (unsigned char*)szPassWord, strlen(szPassWord), ret, &ret_len) == NULL)
       return NULL;
    
    ret[ret_len] = '\0';
    
    return (char*)ret;
    }
    
    int RC4(const unsigned char* data, int data_len, const unsigned char* key, int key_len, unsigned char* out, int* out_len)
    {
    if (data == NULL || key == NULL || out == NULL)
       return NULL;
    
    unsigned char* mBox = new unsigned char[BOX_LEN];
    
    if(GetKey(key, key_len, mBox) == NULL)
       return NULL;
    
    int i=0;
    int x=0;
    int y=0;
    
    for(int k = 0; k < data_len; k++)
    {
       x = (x + 1) % BOX_LEN;
       y = (mBox[x] + y) % BOX_LEN;
       swap_byte(&mBox[x], &mBox[y]);
       out[k] = data[k] ^ mBox[(mBox[x] + mBox[y]) % BOX_LEN];
    }
    
    *out_len = data_len;
    delete[] mBox;
    return -1;
    }
    
    int GetKey(const unsigned char* pass, int pass_len, unsigned char* out)
    {
    if(pass == NULL || out == NULL)
       return NULL;
    
    int i;
    
    for(i = 0; i < BOX_LEN; i++)
       out[i] = i;
    
    int j = 0;
    for(i = 0; i < BOX_LEN; i++)
    {
       j = (pass[i % pass_len] + out[i] + j) % BOX_LEN;
       swap_byte(&out[i], &out[j]);
    }
    
    return -1;
    }
    
    static void swap_byte(unsigned char* a, unsigned char* b)
    {
    unsigned char swapByte;
    
    swapByte = *a;
    
    *a = *b;
    
    *b = swapByte;
    }
    
    // 把字节码转为十六进制码,一个字节两个十六进制,内部为字符串分配空间
    char* ByteToHex(const unsigned char* vByte, const int vLen)
    {
    if(!vByte)
       return NULL;
    
    char* tmp = new char[vLen * 2 + 1]; // 一个字节两个十六进制码,最后要多一个'\0'
    
    int tmp2;
    for (int i=0;i<vLen;i++)
    {
       tmp2 = (int)(vByte[i])/16;
       tmp[i*2] = (char)(tmp2+((tmp2>9)?'A'-10:'0'));
       tmp2 = (int)(vByte[i])%16;
       tmp[i*2+1] = (char)(tmp2+((tmp2>9)?'A'-10:'0'));
    }
    
    tmp[vLen * 2] = '\0';
    return tmp;
    }
    
    // 把十六进制字符串,转为字节码,每两个十六进制字符作为一个字节
    unsigned char* HexToByte(const char* szHex)
    {
    if(!szHex)
       return NULL;
    
    int iLen = strlen(szHex);
    
    if (iLen<=0 || 0!=iLen%2)
       return NULL;
    
    unsigned char* pbBuf = new unsigned char[iLen/2]; // 数据缓冲区
    
    int tmp1, tmp2;
    for (int i=0;i<iLen/2;i++)
    {
       tmp1 = (int)szHex[i*2] - (((int)szHex[i*2]>='A')?'A'-10:'0');
    
       if(tmp1>=16)
        return NULL;
    
       tmp2 = (int)szHex[i*2+1] - (((int)szHex[i*2+1]>='A')?'A'-10:'0');
    
       if(tmp2>=16)
        return NULL;
    
       pbBuf[i] = (tmp1*16+tmp2);
    }
    
    return pbBuf;
    }
    
    main.cpp文件
    
    #include <iostream>
    #include <string>
    #include <stdio.h>
    
    #include "Encrypt.h"
    
    int main(int argc,char *argv[])
    {
    int size = 0;
    
    char source[] = "chenli";
    char pass[] = "123456";
    char *result1 = NULL;
    char *result2 = NULL;
    
    result1 = Encrypt(source, pass);
    
    printf("result1=%s\n", result1);
    
    result2 = Decrypt(result1, pass);
    
    printf("result2=%s\n", result2);
    
    delete []result1;
    delete []result2;
    
    return 0;
    }




  • 相关阅读:
    Linux服务安全之TcpWrapper篇
    通过cmd命令到ftp上下载文件
    常见tcp端口
    cmd常用命令
    TeeChart的最小步长和最大步长
    根据指定的commit查找对应的log
    WCF
    在IIS中某一个网站启用net.tcp
    wcf 远程终结点已终止该序列 可靠会话出错
    IIS中的Application.CommonAppDataPath
  • 原文地址:https://www.cnblogs.com/sevenr/p/3899948.html
Copyright © 2011-2022 走看看