Correct way to free/allocate the context in the OpenSSL

11,866

Solution 1

Allright, i think it's cleared now. If you do EVP style encryption/decryption, make sure you create the context like so:

  EVP_CIPHER_CTX ctx;
  EVP_CIPHER_CTX_init(&ctx);

And free it like so:

EVP_CIPHER_CTX_cleanup(&ctx); 

Don't use EVP_CIPHER_CTX_new/EVP_CIPHER_CTX_free to create/free the context, they are deprecated!

Solution 2

First of all if you want a precise answer, you should always specify which version of OpenSSL you are using. FYI 1.0.2 is current Long Term Support version, while 1.1.0 is the newest (in Sept 2016).

If you read the 1.1.0 man pages you will notice:

EVP_CIPHER_CTX was made opaque in OpenSSL 1.1.0. As a result, EVP_CIPHER_CTX_reset() appeared and EVP_CIPHER_CTX_cleanup() disappeared. EVP_CIPHER_CTX_init() remains as an alias for EVP_CIPHER_CTX_reset().

Short answer is: you should use EVP_CIPHER_CTX_new to initialize and EVP_CIPHER_CTX_free do free the memory, regardless of the version, here's why.

Allocating:

1.0.2 man pages say:

EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);

and 1.1.0 man pages say:

EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();

If you look at the code of EVP_CIPHER_CTX_init in 1.0.2

void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx)
{
   memset(ctx, 0, sizeof(EVP_CIPHER_CTX));
   /* ctx->cipher=NULL; */
}

while EVP_CIPHER_CTX_new is:

EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void)
{
   EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof *ctx);
   if (ctx)
      EVP_CIPHER_CTX_init(ctx);
   return ctx;
}

so you you are still better off initializing the context, like in 1.1.0 example:

EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();

for 1.1.0 the same applies.

For freeing the memory:

1.0.2 man pages:

EVP_CIPHER_CTX_cleanup(&ctx);

1.1.0 man pages:

EVP_CIPHER_CTX_free(ctx);

But if you check the code you can see that for 1.0.2:

void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
{
   if (ctx) {
       EVP_CIPHER_CTX_cleanup(ctx);
      OPENSSL_free(ctx);
   }
}

So you should use EVP_CIPHER_CTX_free for deallocating. If you just want to reset the context for another operation then EVP_CIPHER_CTX_cleanup(1.0.2) and EVP_CIPHER_CTX_reset(1.1.0) are your friends.

If you are curious about malloc memset and calloc, here's a good explanation

Solution 3

You should not use EVP_EncryptInit anymore. That function did automatically create a specific context, but it didn't support the crypto engines that were later added. EVP_EncryptInit_ex however explicitly states that:

ctx must be initialized before calling this function.

so you are required to use EVP_CIPHER_CTX_new here I suppose.

EVP_CIPHER_CTX_free is another matter, it seems to have been deprecated, I don't see any mention of it on the manual pages of OpenSSL. It is good practice (and required for NIST certified functionality) to delete key material and other state of a cipher after use. Otherwise an attacker may scan the memory or use an overflow at a later stage.

The name of EVP_CIPHER_CTX_free only indicates that the CTX memory should be released. But freeing of memory does not imply that it is scrubbed of sensitive information first; it's just returned to the system, which is under no obligation to overwrite it either. EVP_CIPHER_CTX_cleanup on the other hand does explicitly scrub such information before freeing the memory (or it does at least make a decent attempt to do so, I presume). So you need to call this function after you've supplied your key material.

Share:
11,866
Vanya
Author by

Vanya

Updated on June 08, 2022

Comments

  • Vanya
    Vanya almost 2 years

    I'am using the Open SSL in my program, to encrypt and decrypt the data using aes ciphers. At the moment there is a little memory leak, so i'm looking for a way to fix that. In my encrypt decrypt routines, i have the contexts free like so

    EVP_CIPHER_CTX_free(ctx);
    

    And created by:

    EVP_CIPHER_CTX_new
    

    This was on the OpenSSL wiki page in the examples

    But! On the MAN page, there is a suggestion for using EVP_CIPHER_CTX_cleanup and EVP_CIPHER_CTX_init functions. So basically what should be correct to use, is the EVP_CIPHER_CTX_new/EVP_CIPHER_CTX_free is somehow deprecated? And is there any big difference between EVP_CIPHER_CTX_new/EVP_CIPHER_CTX_free and EVP_CIPHER_CTX_init / EVP_CIPHER_CTX_cleanup ?

    if(!(ctx = EVP_CIPHER_CTX_new())) return -1;
    
    
      if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
      {
        EVP_CIPHER_CTX_free(ctx);
        return -1;
      }
    
      if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
      {
        EVP_CIPHER_CTX_free(ctx);
        return -1;
      }
      ciphertext_len = len;
    
    
      if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) { EVP_CIPHER_CTX_free(ctx); return -1; }
      ciphertext_len += len;
    
    
      EVP_CIPHER_CTX_free(ctx);
    
  • Maarten Bodewes
    Maarten Bodewes over 9 years
    I don't think your memory issue is within the context, looking at your code. You may want to try some other things such as static code analyzers.
  • pixelbeat
    pixelbeat about 8 years
    It's the opposite I think. In fact openssl-1.1.0 makes EVP_CIPHER_CTX an opaque type, so the first form above is a compile error
  • rdb
    rdb over 7 years
    This answer has it exactly backwards as stated in the other answers. Please update or unaccept it.
  • Djvu
    Djvu over 2 years
    with EVP_CIPHER_CTX/EVP_CIPHER_CTX_free, but valgrind show that definitely lost memory.