使用c ++,Openssl和aes加密和解密字符串

时间:2014-06-27 18:00:43

标签: c++ encryption dll openssl aes

我正在尝试使用c ++ openssl和aes cbc加密和解密字符串。

关于这一点的奇怪之处在于,它可以在一台电脑上工作,而在另一台电脑上则不然。我只有3/4的原始字符串,所以结尾是错误的。

另一个奇怪的事情是,当我在第二台PC上的exe文件目录中添加一个名为“libeay32.dll”的dll时,它可以工作,但不能在第一台PC上运行。

总之,第一台电脑只能在不使用dll的情况下工作,第二部电脑只适用于dll。

我的问题是,是否可以改进此代码,以及为什么在一台计算机上需要这个dll而在另一台计算机上不需要。

以下是我已经写过的内容:

KEY和Iv是定义:

#define KEY "abc"
#define Iv  "abc"

加密功能:

string aes_encrypt(string _InStr)
{
    string  EncKey,
            EncIV;

    AES_KEY enc_key;

    unsigned char * aes_key   = (unsigned char *) malloc (sizeof(unsigned char) * (32)),
                  * iv_enc    = (unsigned char *) malloc (sizeof(unsigned char) * AES_BLOCK_SIZE),
                  * aes_input = (unsigned char *) malloc (sizeof(unsigned char) * _InStr.size ()),
                  * enc_out   = (unsigned char *) malloc (sizeof(unsigned char) * ((_InStr.size () + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE);



    memcpy ((char *) aes_input, _InStr.c_str (), _InStr.size ());

    memset (aes_key, 0, 32);

    EncKey = KEY;
    EncIV  = Iv;

    for (int i = 0; i < 50; i++)
        EncKey = md5 (EncKey.c_str ());


    for (int i = 0; i < 305; i++)
        EncIV = md5 (EncIV.c_str ());

    EncIV.erase (16);

    memcpy (aes_key, EncKey.c_str (), 32);
    memcpy (iv_enc,  EncIV.c_str  (), 16);


    AES_set_encrypt_key (aes_key, 128, &enc_key);
    AES_cbc_encrypt     (aes_input, enc_out, _InStr.size (), &enc_key, iv_enc, AES_ENCRYPT);


    free (aes_key);
    free (aes_input);
    free (iv_enc); 

    aes_key     = NULL;
    aes_input   = NULL;
    iv_enc      = NULL;

    return string ((char *) enc_out);

}

解密功能:

string aes_decrypt (string _InStr)
{
    string  EncKey,
            EncIV;

    AES_KEY dec_key;

    unsigned char * aes_key   = (unsigned char *) malloc (sizeof(unsigned char) * (32)),
                  * iv_dec    = (unsigned char *) malloc (sizeof(unsigned char) * AES_BLOCK_SIZE),
                  * enc_out   = (unsigned char *) malloc (sizeof(unsigned char) * _InStr.size ()),
                  * dec_out   = (unsigned char *) malloc (sizeof(unsigned char) * _InStr.size ());


    memcpy (enc_out, _InStr.c_str (), _InStr.size ());

    memset (aes_key, 0, 32);

    EncKey = KEY;
    EncIV  = Iv;

    for (int i = 0; i < 50; i++)
        EncKey = md5 (EncKey.c_str ());

    for (int i = 0; i < 305; i++)
        EncIV = md5 (EncIV.c_str ());

    EncIV.erase (16);

    memcpy (aes_key, EncKey.c_str (), 32);
    memcpy (iv_dec,  EncIV.c_str  (), 16);

    AES_set_decrypt_key(aes_key, 128, &dec_key);
    AES_cbc_encrypt(enc_out, dec_out, _InStr.size (), &dec_key, iv_dec, AES_DECRYPT);

    free (aes_key);
    free (iv_dec); 
    free (enc_out);  

    aes_key     = NULL;
    iv_dec      = NULL;
    enc_out     = NULL;

    return string ((char *) dec_out);

}

第一台PC的输出:

输入:

  

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa   aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

加密:

  

取值^Wo◄┘“â▼〜¼\é╣$╨L╡`aC♠·ñZ½h╠∟≥ä°╪╥=αp╙IφoCYN°☺§)↨XwY+☼▀╤M▓÷√NÉk ┼≡&LT;ák◄Ä┬÷∙ž   ¼üt@¥≈╟∙¶√Ñù°7å²²²²½½½½½½½½ε■ε■

解密:

  

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa   aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

第二台PC的输出:

输入:

  

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa   aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

加密:

  

取值^禾+“A〜¼\ $英哩·ðLÁ`aC=ñZ½h|A°IE =ÓpËIÝoCYN°§)XWY +¤¯ÐM|÷¹NÉk+ LT;???????AK A-÷¨ ZD +BñFb   郁]?的

解密:

  

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa   aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa WI»H +²²²²||||||w$○○:?

1 个答案:

答案 0 :(得分:3)

这两个肯定会被打破......

for (int i = 0; i < 50; i++)
    EncKey = md5 (EncKey.c_str ());

for (int i = 0; i < 305; i++)
    EncIV = md5 (EncIV.c_str ());

您需要以下内容:

EncKey = string(md5 (EncKey.c_str ()), 16);

否则,MD5生成的字符串将在string构造函数遇到的第一个0x00处被截断。


这些都是麻烦:

memcpy (aes_key, EncKey.c_str (), 32);
memcpy (iv_enc,  EncIV.c_str  (), 16);

最好,MD5生成一个16字节的字符串。您无法从EncKey中的16字节字符串中提取32个字节。

如果EncKeyEncIV嵌入了null,则会遇到麻烦。如果其中一个有一个,那么该字符串甚至不是16个字节。


正如吉姆在下面的评论中指出的那样,这也是一个麻烦:

return string ((char *) dec_out);

它需要类似于:

string aes_encrypt(string _InStr)
{
    ...
    return string ((char *) dec_out, <some size>);
}

你使用AES_cbc_encrypt看起来不对劲。你应该坚持EVP_*界面。有关示例,请参阅OpenSSL wiki上的EVP Symmetric Encryption and Decryption

更好的是,使用像GCM这样经过身份验证的加密模式,这样您就可以获得真实性/完整性保证。有关示例,请参阅OpenSSL wiki上的EVP Authenticated Encryption and Decryption


最后,使用较大的哈希值,例如SHA256SHA512。除了向后兼容性之外,不再需要MD5。