From: Matthew N. Heler Date: Tue, 9 Jun 2026 02:13:50 +0000 (-0500) Subject: rgw: restore constant-time GCM tag comparison in ISA-L path X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=3a81a126089e201bcc0ddfcd800705d43f7d3b45;p=ceph.git rgw: restore constant-time GCM tag comparison in ISA-L path a8ed43bfc05 replaced ct_memeq with memcmp in the ISA-L GCM accelerator, making tag verification and the key-cache compare non-constant-time. Restore ct_memeq for both; the OpenSSL and EVP paths already compare in constant time. Signed-off-by: Matthew N. Heler --- diff --git a/src/crypto/isa-l/isal_crypto_accel.cc b/src/crypto/isa-l/isal_crypto_accel.cc index 77049964812..3e815be16e0 100644 --- a/src/crypto/isa-l/isal_crypto_accel.cc +++ b/src/crypto/isa-l/isal_crypto_accel.cc @@ -48,6 +48,19 @@ bool ISALCryptoAccel::cbc_decrypt(unsigned char* out, const unsigned char* in, s return true; } +/* + * Constant-time byte comparison to prevent timing attacks on tag verification. + * Always compares all bytes regardless of differences found. + */ +static inline bool ct_memeq(const unsigned char* a, const unsigned char* b, size_t len) +{ + volatile unsigned char diff = 0; + for (size_t i = 0; i < len; ++i) { + diff |= static_cast(a[i] ^ b[i]); + } + return diff == 0; +} + /* * Thread-local GCM key cache to avoid re-running aes_gcm_pre_256() for * repeated keys. Key material is securely wiped on thread exit. @@ -69,7 +82,7 @@ static inline const gcm_key_data* get_cached_gcm_key(const unsigned char* key) if (!cache) cache = std::make_unique(); - if (memcmp(cache->last_key, key, CryptoAccel::AES_256_KEYSIZE) != 0) { + if (!ct_memeq(cache->last_key, key, CryptoAccel::AES_256_KEYSIZE)) { aes_gcm_pre_256(key, &cache->cached_gkey); memcpy(cache->last_key, key, CryptoAccel::AES_256_KEYSIZE); } @@ -127,7 +140,7 @@ bool ISALCryptoAccel::gcm_decrypt(unsigned char* out, const unsigned char* in, s static_cast(aad_len), computed_tag, AES_GCM_TAGSIZE); - if (memcmp(computed_tag, tag, AES_GCM_TAGSIZE) != 0) { + if (!ct_memeq(computed_tag, &tag[0], AES_GCM_TAGSIZE)) { memset(out, 0, size); // Clear output on auth failure return false; }