Skip to content

Commit d25fbe4

Browse files
committed
PG-2278 Re-use cipher contexts for SMGR encryption
Profiling with perf revealed that EVP_CipherInit_ex() showed up quite a lot when encrypting and decrypting tables, so to decrease how much it shows up we make sure to only allocate and initialize contexts for SMGR encryption once on loading pg_tde and then re-use those contexts but re-initializing them with different keys and IVs on use, which is a lot cheaper than doing a full initialization. This way of calling EVP_CipherInit_ex() is poorly documented in OpenSSL. While at it also remove a useless call to the finalize function which is not necessary due to the lack of padding. It did not show up in profiling but it also adds no value and there is precedence for us skipping it in our AES-CTR code. WAL encryption already has logic for reusing contexts so this optimization is not as relevant there.
1 parent a2ae945 commit d25fbe4

1 file changed

Lines changed: 25 additions & 16 deletions

File tree

src/encryption/enc_aes.c

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,42 @@
3232
* 16 byte blocks.
3333
*/
3434

35-
static const EVP_CIPHER *cipher_cbc_128 = NULL;
3635
static const EVP_CIPHER *cipher_gcm_128 = NULL;
3736
static const EVP_CIPHER *cipher_ctr_ecb_128 = NULL;
3837

39-
static const EVP_CIPHER *cipher_cbc_256 = NULL;
4038
static const EVP_CIPHER *cipher_gcm_256 = NULL;
4139
static const EVP_CIPHER *cipher_ctr_ecb_256 = NULL;
4240

41+
static EVP_CIPHER_CTX *ctx_cbc_128 = NULL;
42+
static EVP_CIPHER_CTX *ctx_cbc_256 = NULL;
43+
44+
static EVP_CIPHER_CTX *
45+
AesCbcInitCtx(const EVP_CIPHER *cipher, const char *name)
46+
{
47+
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
48+
49+
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, 1) == 0)
50+
ereport(ERROR,
51+
errmsg("EVP_CipherInit_ex of %s failed. OpenSSL error: %s",
52+
name, ERR_error_string(ERR_get_error(), NULL)));
53+
54+
EVP_CIPHER_CTX_set_padding(ctx, 0);
55+
56+
return ctx;
57+
}
58+
4359
void
4460
AesInit(void)
4561
{
4662
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
4763

48-
cipher_cbc_128 = EVP_aes_128_cbc();
4964
cipher_gcm_128 = EVP_aes_128_gcm();
5065
cipher_ctr_ecb_128 = EVP_aes_128_ecb();
66+
ctx_cbc_128 = AesCbcInitCtx(EVP_aes_128_cbc(), "AES-128-CBC");
5167

52-
cipher_cbc_256 = EVP_aes_256_cbc();
5368
cipher_gcm_256 = EVP_aes_256_gcm();
5469
cipher_ctr_ecb_256 = EVP_aes_256_ecb();
70+
ctx_cbc_256 = AesCbcInitCtx(EVP_aes_256_cbc(), "AES-256-CBC");
5571
}
5672

5773
static void
@@ -94,23 +110,18 @@ AesRunCbc(int enc, const unsigned char *key, int key_len, const unsigned char *i
94110
{
95111
int out_len;
96112
int out_len_final;
97-
EVP_CIPHER_CTX *ctx = NULL;
98-
const EVP_CIPHER *cipher;
113+
EVP_CIPHER_CTX *ctx;
99114

100115
Assert(key_len == 16 || key_len == 32);
101-
cipher = key_len == 32 ? cipher_cbc_256 : cipher_cbc_128;
116+
ctx = key_len == 32 ? ctx_cbc_128 : ctx_cbc_128;
102117

103-
Assert(cipher != NULL);
104-
Assert(in_len % EVP_CIPHER_block_size(cipher) == 0);
105-
106-
ctx = EVP_CIPHER_CTX_new();
118+
Assert(ctx != NULL);
119+
Assert(in_len % EVP_CIPHER_CTX_block_size(ctx) == 0);
107120

108-
if (EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc) == 0)
121+
if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc) == 0)
109122
ereport(ERROR,
110123
errmsg("EVP_CipherInit_ex failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL)));
111124

112-
EVP_CIPHER_CTX_set_padding(ctx, 0);
113-
114125
if (EVP_CipherUpdate(ctx, out, &out_len, in, in_len) == 0)
115126
ereport(ERROR,
116127
errmsg("EVP_CipherUpdate failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL)));
@@ -125,8 +136,6 @@ AesRunCbc(int enc, const unsigned char *key, int key_len, const unsigned char *i
125136
*/
126137
out_len += out_len_final;
127138
Assert(in_len == out_len);
128-
129-
EVP_CIPHER_CTX_free(ctx);
130139
}
131140

132141
void

0 commit comments

Comments
 (0)