mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
Merge #16946: wallet: include a checksum of encrypted private keys
d67055e00dd90f504384e5c3f229fc95306d5aac Upgrade or rewrite encrypted key checksums (Andrew Chow) c9a9ddb4142af0af5f7b1a5ccd13f8e585007089 Set fDecryptionThoroughlyChecked based on whether crypted key checksums are valid (Andrew Chow) a8334f7ac39532528c5f8bd3b0eea05aa63e8794 Read and write a checksum for encrypted keys (Andrew Chow) Pull request description: Adds a checksum to the encrypted key record in the wallet database so that encrypted keys can be checked for corruption on wallet loading, in the same way that unencrypted keys are. This allows for us to skip the full decryption of keys upon the first unlocking of the wallet in that session as any key corruption will have already been detected. The checksum is just the double SHA256 of the encrypted key and it is appended to the record after the encrypted key itself. This is backwards compatible as old wallets will be able to read the encrypted key and ignore that there is more data in the stream. Additionally, old wallets will be upgraded upon their first unlocking (so that key decryption is checked before we commit to a checksum of the encrypted key) and a wallet flag set indicating that. The presence of the wallet flag lets us skip the full decryption as if `fDecryptionThoroughlyChecked` were true. This does mean that the first time an old wallet is unlocked in a new version will take much longer, but subsequent unlocks will be instantaneous. Furthermore, corruption will be detected upon loading rather than on trying to send so wallet corruption will be detected sooner. Fixes #12423 ACKs for top commit: laanwj: code review ACK d67055e00dd90f504384e5c3f229fc95306d5aac jonatack: Code review ACK d67055e00dd90f504384e5c3f229fc95306d5aac meshcollider: Code review ACK d67055e00dd90f504384e5c3f229fc95306d5aac Tree-SHA512: d5c1c10cfcb5db9e10dcf2326423565a9f499290b81f3155ec72254ed5bd7491e2ff5c50e98590eb07842c20d7797b4efa1c3475bae64971d500aad3b4e711d4
This commit is contained in:
parent
2c5cb249be
commit
c0c00f9295
@ -193,6 +193,7 @@ bool LegacyScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key
|
||||
bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
|
||||
bool keyFail = false;
|
||||
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
|
||||
WalletBatch batch(m_storage.GetDatabase());
|
||||
for (; mi != mapCryptedKeys.end(); ++mi)
|
||||
{
|
||||
const CPubKey &vchPubKey = (*mi).second.first;
|
||||
@ -206,6 +207,10 @@ bool LegacyScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key
|
||||
keyPass = true;
|
||||
if (fDecryptionThoroughlyChecked)
|
||||
break;
|
||||
else {
|
||||
// Rewrite these encrypted keys with checksums
|
||||
batch.WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]);
|
||||
}
|
||||
}
|
||||
if (keyPass && keyFail)
|
||||
{
|
||||
@ -923,8 +928,13 @@ bool LegacyScriptPubKeyMan::GetPubKeyInner(const CKeyID &address, CPubKey& vchPu
|
||||
return GetWatchPubKey(address, vchPubKeyOut);
|
||||
}
|
||||
|
||||
bool LegacyScriptPubKeyMan::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
|
||||
bool LegacyScriptPubKeyMan::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, bool checksum_valid)
|
||||
{
|
||||
// Set fDecryptionThoroughlyChecked to false when the checksum is invalid
|
||||
if (!checksum_valid) {
|
||||
fDecryptionThoroughlyChecked = false;
|
||||
}
|
||||
|
||||
return AddCryptedKeyInner(vchPubKey, vchCryptedSecret);
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProv
|
||||
{
|
||||
private:
|
||||
//! keeps track of whether Unlock has run a thorough check before
|
||||
bool fDecryptionThoroughlyChecked = false;
|
||||
bool fDecryptionThoroughlyChecked = true;
|
||||
|
||||
using WatchOnlySet = std::set<CScript>;
|
||||
using WatchKeyMap = std::map<CKeyID, CPubKey>;
|
||||
@ -371,7 +371,7 @@ public:
|
||||
//! Adds an encrypted key to the store, and saves it to disk.
|
||||
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)
|
||||
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, bool checksum_valid);
|
||||
void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
|
||||
//! Adds a CScript to the store
|
||||
bool LoadCScript(const CScript& redeemScript);
|
||||
|
@ -124,8 +124,19 @@ bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WriteIC(std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey), vchCryptedSecret, false)) {
|
||||
return false;
|
||||
// Compute a checksum of the encrypted key
|
||||
uint256 checksum = Hash(vchCryptedSecret.begin(), vchCryptedSecret.end());
|
||||
|
||||
const auto key = std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey);
|
||||
if (!WriteIC(key, std::make_pair(vchCryptedSecret, checksum), false)) {
|
||||
// It may already exist, so try writing just the checksum
|
||||
std::vector<unsigned char> val;
|
||||
if (!m_batch->Read(key, val)) {
|
||||
return false;
|
||||
}
|
||||
if (!WriteIC(key, std::make_pair(val, checksum), true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EraseIC(std::make_pair(DBKeys::KEY, vchPubKey));
|
||||
return true;
|
||||
@ -371,9 +382,21 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
}
|
||||
std::vector<unsigned char> vchPrivKey;
|
||||
ssValue >> vchPrivKey;
|
||||
|
||||
// Get the checksum and check it
|
||||
bool checksum_valid = false;
|
||||
if (!ssValue.eof()) {
|
||||
uint256 checksum;
|
||||
ssValue >> checksum;
|
||||
if ((checksum_valid = Hash(vchPrivKey.begin(), vchPrivKey.end()) != checksum)) {
|
||||
strErr = "Error reading wallet database: Crypted key corrupt";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
wss.nCKeys++;
|
||||
|
||||
if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCryptedKey(vchPubKey, vchPrivKey))
|
||||
if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCryptedKey(vchPubKey, vchPrivKey, checksum_valid))
|
||||
{
|
||||
strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCryptedKey failed";
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user