This post introduces some tips of optimising applications which use OpenSSL
.
(1) Per-thread memory pool. Because OpenSSL
heavily allocate/free memories in its internals, implementing bespoke memory management functions which use per-thread memory pool (register them with CRYPTO_set_mem_functions
) can improve performance.
(2) Reuse contexts. E.g., for EVP_PKEY_CTX
, since every time EVP_PKEY_derive_init()
will initialise its content, every thread can pre-allocate one EVP_PKEY_CTX
and avoid allocating & freeing EVP_PKEY_CTX
frequently. Further more, from the document:
The function EVP_PKEY_derive() can be called more than once on the same context if several operations are performed using the same parameters.
Another example is about EVP_CIPHER_CTX
; a typical program is like this:
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, key, nonce);
EVP_EncryptUpdate(ctx, NULL, &len, aad, sizeof(aad));
EVP_EncryptUpdate(ctx, ct, &ct_len, pt, sizeof(pt));
EVP_EncryptFinal_ex(ctx, ct + ct_len, &len);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, ct + ct_len);
EVP_CIPHER_CTX_free(ctx);
Actually, we can create a dedicated EVP_CIPHER_CTX
for one EVP_CIPHER
, i.e.:
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
Then in program, we can reuse this EVP_CIPHER_CTX
, and just modify other parameters:
EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce);
EVP_EncryptUpdate(ctx, NULL, &len, aad, sizeof(aad));
EVP_EncryptUpdate(ctx, ct, &ct_len, pt, sizeof(pt));
EVP_EncryptFinal_ex(ctx, ct + ct_len, &len);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, ct + ct_len);
This also applies to EVP_Decrypt*
functions.