From 1e21c17d208e310295475c0e4a46d750a5c9ba2d Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 6 Apr 2014 00:18:52 -0700 Subject: [PATCH 1/2] Make CCryptoKeyStore::Unlock check all keys. CCryptoKeyStore::Unlock has a loop to attempt decrypting each key which only executes once, likely due to a simple mistake when the code was originally written. This patch fixes the behavior by making it check all keys. It also adds a fatal assertion in the case some decrypt but some do not, since that indicates that the wallet is in some kind of really bad state. This may make unlocking noticeably slower on wallets with many keys. --- src/crypter.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/crypter.cpp b/src/crypter.cpp index 4c43e3a79..2f94e0827 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -152,6 +152,8 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) if (!SetCrypted()) return false; + bool keyPass = false; + bool keyFail = false; CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); for (; mi != mapCryptedKeys.end(); ++mi) { @@ -159,15 +161,31 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) const std::vector &vchCryptedSecret = (*mi).second.second; CKeyingMaterial vchSecret; if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) - return false; + { + keyFail = true; + break; + } if (vchSecret.size() != 32) - return false; + { + keyFail = true; + break; + } CKey key; key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); - if (key.GetPubKey() == vchPubKey) + if (key.GetPubKey() != vchPubKey) + { + keyFail = true; break; - return false; + } + keyPass = true; } + if (keyPass && keyFail) + { + LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all."); + assert(false); + } + if (keyFail || !keyPass) + return false; vMasterKey = vMasterKeyIn; } NotifyStatusChanged(this); From a35b55b522da8eeaed895f0ed43ba595fc083498 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sat, 9 Aug 2014 18:49:07 -0700 Subject: [PATCH 2/2] Dont run full check every time we decrypt wallet. --- src/crypter.cpp | 3 +++ src/crypter.h | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/crypter.cpp b/src/crypter.cpp index 2f94e0827..122e06d97 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -178,6 +178,8 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) break; } keyPass = true; + if (fDecryptionThoroughlyChecked) + break; } if (keyPass && keyFail) { @@ -187,6 +189,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) if (keyFail || !keyPass) return false; vMasterKey = vMasterKeyIn; + fDecryptionThoroughlyChecked = true; } NotifyStatusChanged(this); return true; diff --git a/src/crypter.h b/src/crypter.h index 4791428b4..f16fcef9c 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -121,6 +121,9 @@ private: // if fUseCrypto is false, vMasterKey must be empty bool fUseCrypto; + // keeps track of whether Unlock has run a thourough check before + bool fDecryptionThoroughlyChecked; + protected: bool SetCrypted(); @@ -130,7 +133,7 @@ protected: bool Unlock(const CKeyingMaterial& vMasterKeyIn); public: - CCryptoKeyStore() : fUseCrypto(false) + CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false) { }