From c9d0677e4fe2be07af0938aabac2fe6ee1635545 Mon Sep 17 00:00:00 2001 From: MarkLee131 Date: Wed, 29 Apr 2026 17:06:49 +0800 Subject: [PATCH] Utils: prefer CRYPTO_memcmp in ConstantTimeEquals when OpenSSL is available Per review feedback on #2017: a hand-rolled byte loop can in principle be folded back into a short-circuiting compare by an aggressive optimizer. Use CRYPTO_memcmp under HAVE_LIBSSL since OpenSSL is already a build dependency for the SHA256 path. For non-OpenSSL builds, mark the accumulator and pointers volatile and note in a comment that this is best-effort. --- src/Utils.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index d83e3ee5..22d264c7 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -28,6 +28,7 @@ #ifdef HAVE_LIBSSL #include #include +#include #include #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x20700000L)) #define X509_getm_notBefore X509_get_notBefore @@ -279,13 +280,22 @@ bool CUtils::ConstantTimeEquals(const CString& a, const CString& b) { if (a.length() != b.length()) { return false; } - unsigned char acc = 0; - const unsigned char* pa = reinterpret_cast(a.data()); - const unsigned char* pb = reinterpret_cast(b.data()); +#ifdef HAVE_LIBSSL + return CRYPTO_memcmp(a.data(), b.data(), a.length()) == 0; +#else + // Best-effort fallback when OpenSSL is unavailable: an optimizer is + // in principle allowed to short-circuit this loop, so the volatile + // accumulator and pointers are a hint rather than a guarantee. + volatile unsigned char acc = 0; + const volatile unsigned char* pa = + reinterpret_cast(a.data()); + const volatile unsigned char* pb = + reinterpret_cast(b.data()); for (size_t i = 0; i < a.length(); ++i) { acc |= static_cast(pa[i] ^ pb[i]); } return acc == 0; +#endif } CString CUtils::GetPass(const CString& sPrompt) {