Remove CCryptoKeyStore and move all of it's functionality into CWallet

Instead of having a separate CCryptoKeyStore that handles the encryption
stuff, just roll it all into CWallet.
This commit is contained in:
Andrew Chow 2019-06-06 23:58:21 +02:00
parent 37a79a4fcc
commit 8f5b81e6ed
5 changed files with 247 additions and 256 deletions

View File

@ -476,7 +476,7 @@ public:
} }
std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override
{ {
return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CCryptoKeyStore*) { fn(); })); return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); }));
} }
std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override
{ {

View File

@ -107,8 +107,7 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
return true; return true;
} }
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{ {
CCrypter cKeyCrypter; CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE); std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
@ -118,7 +117,7 @@ static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMateri
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext); return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
} }
static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext) bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
{ {
CCrypter cKeyCrypter; CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE); std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
@ -128,7 +127,7 @@ static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<u
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext)); return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
} }
static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key) bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
{ {
CKeyingMaterial vchSecret; CKeyingMaterial vchSecret;
if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
@ -140,188 +139,3 @@ static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsi
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
return key.VerifyPubKey(vchPubKey); return key.VerifyPubKey(vchPubKey);
} }
bool CCryptoKeyStore::SetCrypted()
{
LOCK(cs_KeyStore);
if (fUseCrypto)
return true;
if (!mapKeys.empty())
return false;
fUseCrypto = true;
return true;
}
bool CCryptoKeyStore::IsLocked() const
{
if (!IsCrypted()) {
return false;
}
LOCK(cs_KeyStore);
return vMasterKey.empty();
}
bool CCryptoKeyStore::Lock()
{
if (!SetCrypted())
return false;
{
LOCK(cs_KeyStore);
vMasterKey.clear();
}
NotifyStatusChanged(this);
return true;
}
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
{
{
LOCK(cs_KeyStore);
if (!SetCrypted())
return false;
bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
bool keyFail = false;
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
for (; mi != mapCryptedKeys.end(); ++mi)
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CKey key;
if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
{
keyFail = true;
break;
}
keyPass = true;
if (fDecryptionThoroughlyChecked)
break;
}
if (keyPass && keyFail)
{
LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
}
if (keyFail || (!keyPass && !accept_no_keys))
return false;
vMasterKey = vMasterKeyIn;
fDecryptionThoroughlyChecked = true;
}
NotifyStatusChanged(this);
return true;
}
bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::AddKeyPubKey(key, pubkey);
}
if (IsLocked()) {
return false;
}
std::vector<unsigned char> vchCryptedSecret;
CKeyingMaterial vchSecret(key.begin(), key.end());
if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
return false;
}
if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
return false;
}
return true;
}
bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
LOCK(cs_KeyStore);
if (!SetCrypted()) {
return false;
}
mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
ImplicitlyLearnRelatedKeyScripts(vchPubKey);
return true;
}
bool CCryptoKeyStore::HaveKey(const CKeyID &address) const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::HaveKey(address);
}
return mapCryptedKeys.count(address) > 0;
}
bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::GetKey(address, keyOut);
}
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
}
return false;
}
bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
LOCK(cs_KeyStore);
if (!IsCrypted())
return FillableSigningProvider::GetPubKey(address, vchPubKeyOut);
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
vchPubKeyOut = (*mi).second.first;
return true;
}
// Check for watch-only pubkeys
return FillableSigningProvider::GetPubKey(address, vchPubKeyOut);
}
std::set<CKeyID> CCryptoKeyStore::GetKeys() const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::GetKeys();
}
std::set<CKeyID> set_address;
for (const auto& mi : mapCryptedKeys) {
set_address.insert(mi.first);
}
return set_address;
}
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
LOCK(cs_KeyStore);
if (!mapCryptedKeys.empty() || IsCrypted())
return false;
fUseCrypto = true;
for (const KeyMap::value_type& mKey : mapKeys)
{
const CKey &key = mKey.second;
CPubKey vchPubKey = key.GetPubKey();
CKeyingMaterial vchSecret(key.begin(), key.end());
std::vector<unsigned char> vchCryptedSecret;
if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
return false;
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
}
mapKeys.clear();
return true;
}

View File

