return false;
if (!fFileBacked)
return true;
- return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
+ CRITICAL_BLOCK(cs_pwalletdbEncryption)
+ {
+ if (pwalletdbEncryption)
+ return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
+ else
+ return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
+ }
}
bool CWallet::Unlock(const string& strWalletPassphrase)
return false;
if (CCryptoKeyStore::Unlock(vMasterKey))
{
+ int64 nStartTime = GetTimeMillis();
+ crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
+ pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
+
+ nStartTime = GetTimeMillis();
+ crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
+ pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
+
+ if (pMasterKey.second.nDeriveIterations < 25000)
+ pMasterKey.second.nDeriveIterations = 25000;
+
+ printf("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))
return false;
if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
return false;
}
+
+// This class implements an addrIncoming entry that causes pre-0.4
+// clients to crash on startup if reading a private-key-encrypted wallet.
+class CCorruptAddress
+{
+public:
+ IMPLEMENT_SERIALIZE
+ (
+ if (nType & SER_DISK)
+ READWRITE(nVersion);
+ )
+};
+
bool CWallet::EncryptWallet(const string& strWalletPassphrase)
{
- //TODO: use db commits
CRITICAL_BLOCK(cs_mapPubKeys)
CRITICAL_BLOCK(cs_KeyStore)
CRITICAL_BLOCK(cs_vMasterKey)
+ CRITICAL_BLOCK(cs_pwalletdbEncryption)
{
if (IsCrypted())
return false;
RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
CCrypter crypter;
+ int64 nStartTime = GetTimeMillis();
+ crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
+ kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
+
+ nStartTime = GetTimeMillis();
+ crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
+ kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
+
+ if (kMasterKey.nDeriveIterations < 25000)
+ kMasterKey.nDeriveIterations = 25000;
+
+ printf("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))
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked)
{
- DBFlush(false);
- CWalletDB(strWalletFile).WriteMasterKey(nMasterKeyMaxID, kMasterKey);
- DBFlush(false);
+ pwalletdbEncryption = new CWalletDB(strWalletFile);
+ pwalletdbEncryption->TxnBegin();
+ pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
}
if (!EncryptKeys(vMasterKey))
- exit(1); //We now probably have half of our keys encrypted, and half not...die and let the user ask someone with experience to recover their wallet.
+ {
+ if (fFileBacked)
+ pwalletdbEncryption->TxnAbort();
+ exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
+ }
+
+ if (fFileBacked)
+ {
+ CCorruptAddress corruptAddress;
+ pwalletdbEncryption->WriteSetting("addrIncoming", corruptAddress);
+ if (!pwalletdbEncryption->TxnCommit())
+ exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
+
+ pwalletdbEncryption->Close();
+ pwalletdbEncryption = NULL;
+ }
Lock();
}
int64 CWallet::GetBalance() const
{
- int64 nStart = GetTimeMillis();
-
int64 nTotal = 0;
CRITICAL_BLOCK(cs_mapWallet)
{
}
}
- //printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);
return nTotal;
}
-bool CWallet::LoadWallet(bool& fFirstRunRet)
+int CWallet::LoadWallet(bool& fFirstRunRet)
{
if (!fFileBacked)
return false;
fFirstRunRet = false;
- if (!CWalletDB(strWalletFile,"cr+").LoadWallet(this))
- return false;
+ int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
+ if (nLoadWalletRet != DB_LOAD_OK)
+ return nLoadWalletRet;
fFirstRunRet = vchDefaultKey.empty();
if (!HaveKey(vchDefaultKey))
SetDefaultKey(GetOrReuseKeyFromPool());
if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), ""))
- return false;
+ return DB_LOAD_FAIL;
}
CreateThread(ThreadFlushWalletDB, &strWalletFile);
- return true;
+ return DB_LOAD_OK;
}