Correct way to free/allocate the context in the OpenSSL
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.
Vanya
Updated on June 08, 2022Comments
-
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
andEVP_CIPHER_CTX_init
functions. So basically what should be correct to use, is theEVP_CIPHER_CTX_new
/EVP_CIPHER_CTX_free
is somehow deprecated? And is there any big difference betweenEVP_CIPHER_CTX_new
/EVP_CIPHER_CTX_free
andEVP_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 over 9 yearsI 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 about 8 yearsIt'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 over 7 yearsThis answer has it exactly backwards as stated in the other answers. Please update or unaccept it.
-
Djvu over 2 yearswith EVP_CIPHER_CTX/EVP_CIPHER_CTX_free, but valgrind show that definitely lost memory.