crypto: cleanse HMAC stack buffers after use
What changed, and why it matters
This commit is a defensive hardening patch for Bitcoin Core's HMAC code. It wipes two temporary memory buffers that previously held sensitive key-derived data after the HMAC operation finishes. The change reduces the risk that leftover key material could leak through memory dumps, core dumps, or side-channel attacks, but it does not fix an active bug or known exploit.
Treat as a low-risk hardening improvement. Reviewers should verify that memory_cleanse is not optimized away by the compiler on all supported build configurations and that no other sensitive stack buffers in the HMAC code paths remain uncleansed. No urgent deployment action is required.
Security signals we found
cleansing of sensitive stack buffers after cryptographic use
HMAC keyed with BIP32 chain code and HKDF PRK mentioned in commit message
memory_cleanse used to prevent potential information disclosure
defensive hardening with no observable caller change
Evidence from the diff
CHMAC_SHA256 and CHMAC_SHA512 previously left rkey[] (the padded key XORed with ipad) and temp[] (the inner hash output) on the stack without clearing them. When these HMACs are keyed with sensitive material such as BIP32 chain codes or HKDF PRK values, those buffers could retain key-derived state. The patch adds memory_cleanse() calls after constructor and Finalize() to zero these stack buffers, matching existing practice in chacha20.cpp and chacha20poly1305.cpp. This is a mitigation against information disclosure via stack memory exposure, not a vulnerability fix for a currently exploitable condition.
Changed components
src/crypto/hmac_sha256.cppsrc/crypto/hmac_sha512.cppBIP32 child key derivation (BIP32Hash in hash.cpp)BIP324 transport keying (HKDF-Expand in hkdf_sha256_32.cpp)Inspect captured patch +8 / −0
diff --git a/src/crypto/hmac_sha256.cpp b/src/crypto/hmac_sha256.cpp
index a95ef708..0796bbeb 100644
--- a/src/crypto/hmac_sha256.cpp
+++ b/src/crypto/hmac_sha256.cpp
@@ -5,6 +5,7 @@
#include <crypto/hmac_sha256.h>
#include <crypto/sha256.h>
+#include <support/cleanse.h>
#include <cstring>
@@ -26,6 +27,8 @@ CHMAC_SHA256::CHMAC_SHA256(const unsigned char* key, size_t keylen)
for (int n = 0; n < 64; n++)
rkey[n] ^= 0x5c ^ 0x36;
inner.Write(rkey, 64);
+
+ memory_cleanse(rkey, sizeof(rkey));
}
void CHMAC_SHA256::Finalize(unsigned char hash[OUTPUT_SIZE])
@@ -33,4 +36,5 @@ void CHMAC_SHA256::Finalize(unsigned char hash[OUTPUT_SIZE])
unsigned char temp[32];
inner.Finalize(temp);
outer.Write(temp, 32).Finalize(hash);
+ memory_cleanse(temp, sizeof(temp));
}
diff --git a/src/crypto/hmac_sha512.cpp b/src/crypto/hmac_sha512.cpp
index f37e709d..0a9d1041 100644
--- a/src/crypto/hmac_sha512.cpp
+++ b/src/crypto/hmac_sha512.cpp
@@ -5,6 +5,7 @@
#include <crypto/hmac_sha512.h>
#include <crypto/sha512.h>
+#include <support/cleanse.h>
#include <cstring>
@@ -26,6 +27,8 @@ CHMAC_SHA512::CHMAC_SHA512(const unsigned char* key, size_t keylen)
for (int n = 0; n < 128; n++)
rkey[n] ^= 0x5c ^ 0x36;
inner.Write(rkey, 128);
+
+ memory_cleanse(rkey, sizeof(rkey));
}
void CHMAC_SHA512::Finalize(unsigned char hash[OUTPUT_SIZE])
@@ -33,4 +36,5 @@ void CHMAC_SHA512::Finalize(unsigned char hash[OUTPUT_SIZE])
unsigned char temp[64];
inner.Finalize(temp);
outer.Write(temp, 64).Finalize(hash);
+ memory_cleanse(temp, sizeof(temp));
}
Why this scored 51/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.