Merge pull request #352 from TheBlueMatt/newenc

Wallet Private Key Encryption (on CWallet)
This commit is contained in:
Jeff Garzik
2011-07-12 19:10:12 -07:00
24 changed files with 1589 additions and 161 deletions

View File

@@ -245,6 +245,41 @@ void SetDefaultReceivingAddress(const string& strAddress)
}
}
bool GetWalletPassphrase()
{
if (pwalletMain->IsLocked())
{
string strWalletPass;
strWalletPass.reserve(100);
mlock(&strWalletPass[0], strWalletPass.capacity());
// obtain current wallet encrypt/decrypt key, from passphrase
// Note that the passphrase is not mlock()d during this entry and could potentially
// be obtained from disk long after bitcoin has run.
strWalletPass = wxGetPasswordFromUser(_("Enter the current passphrase to the wallet."),
_("Passphrase")).ToStdString();
if (!strWalletPass.size())
{
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
wxMessageBox(_("Please supply the current wallet decryption passphrase."), "Bitcoin");
return false;
}
if (!pwalletMain->Unlock(strWalletPass))
{
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin");
return false;
}
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
}
return true;
}
@@ -333,6 +368,11 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
if (CWalletDB(pwalletMain->strWalletFile,"r").ReadDefaultKey(vchPubKey))
m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
if (pwalletMain->IsCrypted())
m_menuOptions->Remove(m_menuOptionsEncryptWallet);
else
m_menuOptions->Remove(m_menuOptionsChangeWalletPassphrase);
// Fill listctrl with wallet transactions
RefreshListCtrl();
}
@@ -1122,6 +1162,169 @@ void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
return;
}
void CMainFrame::OnMenuOptionsEncryptWallet(wxCommandEvent& event)
{
// Options->Encrypt Wallet
if (pwalletMain->IsCrypted())
{
wxMessageBox(_("Wallet already encrypted."), "Bitcoin", wxOK | wxICON_ERROR);
return;
}
string strWalletPass;
strWalletPass.reserve(100);
mlock(&strWalletPass[0], strWalletPass.capacity());
// obtain current wallet encrypt/decrypt key, from passphrase
// Note that the passphrase is not mlock()d during this entry and could potentially
// be obtained from disk long after bitcoin has run.
strWalletPass = wxGetPasswordFromUser(_("Enter the new passphrase to the wallet.\nPlease use a passphrase of 10 or more random characters, or eight or more words."),
_("Passphrase")).ToStdString();
if (!strWalletPass.size())
{
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
wxMessageBox(_("Error: The supplied passphrase was too short."), "Bitcoin", wxOK | wxICON_ERROR);
return;
}
if(wxMessageBox(_("WARNING: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR BITCOINS!\nAre you sure you wish to encrypt your wallet?"), "Bitcoin", wxYES_NO) != wxYES)
return;
string strWalletPassTest;
strWalletPassTest.reserve(100);
mlock(&strWalletPassTest[0], strWalletPassTest.capacity());
strWalletPassTest = wxGetPasswordFromUser(_("Please re-enter your new wallet passphrase."),
_("Passphrase")).ToStdString();
if (strWalletPassTest != strWalletPass)
{
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
fill(strWalletPassTest.begin(), strWalletPassTest.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
munlock(&strWalletPassTest[0], strWalletPassTest.capacity());
wxMessageBox(_("Error: the supplied passphrases didn't match."), "Bitcoin", wxOK | wxICON_ERROR);
return;
}
if (!pwalletMain->EncryptWallet(strWalletPass))
{
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
fill(strWalletPassTest.begin(), strWalletPassTest.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
munlock(&strWalletPassTest[0], strWalletPassTest.capacity());
wxMessageBox(_("Wallet encryption failed."), "Bitcoin", wxOK | wxICON_ERROR);
return;
}
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
fill(strWalletPassTest.begin(), strWalletPassTest.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
munlock(&strWalletPassTest[0], strWalletPassTest.capacity());
wxMessageBox(_("Wallet Encrypted.\nRemember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer."), "Bitcoin");
m_menuOptions->Remove(m_menuOptionsEncryptWallet);
m_menuOptions->Insert(m_menuOptions->GetMenuItemCount() - 1, m_menuOptionsChangeWalletPassphrase);
}
void CMainFrame::OnMenuOptionsChangeWalletPassphrase(wxCommandEvent& event)
{
// Options->Change Wallet Encryption Passphrase
if (!pwalletMain->IsCrypted())
{
wxMessageBox(_("Wallet is unencrypted, please encrypt it first."), "Bitcoin", wxOK | wxICON_ERROR);
return;
}
string strOldWalletPass;
strOldWalletPass.reserve(100);
mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
// obtain current wallet encrypt/decrypt key, from passphrase
// Note that the passphrase is not mlock()d during this entry and could potentially
// be obtained from disk long after bitcoin has run.
strOldWalletPass = wxGetPasswordFromUser(_("Enter the current passphrase to the wallet."),
_("Passphrase")).ToStdString();
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
bool fWasLocked = pwalletMain->IsLocked();
pwalletMain->Lock();
if (!strOldWalletPass.size() || !pwalletMain->Unlock(strOldWalletPass))
{
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin", wxOK | wxICON_ERROR);
return;
}
if (fWasLocked)
pwalletMain->Lock();
string strNewWalletPass;
strNewWalletPass.reserve(100);
mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
// obtain new wallet encrypt/decrypt key, from passphrase
// Note that the passphrase is not mlock()d during this entry and could potentially
// be obtained from disk long after bitcoin has run.
strNewWalletPass = wxGetPasswordFromUser(_("Enter the new passphrase for the wallet."),
_("Passphrase")).ToStdString();
if (!strNewWalletPass.size())
{
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
wxMessageBox(_("Error: The supplied passphrase was too short."), "Bitcoin", wxOK | wxICON_ERROR);
return;
}
string strNewWalletPassTest;
strNewWalletPassTest.reserve(100);
mlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
// obtain new wallet encrypt/decrypt key, from passphrase
// Note that the passphrase is not mlock()d during this entry and could potentially
// be obtained from disk long after bitcoin has run.
strNewWalletPassTest = wxGetPasswordFromUser(_("Re-enter the new passphrase for the wallet."),
_("Passphrase")).ToStdString();
if (strNewWalletPassTest != strNewWalletPass)
{
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
wxMessageBox(_("Error: the supplied passphrases didn't match."), "Bitcoin", wxOK | wxICON_ERROR);
return;
}
if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
{
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin", wxOK | wxICON_ERROR);
return;
}
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
wxMessageBox(_("Wallet Passphrase Changed."), "Bitcoin");
}
}
void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
{
// Options->Options
@@ -1182,8 +1385,19 @@ void CMainFrame::OnButtonNew(wxCommandEvent& event)
return;
string strName = dialog.GetValue();
// Generate new key
string strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
string strAddress;
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
bool fWasLocked = pwalletMain->IsLocked();
if (!GetWalletPassphrase())
return;
// Generate new key
strAddress = PubKeyToAddress(pwalletMain->GetOrReuseKeyFromPool());
if (fWasLocked)
pwalletMain->Lock();
}
// Save
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
@@ -1947,7 +2161,12 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
if (fBitcoinAddress)
{
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
bool fWasLocked = pwalletMain->IsLocked();
if (!GetWalletPassphrase())
return;
// Send to bitcoin address
CScript scriptPubKey;
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
@@ -1956,13 +2175,22 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
if (strError == "")
wxMessageBox(_("Payment sent "), _("Sending..."));
else if (strError == "ABORTED")
{
if (fWasLocked)
pwalletMain->Lock();
return; // leave send dialog open
}
else
{
wxMessageBox(strError + " ", _("Sending..."));
EndModal(false);
if (fWasLocked)
pwalletMain->Lock();
return;
}
if (fWasLocked)
pwalletMain->Lock();
}
}
else
@@ -2246,16 +2474,27 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
Error(_("Insufficient funds"));
return;
}
CReserveKey reservekey(pwalletMain);
int64 nFeeRequired;
if (!pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired))
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if (nPrice + nFeeRequired > pwalletMain->GetBalance())
Error(strprintf(_("This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds"), FormatMoney(nFeeRequired).c_str()));
else
Error(_("Transaction creation failed"));
return;
}
bool fWasLocked = pwalletMain->IsLocked();
if (!GetWalletPassphrase())
return;
if (!pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired))
{
if (nPrice + nFeeRequired > pwalletMain->GetBalance())
Error(strprintf(_("This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds"), FormatMoney(nFeeRequired).c_str()));
else
Error(_("Transaction creation failed"));
return;
}
if (fWasLocked)
pwalletMain->Lock();
}
// Transaction fee
if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
@@ -2382,7 +2621,7 @@ CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInit
m_listCtrlReceiving->SetFocus();
// Fill listctrl with address book data
CRITICAL_BLOCK(pwalletMain->cs_mapKeys)
CRITICAL_BLOCK(pwalletMain->cs_KeyStore)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
@@ -2581,8 +2820,18 @@ void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
return;
strName = dialog.GetValue();
// Generate new key
strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
bool fWasLocked = pwalletMain->IsLocked();
if (!GetWalletPassphrase())
return;
// Generate new key
strAddress = PubKeyToAddress(pwalletMain->GetOrReuseKeyFromPool());
if (fWasLocked)
pwalletMain->Lock();
}
}
// Add to list and select it