crypto: Use `secure_allocator` for `AES256CBC*::iv`
What changed, and why it matters
This change makes the encryption initialization vector (IV) used by Bitcoin Core's AES-256-CBC routines live in locked, non-swappable memory and be securely erased when no longer needed. Previously the IV was a normal stack-like array, which could potentially be swapped to disk or remain in memory after use. The IV is not a secret key, but it is cryptographic material that should be handled carefully. The patch is a hardening improvement rather than a fix for a known active attack.
Treat as a low-risk hardening patch. Review that `secure_allocator` is correctly implemented on all supported platforms and that the allocation/deallocation paths cannot throw in destructors. No urgent deployment is required, but include in normal release cycle.
Security signals we found
Use of secure_allocator for cryptographic material
Removal of explicit memset in favor of allocator zeroization
Memory-locking hardening for AES-CBC IV
No protocol or algorithmic change
Evidence from the diff
The commit replaces the fixed-size unsigned char iv[AES_BLOCKSIZE] member in AES256CBCEncrypt and AES256CBCDecrypt with a heap allocation via secure_allocator<unsigned char>. The secure allocator in Bitcoin Core typically uses LockedPageManager to prevent swapping and zeroes memory on deallocation. Constructors now call allocator.allocate(AES_BLOCKSIZE) and copy the supplied IV; destructors call allocator.deallocate(iv, AES_BLOCKSIZE) instead of memset(iv, 0, sizeof(iv)). This reduces the risk of IV material leaking to swap or lingering in freed heap memory. The change is defensive and does not alter the cryptographic protocol or fix a demonstrated exploit.
Changed components
src/crypto/aes.cppsrc/crypto/aes.hAES256CBCEncryptAES256CBCDecryptInspect captured patch +8 / −4
diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp
index 207a8e8a..cd2b4f76 100644
--- a/src/crypto/aes.cpp
+++ b/src/crypto/aes.cpp
@@ -124,6 +124,7 @@ static int CBCDecrypt(const T& dec, const unsigned char iv[AES_BLOCKSIZE], const
AES256CBCEncrypt::AES256CBCEncrypt(const unsigned char key[AES256_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn)
: enc(key), pad(padIn)
{
+ iv = allocator.allocate(AES_BLOCKSIZE);
memcpy(iv, ivIn, AES_BLOCKSIZE);
}
@@ -134,12 +135,13 @@ int AES256CBCEncrypt::Encrypt(const unsigned char* data, int size, unsigned char
AES256CBCEncrypt::~AES256CBCEncrypt()
{
- memset(iv, 0, sizeof(iv));
+ allocator.deallocate(iv, AES_BLOCKSIZE);
}
AES256CBCDecrypt::AES256CBCDecrypt(const unsigned char key[AES256_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn)
: dec(key), pad(padIn)
{
+ iv = allocator.allocate(AES_BLOCKSIZE);
memcpy(iv, ivIn, AES_BLOCKSIZE);
}
@@ -151,5 +153,5 @@ int AES256CBCDecrypt::Decrypt(const unsigned char* data, int size, unsigned char
AES256CBCDecrypt::~AES256CBCDecrypt()
{
- memset(iv, 0, sizeof(iv));
+ allocator.deallocate(iv, AES_BLOCKSIZE);
}
diff --git a/src/crypto/aes.h b/src/crypto/aes.h
index 191cffd9..617bb62d 100644
--- a/src/crypto/aes.h
+++ b/src/crypto/aes.h
@@ -49,9 +49,10 @@ public:
int Encrypt(const unsigned char* data, int size, unsigned char* out) const;
private:
+ secure_allocator<unsigned char> allocator;
const AES256Encrypt enc;
const bool pad;
- unsigned char iv[AES_BLOCKSIZE];
+ unsigned char *iv;
};
class AES256CBCDecrypt
@@ -62,9 +63,10 @@ public:
int Decrypt(const unsigned char* data, int size, unsigned char* out) const;
private:
+ secure_allocator<unsigned char> allocator;
const AES256Decrypt dec;
const bool pad;
- unsigned char iv[AES_BLOCKSIZE];
+ unsigned char *iv;
};
#endif // BITCOIN_CRYPTO_AES_H
Why this scored 43/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.