@ -11,8 +11,6 @@
#include <atomic> #include <atomic>
#include <boost/signals2/signal.hpp>
const unsigned int WALLET_CRYPTO_KEY_SIZE = 32; const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
const unsigned int WALLET_CRYPTO_SALT_SIZE = 8; const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
const unsigned int WALLET_CRYPTO_IV_SIZE = 16; const unsigned int WALLET_CRYPTO_IV_SIZE = 16;
@ -111,54 +109,8 @@ public:
} }
}; };
/** Keystore which keeps the private keys encrypted. bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
* It derives from the basic key store, which is used if no encryption is active. bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
*/ bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key);
class CCryptoKeyStore : public FillableSigningProvider
{
private:
CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore);
//! if fUseCrypto is true, mapKeys must be empty
//! if fUseCrypto is false, vMasterKey must be empty
std::atomic<bool> fUseCrypto;
//! keeps track of whether Unlock has run a thorough check before
bool fDecryptionThoroughlyChecked;
protected:
using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
bool SetCrypted();
//! will encrypt previously unencrypted keys
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false);
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
public:
CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)
{
}
bool IsCrypted() const { return fUseCrypto; }
bool IsLocked() const;
bool Lock();
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
bool HaveKey(const CKeyID &address) const override;
bool GetKey(const CKeyID &address, CKey& keyOut) const override;
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
std::set<CKeyID> GetKeys() const override;
/**
* Wallet status (encrypted, locked) changed.
* Note: Called without locks held.
*/
boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
};
#endif // BITCOIN_WALLET_CRYPTER_H #endif // BITCOIN_WALLET_CRYPTER_H

View File

