mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 02:25:40 +01:00
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:
parent
37a79a4fcc
commit
8f5b81e6ed
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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. */
|
||||||
|
Loading…
Reference in New Issue
Block a user