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

11,333

These two are broken for sure....

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

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

You would need something like:

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

Otherwise, the string produced by MD5 is truncated at the first 0x00 the string constructor encounters.


These are trouble:

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

At best, MD5 produces a string of 16 bytes. You can't pull 32 bytes out of the 16 byte string in EncKey.

And you are in trouble if either EncKey or EncIV has an embedded null. If either has one, then that string is not even 16 bytes.


And as Jim pointed out in the comment below, this is also trouble:

return string ((char *) dec_out);

It needs to be similar to:

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

And your use of AES_cbc_encrypt looks wrong. You should stick with the EVP_* interface. For an example, see EVP Symmetric Encryption and Decryption on the OpenSSL wiki.

Better, use an authenticated encryption mode like GCM so you get authenticity/integrity assurances, too. For an example, see EVP Authenticated Encryption and Decryption on the OpenSSL wiki.


Finally, use a larger hash like SHA256 or SHA512. MD5 is no longer desired for anything other than backwards compatibility.

Share:
11,333
schacker22
Author by

schacker22

Updated on July 01, 2022

Comments

  • schacker22
    schacker22 almost 2 years

    I'm trying to encrypt and decrypt a string with c++ openssl and aes cbc.

    The weird thing about this is, on one pc it works, and on the other pc it doesn't. There i have only 3/4 of the original string, so the ending is wrong.

    The other weird thing is, when i add a dll called "libeay32.dll" to the directory of the exe file on the second pc, it works, but not on the first pc.

    In summary, first pc only works without dll, second pc works only with dll.

    My question is, can this code be improved, and why this dll is needed on one computer but not on the other.

    Here's what i've already written:

    KEY and Iv are defines:

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

    Encryption function:

    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);
    
    }
    

    Decryption function:

    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);
    
    }
    

    Output of first pc:

    Input:

    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

    Encrypted:

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

    Decrypted:

    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

    Output of second pc:

    Input:

    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

    Encrypted:

    S^Wo?+"â?~¼\é¦$ðLÁ`aC?·ñZ½h¦?=ä°ÏÊ=ÓpËIÝoCYN°?§)?XwY+¤¯ÐM¦÷¹NÉk+­<ák?Ä-÷¨zð+BñFb YÙ]?s

    Decrypted:

    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?WλH+²²²²¦¦¦¦¦¦w$ö?ó:

  • Jim Flood
    Jim Flood almost 10 years
    This is also trouble: return string ((char *) enc_out); -- enc_out is not null-terminated, and, may accidently be null-terminated by null bytes.