RC4加密出现空字符

来源:互联网 发布:类似金十数据的网站 编辑:程序博客网 时间:2024/05/16 07:24
RC4加密出现空字符


    最近做的竞赛用了RC4加密,网上COPY的代码(没兴趣自己研究密码学,而且我没有数学天分),整到MFC程序中,出了点小问题。
先上代码(做了点小修改)


#include<stdio.h>
#include<string.h>
/*-----------------------初始化函数定义--------------------------*/
void rc4_init(unsigned char *s, unsigned char *key, unsigned long Len)  // s为S-box的地址,key是密钥字符串地址,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)  // s是S-box的地址,Data是需要加(解)密字符串地址
{  // 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];
    }
}
/*-------------------------主函数-----------------------------*/
void main()
{
    unsigned char s[256]={0}; //S-box
    char key[256];
    char pData[512];
    unsigned long len;
    printf("Input Message:");
    gets(pData);
    len=strlen(pData);
    printf("Input Key:");
    gets(key);

    rc4_init(s,(unsigned char *)key,strlen(key));//  调用初始化函数用密钥对S-box进行初始化
    rc4_crypt(s,(unsigned char *)pData,len);//  加密

    printf("cipher text: \"%s\"\n\n",pData);//  输出密文

    rc4_init(s,(unsigned char *)key, strlen(key));//  调用初始化函数对S-box进行初始化
    rc4_crypt(s,(unsigned char *)pData,len);//  解密

    printf("plain text: \"%s\"\n\n",pData);//  输出明文
}


    你可以试验一下,输入明文SuperMan(注意大小写),输入密钥123。你发现了什么!密文是"",可是再次解密得到的明文却仍然是
"SuperMan"。当时我就震惊了。这是为什么呢?调试发现是在明文加密时,也就是第一次进入rc4_crypt函数时,
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];//看这里看这里

}

    经过一系列变换,s[t]是字符'S',而明文的第一个字符Data[0]刚好是'S',这个时候要进行异或(Data[k] ^= s[t])操作,就导致Data[0]的值变为0,也就是'\0',在后面输出密文的时候,printf函数把'\0'作为字符串结尾,于是输出的就是空的了。
    但是解密为什么又能成功呢?因为解密的时候rc4_crypt函数是分别对pData的每个元素解密的,pData[0]不管是什么,它都给你解密出来。另外在对一个字符串进行加密的时候,i、j变量都是在变的,所以你输入"nSuperMan",这里的'S'就不会变成'\0'了。
    既然解密出来是对的,那还有什么问题呢?当我把它用到MFC程序中就出问题了。我的MFC程序里用的都是CString类型的,CString很方便,我很喜欢,但是CString也是把'\0'当做字符串结尾的,于是我有些字符串加密出来就会信息不全,甚至向上面的"SuperMan"一样,完全给整没了。
    那该怎么办呢?我就用了个最简单的方法:遇到s[t]和Data[k]相同的情况,那个字符直接不加密。Just like that:

if( Data[k] != s[t] )
Data[k] ^= s[t];
    不管你喜不喜欢,我还是这样做了。我又懒又笨,不喜欢搞得太复杂。你有什么好的方法,欢迎交流。
    具体的MFC代码,不管你需不需要,我也给上了吧。RC4源代码用s[256]、key[256]、pData[512],我也就用这些了,懒得去搞个纯MFC版本的RC4。

void CRC4Dlg::OnEncrypt() //用来加密的Button的消息响应函数
{
    UpdateData();

    unsigned char s[256]={0};
    char pData[512] = {0};

    int nLength = m_plain.GetLength();//这里m_plain是与一个EditBox相关联的CString类型的成员变量
    for(int i = 0 ; i < nLength ; i++ )//nLength保存了m_plain的字符数
    {
        pData[i] = m_plain.GetAt(i);//对pData进行赋值
    }
    char key[256] = {OURKEY};//OURKEY 是个宏:#define OURKEY "123" // 你想要的密钥

    rc4_init(s,(unsigned char *)key,strlen(key));//初始化S-box
    rc4_crypt(s,(unsigned char *)pData,strlen(pData));//加密
    m_cryption = pData;//m_cryption也是和一个EditBox相关联的CString类型的变量,用来保存密文

    UpdateData(FALSE);
}
void CRC4Dlg::OnDecrypt() //用来解密的Button的消息响应函数
{
    UpdateData();
    int i;
    unsigned char s[256]={0};
    char pData[512] = {0};
    int nLength;
    length = m_cryption.GetLength();

    for( i = 0 ; i < nLength ; i++ )
    {
        pData[i] = m_cryption.GetAt(i);
    }
    char key[256] = {OURKEY};

    rc4_init(s,(unsigned char *)key,strlen(key));//初始化S-box
    rc4_crypt(s,(unsigned char *)pData,strlen(pData));//解密

    m_decryption = pData;//m_decryption是个和EditBox相关的CString类的变量,存放解密出的明文

    UpdateData(FALSE);
}
    还有别忘了在rc4_crypt中处理会出现'\0'的那段代码,否则加密后密文就没了。
    这里还有个问题,你在加密的编辑框输入"SuperMan",按加密按钮,密文的编辑框上会显示密文,当你按下解密按钮的时候,出现在解密出的明文的编辑框上的"SuperMa",少了个字符,经常会出现这种情况。这可能是UpdateData从编辑框交换数据时候出的问题。这个问题我没有去研究,求大神指导。另外如果把密文存到一个文件中,再读取这个文件中的密文进行解密,貌似一点问题都没有。

原创粉丝点击