Skip to content

Commit 9a0684b

Browse files
committed
Fix AES MySQL default-IV regression when reusing OpenSSL contexts by ensuring zero IV is explicitly set per row instead of reusing the previous block’s IV.
Add a helper to supply a zero-filled IV buffer and route all reuse/init paths through it for both encrypt and decrypt code paths.
1 parent 0e4f172 commit 9a0684b

File tree

1 file changed

+41
-19
lines changed

1 file changed

+41
-19
lines changed

src/Functions/FunctionsAES.h

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,17 @@ class FunctionEncrypt : public IFunction
275275
const auto block_size = static_cast<size_t>(EVP_CIPHER_block_size(evp_cipher));
276276
const auto key_size = static_cast<size_t>(EVP_CIPHER_key_length(evp_cipher));
277277
[[maybe_unused]] const auto iv_size = static_cast<size_t>(EVP_CIPHER_iv_length(evp_cipher));
278+
std::string zero_iv_buffer;
279+
auto getIVPtr = [&](const StringRef & iv_value) -> const unsigned char *
280+
{
281+
if (iv_size > 0 && iv_value.size == 0)
282+
{
283+
if (zero_iv_buffer.size() != iv_size)
284+
zero_iv_buffer.assign(iv_size, '\0');
285+
return reinterpret_cast<const unsigned char *>(zero_iv_buffer.data());
286+
}
287+
return reinterpret_cast<const unsigned char *>(iv_value.data);
288+
};
278289
const auto tag_size = 16; // https://tools.ietf.org/html/rfc5116#section-5.1
279290

280291
auto encrypted_result_column = ColumnString::create();
@@ -341,7 +352,7 @@ class FunctionEncrypt : public IFunction
341352
{
342353
if (EVP_EncryptInit_ex(evp_ctx, evp_cipher, nullptr,
343354
reinterpret_cast<const unsigned char*>(const_key_value.data),
344-
reinterpret_cast<const unsigned char*>(const_iv_value.data)) != 1)
355+
getIVPtr(const_iv_value)) != 1)
345356
onError("EVP_EncryptInit_ex");
346357
}
347358
}
@@ -358,7 +369,7 @@ class FunctionEncrypt : public IFunction
358369

359370
/// Reset context to the fresh state but keep the already prepared key schedule.
360371
if (row_idx != 0 && EVP_EncryptInit_ex(evp_ctx, nullptr, nullptr, nullptr,
361-
reinterpret_cast<const unsigned char*>(iv_value.data)) != 1)
372+
getIVPtr(iv_value)) != 1)
362373
onError("EVP_EncryptInit_ex");
363374
}
364375
else if (can_reuse_gcm_key)
@@ -395,7 +406,7 @@ class FunctionEncrypt : public IFunction
395406
validateIV<mode>(iv_value, iv_size);
396407

397408
if (EVP_EncryptInit_ex(evp_ctx, nullptr, nullptr, nullptr,
398-
reinterpret_cast<const unsigned char*>(iv_value.data)) != 1)
409+
getIVPtr(iv_value)) != 1)
399410
onError("EVP_EncryptInit_ex");
400411
}
401412
else
@@ -435,17 +446,17 @@ class FunctionEncrypt : public IFunction
435446
// 1: Init CTX
436447
if constexpr (mode == CipherMode::RFC5116_AEAD_AES_GCM)
437448
{
438-
// 1.a.1: Init CTX with custom IV length
439-
if (EVP_EncryptInit_ex(evp_ctx, evp_cipher, nullptr, nullptr, nullptr) != 1)
440-
onError("EVP_EncryptInit_ex");
449+
// 1.a.1: Init CTX with custom IV length
450+
if (EVP_EncryptInit_ex(evp_ctx, evp_cipher, nullptr, nullptr, nullptr) != 1)
451+
onError("EVP_EncryptInit_ex");
441452

442-
if (EVP_CIPHER_CTX_ctrl(evp_ctx, EVP_CTRL_AEAD_SET_IVLEN, safe_cast<int>(iv_value.size), nullptr) != 1)
443-
onError("EVP_CIPHER_CTX_ctrl");
453+
if (EVP_CIPHER_CTX_ctrl(evp_ctx, EVP_CTRL_AEAD_SET_IVLEN, safe_cast<int>(iv_value.size), nullptr) != 1)
454+
onError("EVP_CIPHER_CTX_ctrl");
444455

445-
if (EVP_EncryptInit_ex(evp_ctx, nullptr, nullptr,
446-
reinterpret_cast<const unsigned char*>(key_value.data),
447-
reinterpret_cast<const unsigned char*>(iv_value.data)) != 1)
448-
onError("EVP_EncryptInit_ex");
456+
if (EVP_EncryptInit_ex(evp_ctx, nullptr, nullptr,
457+
reinterpret_cast<const unsigned char*>(key_value.data),
458+
getIVPtr(iv_value)) != 1)
459+
onError("EVP_EncryptInit_ex");
449460
}
450461
else
451462
{
@@ -454,7 +465,7 @@ class FunctionEncrypt : public IFunction
454465

455466
if (EVP_EncryptInit_ex(evp_ctx, evp_cipher, nullptr,
456467
reinterpret_cast<const unsigned char*>(key_value.data),
457-
reinterpret_cast<const unsigned char*>(iv_value.data)) != 1)
468+
getIVPtr(iv_value)) != 1)
458469
onError("EVP_EncryptInit_ex");
459470
}
460471
}
@@ -651,6 +662,17 @@ class FunctionDecrypt : public IFunction
651662

