mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-09 11:27:28 -03:00
Merge bda3a48190
into 66aa6a47bd
This commit is contained in:
commit
3a49618fc5
2 changed files with 76 additions and 65 deletions
|
@ -37,13 +37,16 @@ public:
|
|||
std::vector<unsigned char> vchCryptedKey;
|
||||
std::vector<unsigned char> vchSalt;
|
||||
//! 0 = EVP_sha512()
|
||||
//! 1 = scrypt()
|
||||
unsigned int nDerivationMethod;
|
||||
unsigned int nDeriveIterations;
|
||||
//! Use this for more parameters to key derivation,
|
||||
//! such as the various parameters to scrypt
|
||||
//! Use this for more parameters to key derivation (currently unused)
|
||||
std::vector<unsigned char> vchOtherDerivationParameters;
|
||||
|
||||
//! Default/minimum number of key derivation rounds
|
||||
// 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M
|
||||
// ie slightly lower than the lowest hardware we need bother supporting
|
||||
static constexpr int DEFAULT_DERIVE_ITERATIONS = 25000;
|
||||
|
||||
SERIALIZE_METHODS(CMasterKey, obj)
|
||||
{
|
||||
READWRITE(obj.vchCryptedKey, obj.vchSalt, obj.nDerivationMethod, obj.nDeriveIterations, obj.vchOtherDerivationParameters);
|
||||
|
@ -51,9 +54,7 @@ public:
|
|||
|
||||
CMasterKey()
|
||||
{
|
||||
// 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M
|
||||
// ie slightly lower than the lowest hardware we need bother supporting
|
||||
nDeriveIterations = 25000;
|
||||
nDeriveIterations = DEFAULT_DERIVE_ITERATIONS;
|
||||
nDerivationMethod = 0;
|
||||
vchOtherDerivationParameters = std::vector<unsigned char>(0);
|
||||
}
|
||||
|
|
|
@ -570,20 +570,60 @@ void CWallet::UpgradeDescriptorCache()
|
|||
SetWalletFlag(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED);
|
||||
}
|
||||
|
||||
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
|
||||
/* Given a wallet passphrase string and an unencrypted master key, determine the proper key
|
||||
* derivation parameters (should take at least 100ms) and encrypt the master key. */
|
||||
static bool EncryptMasterKey(const SecureString& wallet_passphrase, const CKeyingMaterial& plain_master_key, CMasterKey& master_key)
|
||||
{
|
||||
constexpr MillisecondsDouble target{100};
|
||||
auto start{SteadyClock::now()};
|
||||
CCrypter crypter;
|
||||
|
||||
crypter.SetKeyFromPassphrase(wallet_passphrase, master_key.vchSalt, master_key.nDeriveIterations, master_key.nDerivationMethod);
|
||||
master_key.nDeriveIterations = static_cast<unsigned int>(master_key.nDeriveIterations * target / (SteadyClock::now() - start));
|
||||
|
||||
start = SteadyClock::now();
|
||||
crypter.SetKeyFromPassphrase(wallet_passphrase, master_key.vchSalt, master_key.nDeriveIterations, master_key.nDerivationMethod);
|
||||
master_key.nDeriveIterations = (master_key.nDeriveIterations + static_cast<unsigned int>(master_key.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
|
||||
|
||||
if (master_key.nDeriveIterations < CMasterKey::DEFAULT_DERIVE_ITERATIONS) {
|
||||
master_key.nDeriveIterations = CMasterKey::DEFAULT_DERIVE_ITERATIONS;
|
||||
}
|
||||
|
||||
if (!crypter.SetKeyFromPassphrase(wallet_passphrase, master_key.vchSalt, master_key.nDeriveIterations, master_key.nDerivationMethod)) {
|
||||
return false;
|
||||
}
|
||||
if (!crypter.Encrypt(plain_master_key, master_key.vchCryptedKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool DecryptMasterKey(const SecureString& wallet_passphrase, const CMasterKey& master_key, CKeyingMaterial& plain_master_key)
|
||||
{
|
||||
CCrypter crypter;
|
||||
CKeyingMaterial _vMasterKey;
|
||||
if (!crypter.SetKeyFromPassphrase(wallet_passphrase, master_key.vchSalt, master_key.nDeriveIterations, master_key.nDerivationMethod)) {
|
||||
return false;
|
||||
}
|
||||
if (!crypter.Decrypt(master_key.vchCryptedKey, plain_master_key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
|
||||
{
|
||||
CKeyingMaterial plain_master_key;
|
||||
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
for (const MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
|
||||
for (const auto& [_, master_key] : mapMasterKeys)
|
||||
{
|
||||
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
|
||||
return false;
|
||||
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
|
||||
if (!DecryptMasterKey(strWalletPassphrase, master_key, plain_master_key)) {
|
||||
continue; // try another master key
|
||||
if (Unlock(_vMasterKey)) {
|
||||
}
|
||||
if (Unlock(plain_master_key)) {
|
||||
// Now that we've unlocked, upgrade the key metadata
|
||||
UpgradeKeyMetadata();
|
||||
// Now that we've unlocked, upgrade the descriptor cache
|
||||
|
@ -603,35 +643,20 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
|
|||
LOCK2(m_relock_mutex, cs_wallet);
|
||||
Lock();
|
||||
|
||||
CCrypter crypter;
|
||||
CKeyingMaterial _vMasterKey;
|
||||
for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
|
||||
CKeyingMaterial plain_master_key;
|
||||
for (auto& [master_key_id, master_key] : mapMasterKeys)
|
||||
{
|
||||
if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
|
||||
if (!DecryptMasterKey(strOldWalletPassphrase, master_key, plain_master_key)) {
|
||||
return false;
|
||||
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
|
||||
return false;
|
||||
if (Unlock(_vMasterKey))
|
||||
}
|
||||
if (Unlock(plain_master_key))
|
||||
{
|
||||
constexpr MillisecondsDouble target{100};
|
||||
auto start{SteadyClock::now()};
|
||||
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
|
||||
pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start));
|
||||
|
||||
start = SteadyClock::now();
|
||||
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
|
||||
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
|
||||
|
||||
if (pMasterKey.second.nDeriveIterations < 25000)
|
||||
pMasterKey.second.nDeriveIterations = 25000;
|
||||
|
||||
WalletLogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
|
||||
|
||||
if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
|
||||
if (!EncryptMasterKey(strNewWalletPassphrase, plain_master_key, master_key)) {
|
||||
return false;
|
||||
if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))
|
||||
return false;
|
||||
WalletBatch(GetDatabase()).WriteMasterKey(pMasterKey.first, pMasterKey.second);
|
||||
}
|
||||
WalletLogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", master_key.nDeriveIterations);
|
||||
|
||||
WalletBatch(GetDatabase()).WriteMasterKey(master_key_id, master_key);
|
||||
if (fWasLocked)
|
||||
Lock();
|
||||
return true;
|
||||
|
@ -806,50 +831,35 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
|
|||
if (IsCrypted())
|
||||
return false;
|
||||
|
||||
CKeyingMaterial _vMasterKey;
|
||||
CKeyingMaterial plain_master_key;
|
||||
|
||||
_vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
|
||||
GetStrongRandBytes(_vMasterKey);
|
||||
plain_master_key.resize(WALLET_CRYPTO_KEY_SIZE);
|
||||
GetStrongRandBytes(plain_master_key);
|
||||
|
||||
CMasterKey kMasterKey;
|
||||
CMasterKey master_key;
|
||||
|
||||
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
|
||||
GetStrongRandBytes(kMasterKey.vchSalt);
|
||||
master_key.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
|
||||
GetStrongRandBytes(master_key.vchSalt);
|
||||
|
||||
CCrypter crypter;
|
||||
constexpr MillisecondsDouble target{100};
|
||||
auto start{SteadyClock::now()};
|
||||
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
|
||||
kMasterKey.nDeriveIterations = static_cast<unsigned int>(25000 * target / (SteadyClock::now() - start));
|
||||
|
||||
start = SteadyClock::now();
|
||||
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
|
||||
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
|
||||
|
||||
if (kMasterKey.nDeriveIterations < 25000)
|
||||
kMasterKey.nDeriveIterations = 25000;
|
||||
|
||||
WalletLogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
|
||||
|
||||
if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
|
||||
return false;
|
||||
if (!crypter.Encrypt(_vMasterKey, kMasterKey.vchCryptedKey))
|
||||
if (!EncryptMasterKey(strWalletPassphrase, plain_master_key, master_key)) {
|
||||
return false;
|
||||
}
|
||||
WalletLogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", master_key.nDeriveIterations);
|
||||
|
||||
{
|
||||
LOCK2(m_relock_mutex, cs_wallet);
|
||||
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
|
||||
mapMasterKeys[++nMasterKeyMaxID] = master_key;
|
||||
WalletBatch* encrypted_batch = new WalletBatch(GetDatabase());
|
||||
if (!encrypted_batch->TxnBegin()) {
|
||||
delete encrypted_batch;
|
||||
encrypted_batch = nullptr;
|
||||
return false;
|
||||
}
|
||||
encrypted_batch->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
|
||||
encrypted_batch->WriteMasterKey(nMasterKeyMaxID, master_key);
|
||||
|
||||
for (const auto& spk_man_pair : m_spk_managers) {
|
||||
auto spk_man = spk_man_pair.second.get();
|
||||
if (!spk_man->Encrypt(_vMasterKey, encrypted_batch)) {
|
||||
if (!spk_man->Encrypt(plain_master_key, encrypted_batch)) {
|
||||
encrypted_batch->TxnAbort();
|
||||
delete encrypted_batch;
|
||||
encrypted_batch = nullptr;
|
||||
|
|
Loading…
Reference in a new issue