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

Encrypt and decrypt string with c++, Openssl and aes

本文关键字:加密 解密 字符串 aes 使用 Openssl c++      更新时间:2023-10-16

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

奇怪的是,在一台电脑上它可以工作,而在另一台电脑上它不能。我只有原来字符串的3/4,所以结尾是错误的。

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

总而言之,第一台pc只能在没有dll的情况下工作,第二台pc只能在有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的输出:

输入:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

加密:

S ^我们◄┘"▼~¼ e╣╨L╡美元的aC♠·新西兰½h╠∟≥一°╪╥=α我╙φoCYN°☺§)↨XwY +☼▀╤M▓÷√山峡┼≡& lt; ak◄一┬÷∙z¼ut@¥≈╟∙¶√ν7° ²²²²½½½½½½½½ ε■ε■

解密:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

第二台pc的输出:

输入:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

加密:

S ^我? +"? ~¼ e¦ðLA 'aC美元?·新西兰½h¦? =°IE = OpEIYoCYN°?§)? XwY +¤¯ÐM¦÷¹山峡+ & lt; ak党?A -÷¨zð+ BnFbYU) ?s

解密:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ? WI»H +²²²²¦¦¦¦¦¦ w美元啊?o:

这两个肯定坏了....

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字节。


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

return string ((char *) dec_out);

它需要类似于:

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

你对AES_cbc_encrypt的使用看起来是错误的。您应该坚持使用EVP_*接口。参考OpenSSL wiki上的EVP对称加密与解密。

最好使用像GCM这样的经过身份验证的加密模式,这样您也可以获得真实性/完整性保证。参考OpenSSL wiki上的"EVP认证加解密"。


最后,使用较大的散列,如SHA256SHA512。除了向后兼容之外,MD5不再用于任何其他用途。