@ -294,14 +294,14 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& secret, const C
// Make sure we aren't adding private keys to private key disabled wallets // Make sure we aren't adding private keys to private key disabled wallets
assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
// CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey // FillableSigningProvider has no concept of wallet databases, but calls AddCryptedKey
// which is overridden below. To avoid flushes, the database handle is // which is overridden below. To avoid flushes, the database handle is
// tunneled through to it. // tunneled through to it.
bool needsDB = !encrypted_batch; bool needsDB = !encrypted_batch;
if (needsDB) { if (needsDB) {
encrypted_batch = &batch; encrypted_batch = &batch;
} }
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) { if (!AddKeyPubKeyInner(secret, pubkey)) {
if (needsDB) encrypted_batch = nullptr; if (needsDB) encrypted_batch = nullptr;
return false; return false;
} }
@ -336,7 +336,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
const std::vector<unsigned char> &vchCryptedSecret) const std::vector<unsigned char> &vchCryptedSecret)
{ {
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) if (!AddCryptedKeyInner(vchPubKey, vchCryptedSecret))
return false; return false;
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
@ -404,7 +404,7 @@ void CWallet::UpgradeKeyMetadata()
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{ {
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); return AddCryptedKeyInner(vchPubKey, vchCryptedSecret);
} }
/** /**
@ -431,7 +431,7 @@ bool CWallet::AddCScript(const CScript& redeemScript)
bool CWallet::AddCScriptWithDB(WalletBatch& batch, const CScript& redeemScript) bool CWallet::AddCScriptWithDB(WalletBatch& batch, const CScript& redeemScript)
{ {
if (!CCryptoKeyStore::AddCScript(redeemScript)) if (!FillableSigningProvider::AddCScript(redeemScript))
return false; return false;
if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) { if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) {
UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET); UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET);
@ -452,12 +452,12 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
return true; return true;
} }
return CCryptoKeyStore::AddCScript(redeemScript); return FillableSigningProvider::AddCScript(redeemScript);
} }
bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest)
{ {
if (!CCryptoKeyStore::AddWatchOnly(dest)) if (!FillableSigningProvider::AddWatchOnly(dest))
return false; return false;
const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)]; const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)];
UpdateTimeFirstKey(meta.nCreateTime); UpdateTimeFirstKey(meta.nCreateTime);
@ -490,7 +490,7 @@ bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
bool CWallet::RemoveWatchOnly(const CScript &dest) bool CWallet::RemoveWatchOnly(const CScript &dest)
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
if (!CCryptoKeyStore::RemoveWatchOnly(dest)) if (!FillableSigningProvider::RemoveWatchOnly(dest))
return false; return false;
if (!HaveWatchOnly()) if (!HaveWatchOnly())
NotifyWatchonlyChanged(false); NotifyWatchonlyChanged(false);
@ -502,7 +502,7 @@ bool CWallet::RemoveWatchOnly(const CScript &dest)
bool CWallet::LoadWatchOnly(const CScript &dest) bool CWallet::LoadWatchOnly(const CScript &dest)
{ {
return CCryptoKeyStore::AddWatchOnly(dest); return FillableSigningProvider::AddWatchOnly(dest);
} }
bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys) bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys)
@ -518,7 +518,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_key
return false; return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
continue; // try another master key continue; // try another master key
if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys)) { if (Unlock(_vMasterKey, accept_no_keys)) {
// Now that we've unlocked, upgrade the key metadata // Now that we've unlocked, upgrade the key metadata
UpgradeKeyMetadata(); UpgradeKeyMetadata();
return true; return true;
@ -544,7 +544,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
return false; return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
return false; return false;
if (CCryptoKeyStore::Unlock(_vMasterKey)) if (Unlock(_vMasterKey))
{ {
int64_t nStartTime = GetTimeMillis(); int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
@ -4588,3 +4588,188 @@ bool CWallet::AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, cons
mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path); mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path);
return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true); return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true);
} }
bool CWallet::SetCrypted()
{
LOCK(cs_KeyStore);
if (fUseCrypto)
return true;
if (!mapKeys.empty())
return false;
fUseCrypto = true;
return true;
}
bool CWallet::IsLocked() const
{
if (!IsCrypted()) {
return false;
}
LOCK(cs_KeyStore);
return vMasterKey.empty();
}
bool CWallet::Lock()
{
if (!SetCrypted())
return false;
{
LOCK(cs_KeyStore);
vMasterKey.clear();
}
NotifyStatusChanged(this);
return true;
}
bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
{
{
LOCK(cs_KeyStore);
if (!SetCrypted())
return false;
bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
bool keyFail = false;
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
for (; mi != mapCryptedKeys.end(); ++mi)
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CKey key;
if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
{
keyFail = true;
break;
}
keyPass = true;
if (fDecryptionThoroughlyChecked)
break;
}
if (keyPass && keyFail)
{
LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
}
if (keyFail || (!keyPass && !accept_no_keys))
return false;
vMasterKey = vMasterKeyIn;
fDecryptionThoroughlyChecked = true;
}
NotifyStatusChanged(this);
return true;
}
bool CWallet::HaveKey(const CKeyID &address) const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::HaveKey(address);
}
return mapCryptedKeys.count(address) > 0;
}
bool CWallet::GetKey(const CKeyID &address, CKey& keyOut) const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::GetKey(address, keyOut);
}
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
}
return false;
}
bool CWallet::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
LOCK(cs_KeyStore);
if (!IsCrypted())
return FillableSigningProvider::GetPubKey(address, vchPubKeyOut);
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
vchPubKeyOut = (*mi).second.first;
return true;
}
// Check for watch-only pubkeys
return FillableSigningProvider::GetPubKey(address, vchPubKeyOut);
}
std::set<CKeyID> CWallet::GetKeys() const
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::GetKeys();
}
std::set<CKeyID> set_address;
for (const auto& mi : mapCryptedKeys) {
set_address.insert(mi.first);
}
return set_address;
}
bool CWallet::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
LOCK(cs_KeyStore);
if (!mapCryptedKeys.empty() || IsCrypted())
return false;
fUseCrypto = true;
for (const KeyMap::value_type& mKey : mapKeys)
{
const CKey &key = mKey.second;
CPubKey vchPubKey = key.GetPubKey();
CKeyingMaterial vchSecret(key.begin(), key.end());
std::vector<unsigned char> vchCryptedSecret;
if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
return false;
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
}
mapKeys.clear();
return true;
}
bool CWallet::AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey)
{
LOCK(cs_KeyStore);
if (!IsCrypted()) {
return FillableSigningProvider::AddKeyPubKey(key, pubkey);
}
if (IsLocked()) {
return false;
}
std::vector<unsigned char> vchCryptedSecret;
CKeyingMaterial vchSecret(key.begin(), key.end());
if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
return false;
}
if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
return false;
}
return true;
}
bool CWallet::AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
LOCK(cs_KeyStore);
if (!SetCrypted()) {
return false;
}
mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
ImplicitlyLearnRelatedKeyScripts(vchPubKey);
return true;
}

View File

@ -35,6 +35,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/signals2/signal.hpp>
//! Explicitly unload and delete the wallet. //! Explicitly unload and delete the wallet.
//! Blocks the current thread after signaling the unload intent so that all //! Blocks the current thread after signaling the unload intent so that all
//! wallet clients release the wallet. //! wallet clients release the wallet.
@ -709,9 +711,31 @@ class WalletRescanReserver; //forward declarations for ScanForWalletTransactions
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, * A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions. * and provides the ability to create new transactions.
*/ */
class CWallet final : public CCryptoKeyStore, private interfaces::Chain::Notifications class CWallet final : public FillableSigningProvider, private interfaces::Chain::Notifications
{ {
private: private:
CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore);
//! if fUseCrypto is true, mapKeys must be empty
//! if fUseCrypto is false, vMasterKey must be empty
std::atomic<bool> fUseCrypto;
//! keeps track of whether Unlock has run a thorough check before
bool fDecryptionThoroughlyChecked;
using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
bool SetCrypted();
//! will encrypt previously unencrypted keys
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false);
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey);
std::atomic<bool> fAbortRescan{false}; std::atomic<bool> fAbortRescan{false};
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
std::atomic<int64_t> m_scanning_start{0}; std::atomic<int64_t> m_scanning_start{0};
@ -879,7 +903,9 @@ public:
/** Construct wallet with specified name and database implementation. */ /** Construct wallet with specified name and database implementation. */
CWallet(interfaces::Chain* chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database) CWallet(interfaces::Chain* chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database)
: m_chain(chain), : fUseCrypto(false),
fDecryptionThoroughlyChecked(false),
m_chain(chain),
m_location(location), m_location(location),
database(std::move(database)) database(std::move(database))
{ {
@ -893,6 +919,10 @@ public:
encrypted_batch = nullptr; encrypted_batch = nullptr;
} }
bool IsCrypted() const { return fUseCrypto; }
bool IsLocked() const;
bool Lock();
std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet); std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet);
typedef std::multimap<int64_t, CWalletTx*> TxItems; typedef std::multimap<int64_t, CWalletTx*> TxItems;
@ -975,7 +1005,7 @@ public:
//! Adds a key to the store, and saves it to disk. //! Adds a key to the store, and saves it to disk.
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a key to the store, without saving it to disk (used by LoadWallet) //! Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } bool LoadKey(const CKey& key, const CPubKey &pubkey) { return AddKeyPubKeyInner(key, pubkey); }
//! Load metadata (used by LoadWallet) //! Load metadata (used by LoadWallet)
void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@ -986,9 +1016,13 @@ public:
void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds an encrypted key to the store, and saves it to disk. //! Adds an encrypted key to the store, and saves it to disk.
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) override; bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
//! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool GetKey(const CKeyID &address, CKey& keyOut) const override;
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
bool HaveKey(const CKeyID &address) const override;
std::set<CKeyID> GetKeys() const override;
bool AddCScript(const CScript& redeemScript) override; bool AddCScript(const CScript& redeemScript) override;
bool LoadCScript(const CScript& redeemScript); bool LoadCScript(const CScript& redeemScript);
@ -1232,6 +1266,12 @@ public:
/** Keypool has new keys */ /** Keypool has new keys */
boost::signals2::signal<void ()> NotifyCanGetAddressesChanged; boost::signals2::signal<void ()> NotifyCanGetAddressesChanged;
/**
* Wallet status (encrypted, locked) changed.
* Note: Called without locks held.
*/
boost::signals2::signal<void (CWallet* wallet)> NotifyStatusChanged;
/** Inquire whether this wallet broadcasts transactions. */ /** Inquire whether this wallet broadcasts transactions. */
bool GetBroadcastTransactions() const { return fBroadcastTransactions; } bool GetBroadcastTransactions() const { return fBroadcastTransactions; }
/** Set whether this wallet broadcasts transactions. */ /** Set whether this wallet broadcasts transactions. */