From 501a3dd4ad4a545a05663a78cec61575966045c7 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Fri, 6 Mar 2026 16:58:49 +0100 Subject: [PATCH] walletdb: hash pubkey/privkey in one shot to avoid leaking secret data Avoid storing the privkey in a vector, which could linger in memory and potentially leak sensitive data. An alternative approach is to use `secure_allocator` for the `std::vector` instances, but this commit has the advantage of also deduplicating code at the same shot. Thanks to @theuni for suggesting this. --- src/wallet/walletdb.cpp | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 4cb8c11ee95..6e6aab14742 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -117,12 +117,9 @@ bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, } // hash pubkey/privkey to accelerate wallet load - std::vector vchKey; - vchKey.reserve(vchPubKey.size() + vchPrivKey.size()); - vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); - vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end()); + const auto keypair_hash = Hash(vchPubKey, vchPrivKey); - return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey)), false); + return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, keypair_hash), false); } bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey, @@ -220,12 +217,9 @@ bool WalletBatch::EraseActiveScriptPubKeyMan(uint8_t type, bool internal) bool WalletBatch::WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey) { // hash pubkey/privkey to accelerate wallet load - std::vector key; - key.reserve(pubkey.size() + privkey.size()); - key.insert(key.end(), pubkey.begin(), pubkey.end()); - key.insert(key.end(), privkey.begin(), privkey.end()); + const auto keypair_hash = Hash(pubkey, privkey); - return WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)), std::make_pair(privkey, Hash(key)), false); + return WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)), std::make_pair(privkey, keypair_hash), false); } bool WalletBatch::WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector& secret) @@ -328,12 +322,9 @@ bool LoadKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::stri if (!hash.IsNull()) { // hash pubkey/privkey to accelerate wallet load - std::vector vchKey; - vchKey.reserve(vchPubKey.size() + pkey.size()); - vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); - vchKey.insert(vchKey.end(), pkey.begin(), pkey.end()); + const auto keypair_hash = Hash(vchPubKey, pkey); - if (Hash(vchKey) != hash) + if (keypair_hash != hash) { strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt"; return false; @@ -875,12 +866,9 @@ static DBErrors LoadDescriptorWalletRecords(CWallet* pwallet, DatabaseBatch& bat value >> hash; // hash pubkey/privkey to accelerate wallet load - std::vector to_hash; - to_hash.reserve(pubkey.size() + pkey.size()); - to_hash.insert(to_hash.end(), pubkey.begin(), pubkey.end()); - to_hash.insert(to_hash.end(), pkey.begin(), pkey.end()); + const auto keypair_hash = Hash(pubkey, pkey); - if (Hash(to_hash) != hash) + if (keypair_hash != hash) { strErr = "Error reading wallet database: descriptor unencrypted key CPubKey/CPrivKey corrupt"; return DBErrors::CORRUPT;