652663
[[maybe_unused]] const auto block_size = static_cast<size_t>(EVP_CIPHER_block_size(evp_cipher));
653664
[[maybe_unused]] const auto iv_size = static_cast<size_t>(EVP_CIPHER_iv_length(evp_cipher));
665+
std::string zero_iv_buffer;
666+
auto getIVPtr = [&](const StringRef & iv_value) -> const unsigned char *
667+
{
668+
if (iv_size > 0 && iv_value.size == 0)
669+
{
670+
if (zero_iv_buffer.size() != iv_size)
671+
zero_iv_buffer.assign(iv_size, '\0');
672+
return reinterpret_cast<const unsigned char *>(zero_iv_buffer.data());
673+
}
674+
return reinterpret_cast<const unsigned char *>(iv_value.data);
675+
};
654676

655677
const size_t key_size = static_cast<size_t>(EVP_CIPHER_key_length(evp_cipher));
656678
static constexpr size_t tag_size = 16; // https://tools.ietf.org/html/rfc5116#section-5.1
@@ -726,7 +748,7 @@ class FunctionDecrypt : public IFunction
726748
{
727749
if (EVP_DecryptInit_ex(evp_ctx, evp_cipher, nullptr,
728750
reinterpret_cast<const unsigned char*>(const_key_value.data),
729-
reinterpret_cast<const unsigned char*>(const_iv_value.data)) != 1)
751+
getIVPtr(const_iv_value)) != 1)
730752
onError("EVP_DecryptInit_ex");
731753
}
732754
}
@@ -744,7 +766,7 @@ class FunctionDecrypt : public IFunction
744766

745767
/// Reset context but keep already computed key schedule.
746768
if (row_idx != 0 && EVP_DecryptInit_ex(evp_ctx, nullptr, nullptr, nullptr,
747-
reinterpret_cast<const unsigned char*>(iv_value.data)) != 1)
769+
getIVPtr(iv_value)) != 1)
748770
onError("EVP_DecryptInit_ex");
749771
}
750772
else if (can_reuse_gcm_key)
@@ -766,7 +788,7 @@ class FunctionDecrypt : public IFunction
766788
onError("EVP_CIPHER_CTX_ctrl");
767789

768790
if (EVP_DecryptInit_ex(evp_ctx, nullptr, nullptr, nullptr,
769-
reinterpret_cast<const unsigned char*>(iv_value.data)) != 1)
791+
getIVPtr(iv_value)) != 1)
770792
onError("EVP_DecryptInit_ex");
771793
}
772794
else if (can_reuse_key_schedule)
@@ -784,7 +806,7 @@ class FunctionDecrypt : public IFunction
784806
validateIV<mode>(iv_value, iv_size);
785807

786808
if (EVP_DecryptInit_ex(evp_ctx, nullptr, nullptr, nullptr,
787-
reinterpret_cast<const unsigned char*>(iv_value.data)) != 1)
809+
getIVPtr(iv_value)) != 1)
788810
onError("EVP_DecryptInit_ex");
789811
}
790812
else
@@ -850,7 +872,7 @@ class FunctionDecrypt : public IFunction
850872
// 1.a.1 : Init CTX with key and IV
851873
if (EVP_DecryptInit_ex(evp_ctx, nullptr, nullptr,
852874
reinterpret_cast<const unsigned char*>(key_value.data),
853-
reinterpret_cast<const unsigned char*>(iv_value.data)) != 1)
875+
getIVPtr(iv_value)) != 1)
854876
onError("EVP_DecryptInit_ex");
855877
}
856878
else
@@ -860,7 +882,7 @@ class FunctionDecrypt : public IFunction
860882

861883
if (EVP_DecryptInit_ex(evp_ctx, evp_cipher, nullptr,
862884
reinterpret_cast<const unsigned char*>(key_value.data),
863-
reinterpret_cast<const unsigned char*>(iv_value.data)) != 1)
885+
getIVPtr(iv_value)) != 1)
864886
onError("EVP_DecryptInit_ex");
865887
}
866888
}

0 commit comments

Comments
 (0)