This commit is contained in:
Wladimir J. van der Laan 2011-07-15 16:08:38 +02:00
commit d421117620
42 changed files with 2269 additions and 683 deletions

View File

@ -83,7 +83,8 @@ HEADERS += src/qt/bitcoingui.h \
src/bitcoinrpc.h \
src/qt/overviewpage.h \
src/qt/csvmodelwriter.h \
src/qt/qtwin.h
src/qt/qtwin.h \
src/crypter.h
SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/transactiontablemodel.cpp \
src/qt/addresstablemodel.cpp \
@ -122,7 +123,8 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/bitcoinrpc.cpp \
src/qt/overviewpage.cpp \
src/qt/csvmodelwriter.cpp \
src/qt/qtwin.cpp
src/qt/qtwin.cpp \
src/crypter.cpp
RESOURCES += \
src/qt/bitcoin.qrc

View File

@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.3.24</string>
<string>0.3.25</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>324</string>
<string>325</string>
<key>LSMinimumSystemVersion</key>
<string>10.5</string>
<key>CFBundleIconFile</key>

View File

@ -1,4 +1,4 @@
Bitcoin 0.3.24 BETA
Bitcoin 0.3.25 BETA
Copyright (c) 2009-2011 Bitcoin Developers
Distributed under the MIT/X11 software license, see the accompanying
@ -24,6 +24,49 @@ Unpack the files into a directory and run:
bin/64/bitcoin (GUI, 64-bit)
bin/64/bitcoind (headless, 64-bit)
Wallet Encryption
-----------------
Bitcoin supports native wallet encryption so that people who steal your
wallet file don't automatically get access to all of your Bitcoins.
In order to enable this feature, chose "Encrypt Wallet" from the
Options menu. You will be prompted to enter a passphrase, which
will be used as the key to encrypt your wallet and will be needed
every time you wish to send Bitcoins. If you lose this passphrase,
you will lose access to spend all of the bitcoins in your wallet,
no one, not even the Bitcoin developers can recover your Bitcoins.
This means you are responsible for your own security, store your
password in a secure location and do not forget it.
Remember that the encryption built into bitcoin only encrypts the
actual keys which are required to send your bitcoins, not the full
wallet. This means that someone who steals your wallet file will
be able to see all the addresses which belong to you, as well as the
relevant transactions, you are only protected from someone spending
your coins.
It is recommended that you backup your wallet file before you
encrypt your wallet. To do this, close the Bitcoin client and
copy the wallet.dat file from ~/.bitcoin/ on Linux, /Users/(user
name)/Application Support/Bitcoin/ on Mac OSX, and %APPDATA%/Bitcoin/
on Windows (that is /Users/(user name)/AppData/Roaming/Bitcoin on
Windows Vista and 7 and /Documents and Settings/(user name)/Application
Data/Bitcoin on Windows XP). Once you have copied that file to a
safe location, reopen the Bitcoin client and Encrypt your wallet.
If everything goes fine, delete the backup and enjoy your encrypted
wallet. Note that once you encrypt your wallet, you will never be
able to go back to a version of the Bitcoin client older than 0.4.
Keep in mind that you are always responsible for you own security.
All it takes is a slightly more advanced wallet-stealing trojan which
installs a keylogger to steal your wallet passphrase as you enter it
in addition to your wallet file and you have lost all your Bitcoins.
Wallet encryption cannot keep you safe if you do not practice
good security, such as running up-to-date antivirus software, only
entering your wallet passphrase in the Bitcoin client and using the
same passphrase only as your wallet passphrase.
See the documentation at the bitcoin wiki:
https://en.bitcoin.it/wiki/Main_Page

View File

@ -1,4 +1,4 @@
Bitcoin 0.3.24 BETA
Bitcoin 0.3.25 BETA
Copyright (c) 2009-2011 Bitcoin Developers
Distributed under the MIT/X11 software license, see the accompanying

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

View File

@ -1,15 +1,20 @@
Name Bitcoin
RequestExecutionLevel highest
SetCompressor /SOLID lzma
# General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)"
!define VERSION 0.3.24
!define VERSION 0.3.25
!define COMPANY "Bitcoin project"
!define URL http://www.bitcoin.org/
# MUI Symbol Definitions
!define MUI_ICON "../share/pixmaps/bitcoin.ico"
!define MUI_WELCOMEFINISHPAGE_BITMAP "../share/pixmaps/nsis-wizard.bmp"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_RIGHT
!define MUI_HEADERIMAGE_BITMAP "../share/pixmaps/nsis-header.bmp"
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM
!define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY}
@ -17,6 +22,7 @@ RequestExecutionLevel highest
!define MUI_STARTMENUPAGE_DEFAULTFOLDER Bitcoin
!define MUI_FINISHPAGE_RUN $INSTDIR\bitcoin.exe
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "../share/pixmaps/nsis-wizard.bmp"
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
# Included files
@ -39,12 +45,13 @@ Var StartMenuGroup
!insertmacro MUI_LANGUAGE English
# Installer attributes
OutFile bitcoin-0.3.24-win32-setup.exe
OutFile bitcoin-0.3.25-win32-setup.exe
InstallDir $PROGRAMFILES\Bitcoin
CRCCheck on
XPStyle on
BrandingText " "
ShowInstDetails show
VIProductVersion 0.3.24.0
VIProductVersion 0.3.25.0
VIAddVersionKey ProductName Bitcoin
VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}"

View File

@ -162,6 +162,36 @@
<event name="OnMenuSelection">OnMenuOptionsChangeYourAddress</event>
<event name="OnUpdateUI"></event>
</object>
<object class="wxMenuItem" expanded="1">
<property name="bitmap"></property>
<property name="checked">0</property>
<property name="enabled">1</property>
<property name="help"></property>
<property name="id">wxID_ANY</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">&amp;Encrypt Wallet...</property>
<property name="name">m_menuOptionsEncryptWallet</property>
<property name="permission">public</property>
<property name="shortcut"></property>
<property name="unchecked_bitmap"></property>
<event name="OnMenuSelection">OnMenuOptionsEncryptWallet</event>
<event name="OnUpdateUI"></event>
</object>
<object class="wxMenuItem" expanded="1">
<property name="bitmap"></property>
<property name="checked">0</property>
<property name="enabled">1</property>
<property name="help"></property>
<property name="id">wxID_ANY</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">&amp;Change Wallet Encryption Passphrase...</property>
<property name="name">m_menuOptionsChangeWalletPassphrase</property>
<property name="permission">public</property>
<property name="shortcut"></property>
<property name="unchecked_bitmap"></property>
<event name="OnMenuSelection">OnMenuOptionsChangeWalletPassphrase</event>
<event name="OnUpdateUI"></event>
</object>
<object class="wxMenuItem" expanded="1">
<property name="bitmap"></property>
<property name="checked">0</property>

View File

@ -36,6 +36,9 @@ void ThreadRPCServer2(void* parg);
typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
extern map<string, rpcfn_type> mapCallTable;
static int64 nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
Object JSONRPCError(int code, const string& message)
{
@ -309,7 +312,10 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
obj.push_back(Pair("testnet", fTestNet));
obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
if (pwalletMain->IsCrypted())
obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj;
}
@ -324,13 +330,19 @@ Value getnewaddress(const Array& params, bool fHelp)
"If [account] is specified (recommended), it is added to the address book "
"so payments received with the address will be credited to [account].");
if (!pwalletMain->IsLocked())
pwalletMain->TopUpKeyPool();
if (pwalletMain->GetKeyPoolSize() < 1)
throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
// Parse the account first so we don't generate a key if there's an error
string strAccount;
if (params.size() > 0)
strAccount = AccountFromValue(params[0]);
// Generate a new key that is added to wallet
string strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
string strAddress = PubKeyToAddress(pwalletMain->GetOrReuseKeyFromPool());
// This could be done in the same main CS as GetKeyFromKeyPool.
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
@ -346,37 +358,48 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
string strAddress;
CWalletDB walletdb(pwalletMain->strWalletFile);
walletdb.TxnBegin();
CAccount account;
walletdb.ReadAccount(strAccount, account);
// Check if the current key has been used
if (!account.vchPubKey.empty())
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(account.vchPubKey);
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
++it)
walletdb.ReadAccount(strAccount, account);
bool bKeyUsed = false;
// Check if the current key has been used
if (!account.vchPubKey.empty())
{
const CWalletTx& wtx = (*it).second;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if (txout.scriptPubKey == scriptPubKey)
account.vchPubKey.clear();
CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(account.vchPubKey);
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
++it)
{
const CWalletTx& wtx = (*it).second;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if (txout.scriptPubKey == scriptPubKey)
bKeyUsed = true;
}
}
// Generate a new key
if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
{
if (pwalletMain->GetKeyPoolSize() < 1)
{
if (bKeyUsed || bForceNew)
throw JSONRPCError(-12, "Error: Keypool ran out, please call topupkeypool first");
}
else
{
account.vchPubKey = pwalletMain->GetOrReuseKeyFromPool();
string strAddress = PubKeyToAddress(account.vchPubKey);
pwalletMain->SetAddressBookName(strAddress, strAccount);
walletdb.WriteAccount(strAccount, account);
}
}
}
// Generate a new key
if (account.vchPubKey.empty() || bForceNew)
{
account.vchPubKey = pwalletMain->GetKeyFromKeyPool();
string strAddress = PubKeyToAddress(account.vchPubKey);
pwalletMain->SetAddressBookName(strAddress, strAccount);
walletdb.WriteAccount(strAccount, account);
}
walletdb.TxnCommit();
strAddress = PubKeyToAddress(account.vchPubKey);
return strAddress;
@ -510,7 +533,12 @@ Value settxfee(const Array& params, bool fHelp)
Value sendtoaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 4)
if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
throw runtime_error(
"sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.00000001\n"
"requires wallet passphrase to be set with walletpassphrase first");
if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
throw runtime_error(
"sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.00000001");
@ -528,7 +556,11 @@ Value sendtoaddress(const Array& params, bool fHelp)
wtx.mapValue["to"] = params[3].get_str();
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if(pwalletMain->IsLocked())
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
if (strError != "")
throw JSONRPCError(-4, strError);
@ -674,7 +706,7 @@ int64 GetAccountBalance(const string& strAccount, int nMinDepth)
Value getbalance(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 0 || params.size() > 2)
if (fHelp || params.size() > 2)
throw runtime_error(
"getbalance [account] [minconf=1]\n"
"If [account] is not specified, returns the server's total available balance.\n"
@ -733,9 +765,9 @@ Value movecmd(const Array& params, bool fHelp)
string strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]);
int64 nAmount = AmountFromValue(params[2]);
int nMinDepth = 1;
if (params.size() > 3)
nMinDepth = params[3].get_int();
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)params[3].get_int();
string strComment;
if (params.size() > 4)
strComment = params[4].get_str();
@ -773,7 +805,12 @@ Value movecmd(const Array& params, bool fHelp)
Value sendfrom(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 3 || params.size() > 6)
if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
throw runtime_error(
"sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.00000001\n"
"requires wallet passphrase to be set with walletpassphrase first");
if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
throw runtime_error(
"sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.00000001");
@ -794,7 +831,11 @@ Value sendfrom(const Array& params, bool fHelp)
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if(pwalletMain->IsLocked())
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
// Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
if (nAmount > nBalance)
@ -809,9 +850,15 @@ Value sendfrom(const Array& params, bool fHelp)
return wtx.GetHash().GetHex();
}
Value sendmany(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 4)
if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
throw runtime_error(
"sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
"amounts are double-precision floating point numbers\n"
"requires wallet passphrase to be set with walletpassphrase first");
if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
throw runtime_error(
"sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
"amounts are double-precision floating point numbers");
@ -851,7 +898,11 @@ Value sendmany(const Array& params, bool fHelp)
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if(pwalletMain->IsLocked())
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
// Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
if (totalAmount > nBalance)
@ -1281,6 +1332,219 @@ Value backupwallet(const Array& params, bool fHelp)
}
Value keypoolrefill(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
throw runtime_error(
"keypoolrefill\n"
"Fills the keypool, requires wallet passphrase to be set.");
if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
throw runtime_error(
"keypoolrefill\n"
"Fills the keypool.");
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
pwalletMain->TopUpKeyPool();
}
if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
throw JSONRPCError(-4, "Error refreshing keypool.");
return Value::null;
}
void ThreadTopUpKeyPool(void* parg)
{
pwalletMain->TopUpKeyPool();
}
void ThreadCleanWalletPassphrase(void* parg)
{
int64 nMyWakeTime = GetTime() + *((int*)parg);
if (nWalletUnlockTime == 0)
{
CRITICAL_BLOCK(cs_nWalletUnlockTime)
{
nWalletUnlockTime = nMyWakeTime;
}
while (GetTime() < nWalletUnlockTime)
Sleep(GetTime() - nWalletUnlockTime);
CRITICAL_BLOCK(cs_nWalletUnlockTime)
{
nWalletUnlockTime = 0;
}
}
else
{
CRITICAL_BLOCK(cs_nWalletUnlockTime)
{
if (nWalletUnlockTime < nMyWakeTime)
nWalletUnlockTime = nMyWakeTime;
}
free(parg);
return;
}
pwalletMain->Lock();
delete (int*)parg;
}
Value walletpassphrase(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
throw runtime_error(
"walletpassphrase <passphrase> <timeout>\n"
"Stores the wallet decryption key in memory for <timeout> seconds.");
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
if (!pwalletMain->IsLocked())
throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
// Note that the walletpassphrase is stored in params[0] which is not mlock()ed
string strWalletPass;
strWalletPass.reserve(100);
mlock(&strWalletPass[0], strWalletPass.capacity());
strWalletPass = params[0].get_str();
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if (strWalletPass.length() > 0)
{
if (!pwalletMain->Unlock(strWalletPass))
{
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
}
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
}
else
throw runtime_error(
"walletpassphrase <passphrase> <timeout>\n"
"Stores the wallet decryption key in memory for <timeout> seconds.");
}
CreateThread(ThreadTopUpKeyPool, NULL);
int* pnSleepTime = new int(params[1].get_int());
CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
return Value::null;
}
Value walletpassphrasechange(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
throw runtime_error(
"walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
"Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
string strOldWalletPass;
strOldWalletPass.reserve(100);
mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
strOldWalletPass = params[0].get_str();
string strNewWalletPass;
strNewWalletPass.reserve(100);
mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
strNewWalletPass = params[1].get_str();
if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
throw runtime_error(
"walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
"Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
{
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
}
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
return Value::null;
}
Value walletlock(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
throw runtime_error(
"walletlock\n"
"Removes the wallet encryption key from memory, locking the wallet.\n"
"After calling this method, you will need to call walletpassphrase again\n"
"before being able to call any methods which require the wallet to be unlocked.");
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
pwalletMain->Lock();
CRITICAL_BLOCK(cs_nWalletUnlockTime)
{
nWalletUnlockTime = 0;
}
return Value::null;
}
Value encryptwallet(const Array& params, bool fHelp)
{
if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
throw runtime_error(
"encryptwallet <passphrase>\n"
"Encrypts the wallet with <passphrase>.");
if (fHelp)
return true;
if (pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
string strWalletPass;
strWalletPass.reserve(100);
mlock(&strWalletPass[0], strWalletPass.capacity());
strWalletPass = params[0].get_str();
if (strWalletPass.length() < 1)
throw runtime_error(
"encryptwallet <passphrase>\n"
"Encrypts the wallet with <passphrase>.");
if (!pwalletMain->EncryptWallet(strWalletPass))
{
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
}
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
return Value::null;
}
Value validateaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
@ -1432,44 +1696,49 @@ Value getwork(const Array& params, bool fHelp)
pair<string, rpcfn_type> pCallTable[] =
{
make_pair("help", &help),
make_pair("stop", &stop),
make_pair("getblockcount", &getblockcount),
make_pair("getblocknumber", &getblocknumber),
make_pair("getconnectioncount", &getconnectioncount),
make_pair("getdifficulty", &getdifficulty),
make_pair("getgenerate", &getgenerate),
make_pair("setgenerate", &setgenerate),
make_pair("gethashespersec", &gethashespersec),
make_pair("getinfo", &getinfo),
make_pair("getnewaddress", &getnewaddress),
make_pair("getaccountaddress", &getaccountaddress),
make_pair("setaccount", &setaccount),
make_pair("setlabel", &setaccount), // deprecated
make_pair("getaccount", &getaccount),
make_pair("getlabel", &getaccount), // deprecated
make_pair("getaddressesbyaccount", &getaddressesbyaccount),
make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
make_pair("sendtoaddress", &sendtoaddress),
make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
make_pair("getreceivedbyaddress", &getreceivedbyaddress),
make_pair("getreceivedbyaccount", &getreceivedbyaccount),
make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
make_pair("listreceivedbyaddress", &listreceivedbyaddress),
make_pair("listreceivedbyaccount", &listreceivedbyaccount),
make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
make_pair("backupwallet", &backupwallet),
make_pair("validateaddress", &validateaddress),
make_pair("getbalance", &getbalance),
make_pair("move", &movecmd),
make_pair("sendfrom", &sendfrom),
make_pair("sendmany", &sendmany),
make_pair("gettransaction", &gettransaction),
make_pair("listtransactions", &listtransactions),
make_pair("getwork", &getwork),
make_pair("listaccounts", &listaccounts),
make_pair("settxfee", &settxfee),
make_pair("help", &help),
make_pair("stop", &stop),
make_pair("getblockcount", &getblockcount),
make_pair("getblocknumber", &getblocknumber),
make_pair("getconnectioncount", &getconnectioncount),
make_pair("getdifficulty", &getdifficulty),
make_pair("getgenerate", &getgenerate),
make_pair("setgenerate", &setgenerate),
make_pair("gethashespersec", &gethashespersec),
make_pair("getinfo", &getinfo),
make_pair("getnewaddress", &getnewaddress),
make_pair("getaccountaddress", &getaccountaddress),
make_pair("setaccount", &setaccount),
make_pair("setlabel", &setaccount), // deprecated
make_pair("getaccount", &getaccount),
make_pair("getlabel", &getaccount), // deprecated
make_pair("getaddressesbyaccount", &getaddressesbyaccount),
make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
make_pair("sendtoaddress", &sendtoaddress),
make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
make_pair("getreceivedbyaddress", &getreceivedbyaddress),
make_pair("getreceivedbyaccount", &getreceivedbyaccount),
make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
make_pair("listreceivedbyaddress", &listreceivedbyaddress),
make_pair("listreceivedbyaccount", &listreceivedbyaccount),
make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
make_pair("backupwallet", &backupwallet),
make_pair("keypoolrefill", &keypoolrefill),
make_pair("walletpassphrase", &walletpassphrase),
make_pair("walletpassphrasechange", &walletpassphrasechange),
make_pair("walletlock", &walletlock),
make_pair("encryptwallet", &encryptwallet),
make_pair("validateaddress", &validateaddress),
make_pair("getbalance", &getbalance),
make_pair("move", &movecmd),
make_pair("sendfrom", &sendfrom),
make_pair("sendmany", &sendmany),
make_pair("gettransaction", &gettransaction),
make_pair("listtransactions", &listtransactions),
make_pair("getwork", &getwork),
make_pair("listaccounts", &listaccounts),
make_pair("settxfee", &settxfee),
};
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
@ -1493,6 +1762,9 @@ string pAllowInSafeMode[] =
"getaddressesbyaccount",
"getaddressesbylabel", // deprecated
"backupwallet",
"keypoolrefill",
"walletpassphrase",
"walletlock",
"validateaddress",
"getwork",
};
@ -2130,6 +2402,7 @@ int CommandLineRPC(int argc, char *argv[])
if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendmany" && n > 1)
{
string s = params[1].get_str();
@ -2146,7 +2419,6 @@ int CommandLineRPC(int argc, char *argv[])
// Parse reply
const Value& result = find_value(reply, "result");
const Value& error = find_value(reply, "error");
const Value& id = find_value(reply, "id");
if (error.type() != null_type)
{

132
src/crypter.cpp Normal file
View File

@ -0,0 +1,132 @@
// Copyright (c) 2011 The Bitcoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <vector>
#include <string>
#include "headers.h"
#ifdef __WXMSW__
#include <windows.h>
#endif
#include "crypter.h"
#include "main.h"
#include "util.h"
bool CCrypter::SetKeyFromPassphrase(const std::string& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
{
if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
return false;
// Try to keep the keydata out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap)
// Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
// Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process.
mlock(&chKey[0], sizeof chKey);
mlock(&chIV[0], sizeof chIV);
int i = 0;
if (nDerivationMethod == 0)
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
(unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
if (i != WALLET_CRYPTO_KEY_SIZE)
{
memset(&chKey, 0, sizeof chKey);
memset(&chIV, 0, sizeof chIV);
return false;
}
fKeySet = true;
return true;
}
bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
{
if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
return false;
// Try to keep the keydata out of swap
// Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
// Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process.
mlock(&chKey[0], sizeof chKey);
mlock(&chIV[0], sizeof chIV);
memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
fKeySet = true;
return true;
}
bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext)
{
if (!fKeySet)
return false;
// max ciphertext len for a n bytes of plaintext is
// n + AES_BLOCK_SIZE - 1 bytes
int nLen = vchPlaintext.size();
int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
vchCiphertext = std::vector<unsigned char> (nCLen);
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV);
EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen);
EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0])+nCLen, &nFLen);
EVP_CIPHER_CTX_cleanup(&ctx);
vchCiphertext.resize(nCLen + nFLen);
return true;
}
bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext)
{
if (!fKeySet)
return false;
// plaintext will always be equal to or lesser than length of ciphertext
int nLen = vchCiphertext.size();
int nPLen = nLen, nFLen = 0;
vchPlaintext = CKeyingMaterial(nPLen);
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV);
EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen);
EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0])+nPLen, &nFLen);
EVP_CIPHER_CTX_cleanup(&ctx);
vchPlaintext.resize(nPLen + nFLen);
return true;
}
bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext);
}
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
}

96
src/crypter.h Normal file
View File

@ -0,0 +1,96 @@
// Copyright (c) 2011 The Bitcoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef __CRYPTER_H__
#define __CRYPTER_H__
#include "key.h"
const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
/*
Private key encryption is done based on a CMasterKey,
which holds a salt and random encryption key.
CMasterKeys is encrypted using AES-256-CBC using a key
derived using derivation method nDerivationMethod
(0 == EVP_sha512()) and derivation iterations nDeriveIterations.
vchOtherDerivationParameters is provided for alternative algorithms
which may require more parameters (such as scrypt).
Wallet Private Keys are then encrypted using AES-256-CBC
with the double-sha256 of the private key as the IV, and the
master key's key as the encryption key.
*/
class CMasterKey
{
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
std::vector<unsigned char> vchOtherDerivationParameters;
IMPLEMENT_SERIALIZE
(
READWRITE(vchCryptedKey);
READWRITE(vchSalt);
READWRITE(nDerivationMethod);
READWRITE(nDeriveIterations);
READWRITE(vchOtherDerivationParameters);
)
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;
nDerivationMethod = 0;
vchOtherDerivationParameters = std::vector<unsigned char>(0);
}
};
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
class CCrypter
{
private:
unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
unsigned char chIV[WALLET_CRYPTO_KEY_SIZE];
bool fKeySet;
public:
bool SetKeyFromPassphrase(const std::string &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod);
bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext);
bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext);
bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV);
void CleanKey()
{
memset(&chKey, 0, sizeof chKey);
memset(&chIV, 0, sizeof chIV);
munlock(&chKey, sizeof chKey);
munlock(&chIV, sizeof chIV);
fKeySet = false;
}
CCrypter()
{
fKeySet = false;
}
~CCrypter()
{
CleanKey();
}
};
bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char> &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext);
#endif

View File

@ -80,7 +80,7 @@ bool CpuId(word32 input, word32 *output)
#endif
}
#ifndef _MSC_VER
#if !CRYPTOPP_BOOL_X64 && !defined(_MSC_VER) && defined(__GNUC__)
static jmp_buf s_jmpNoSSE2;
static void SigIllHandlerSSE2(int)
{

View File

@ -627,8 +627,6 @@ int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
{
int64 nCreditDebit = 0;
bool fAllAccounts = (strAccount == "*");
Dbc* pcursor = GetCursor();
@ -670,7 +668,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
}
bool CWalletDB::LoadWallet(CWallet* pwallet)
int CWalletDB::LoadWallet(CWallet* pwallet)
{
pwallet->vchDefaultKey.clear();
int nFileVersion = 0;
@ -685,12 +683,12 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
//// todo: shouldn't we catch exceptions and try to recover and continue?
CRITICAL_BLOCK(pwallet->cs_mapWallet)
CRITICAL_BLOCK(pwallet->cs_mapKeys)
CRITICAL_BLOCK(pwallet->cs_KeyStore)
{
// Get cursor
Dbc* pcursor = GetCursor();
if (!pcursor)
return false;
return DB_CORRUPT;
loop
{
@ -701,7 +699,7 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
return false;
return DB_CORRUPT;
// Unserialize
// Taking advantage of the fact that pair serialization
@ -765,14 +763,42 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
{
vector<unsigned char> vchPubKey;
ssKey >> vchPubKey;
CWalletKey wkey;
CKey key;
if (strType == "key")
ssValue >> wkey.vchPrivKey;
{
CPrivKey pkey;
ssValue >> pkey;
key.SetPrivKey(pkey);
}
else
{
CWalletKey wkey;
ssValue >> wkey;
pwallet->mapKeys[vchPubKey] = wkey.vchPrivKey;
mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
key.SetPrivKey(wkey.vchPrivKey);
}
if (!pwallet->LoadKey(key))
return DB_CORRUPT;
}
else if (strType == "mkey")
{
unsigned int nID;
ssKey >> nID;
CMasterKey kMasterKey;
ssValue >> kMasterKey;
if(pwallet->mapMasterKeys.count(nID) != 0)
return DB_CORRUPT;
pwallet->mapMasterKeys[nID] = kMasterKey;
if (pwallet->nMasterKeyMaxID < nID)
pwallet->nMasterKeyMaxID = nID;
}
else if (strType == "ckey")
{
vector<unsigned char> vchPubKey;
ssKey >> vchPubKey;
vector<unsigned char> vchPrivKey;
ssValue >> vchPrivKey;
if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
return DB_CORRUPT;
}
else if (strType == "defaultkey")
{
@ -800,7 +826,6 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins;
#endif
if (strKey == "nTransactionFee") ssValue >> nTransactionFee;
if (strKey == "addrIncoming") ssValue >> addrIncoming;
if (strKey == "fLimitProcessors") ssValue >> fLimitProcessors;
if (strKey == "nLimitProcessors") ssValue >> nLimitProcessors;
if (strKey == "fMinimizeToTray") ssValue >> fMinimizeToTray;
@ -809,6 +834,13 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
if (strKey == "addrProxy") ssValue >> addrProxy;
if (fHaveUPnP && strKey == "fUseUPnP") ssValue >> fUseUPnP;
}
else if (strType == "minversion")
{
int nMinVersion = 0;
ssValue >> nMinVersion;
if (nMinVersion > VERSION)
return DB_TOO_NEW;
}
}
pcursor->close();
}
@ -819,7 +851,6 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
printf("nFileVersion = %d\n", nFileVersion);
printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
printf("addrIncoming = %s\n", addrIncoming.ToString().c_str());
printf("fMinimizeToTray = %d\n", fMinimizeToTray);
printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
printf("fUseProxy = %d\n", fUseProxy);
@ -839,7 +870,7 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
}
return true;
return DB_LOAD_OK;
}
void ThreadFlushWalletDB(void* parg)

View File

@ -88,7 +88,7 @@ protected:
if (!pdb)
return false;
if (fReadOnly)
assert(("Write called on database in read-only mode", false));
assert(!"Write called on database in read-only mode");
// Key
CDataStream ssKey(SER_DISK);
@ -117,7 +117,7 @@ protected:
if (!pdb)
return false;
if (fReadOnly)
assert(("Erase called on database in read-only mode", false));
assert(!"Erase called on database in read-only mode");
// Key
CDataStream ssKey(SER_DISK);
@ -342,6 +342,14 @@ public:
enum DBErrors
{
DB_LOAD_OK,
DB_CORRUPT,
DB_TOO_NEW,
DB_LOAD_FAIL,
};
class CWalletDB : public CDB
{
public:
@ -391,6 +399,25 @@ public:
return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
}
bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
{
nWalletDBUpdated++;
if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
return false;
if (fEraseUnencryptedKey)
{
Erase(std::make_pair(std::string("key"), vchPubKey));
Erase(std::make_pair(std::string("wkey"), vchPubKey));
}
return true;
}
bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
}
bool WriteBestBlock(const CBlockLocator& locator)
{
nWalletDBUpdated++;
@ -450,7 +477,7 @@ public:
int64 GetAccountCreditDebit(const std::string& strAccount);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
bool LoadWallet(CWallet* pwallet);
int LoadWallet(CWallet* pwallet);
};
#endif

View File

@ -386,8 +386,16 @@ bool AppInit2(int argc, char* argv[])
nStart = GetTimeMillis();
bool fFirstRun;
pwalletMain = new CWallet("wallet.dat");
if (!pwalletMain->LoadWallet(fFirstRun))
strErrors += _("Error loading wallet.dat \n");
int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
if (nLoadWalletRet == DB_CORRUPT)
strErrors += _("Error loading wallet.dat: Wallet corrupted \n");
else if (nLoadWalletRet == DB_TOO_NEW)
strErrors += _("Error loading wallet.dat: Wallet requires newer version of Bitcoin \n");
else
strErrors += _("Error loading wallet.dat \n");
}
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
RegisterWallet(pwalletMain);
@ -415,7 +423,6 @@ bool AppInit2(int argc, char* argv[])
//// debug print
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
printf("nBestHeight = %d\n", nBestHeight);
printf("mapKeys.size() = %d\n", pwalletMain->mapKeys.size());
printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
printf("mapPubKeys.size() = %d\n", mapPubKeys.size());
printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());

View File

@ -31,6 +31,41 @@
// see www.keylength.com
// script supports up to 75 for single byte push
int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
int ok = 0;
BN_CTX *ctx = NULL;
EC_POINT *pub_key = NULL;
if (!eckey) return 0;
const EC_GROUP *group = EC_KEY_get0_group(eckey);
if ((ctx = BN_CTX_new()) == NULL)
goto err;
pub_key = EC_POINT_new(group);
if (pub_key == NULL)
goto err;
if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
goto err;
EC_KEY_set_private_key(eckey,priv_key);
EC_KEY_set_public_key(eckey,pub_key);
ok = 1;
err:
if (pub_key)
EC_POINT_free(pub_key);
if (ctx != NULL)
BN_CTX_free(ctx);
return(ok);
}
class key_error : public std::runtime_error
@ -42,8 +77,7 @@ public:
// secure_allocator is defined in serialize.h
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
class CKey
{
@ -102,6 +136,38 @@ public:
return true;
}
bool SetSecret(const CSecret& vchSecret)
{
EC_KEY_free(pkey);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if (pkey == NULL)
throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
if (vchSecret.size() != 32)
throw key_error("CKey::SetSecret() : secret must be 32 bytes");
BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
if (bn == NULL)
throw key_error("CKey::SetSecret() : BN_bin2bn failed");
if (!EC_KEY_regenerate_key(pkey,bn))
throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
BN_clear_free(bn);
fSet = true;
return true;
}
CSecret GetSecret() const
{
CSecret vchRet;
vchRet.resize(32);
const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
int nBytes = BN_num_bytes(bn);
if (bn == NULL)
throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
if (n != nBytes)
throw key_error("CKey::GetSecret(): BN_bn2bin failed");
return vchRet;
}
CPrivKey GetPrivKey() const
{
unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);
@ -154,22 +220,6 @@ public:
return false;
return true;
}
static bool Sign(const CPrivKey& vchPrivKey, uint256 hash, std::vector<unsigned char>& vchSig)
{
CKey key;
if (!key.SetPrivKey(vchPrivKey))
return false;
return key.Sign(hash, vchSig);
}
static bool Verify(const std::vector<unsigned char>& vchPubKey, uint256 hash, const std::vector<unsigned char>& vchSig)
{
CKey key;
if (!key.SetPubKey(vchPubKey))
return false;
return key.Verify(hash, vchSig);
}
};
#endif

View File

@ -4,13 +4,7 @@
#include "headers.h"
#include "db.h"
//////////////////////////////////////////////////////////////////////////////
//
// mapKeys
//
#include "crypter.h"
std::vector<unsigned char> CKeyStore::GenerateNewKey()
{
@ -18,13 +12,14 @@ std::vector<unsigned char> CKeyStore::GenerateNewKey()
CKey key;
key.MakeNewKey();
if (!AddKey(key))
throw std::runtime_error("GenerateNewKey() : AddKey failed");
throw std::runtime_error("CKeyStore::GenerateNewKey() : AddKey failed");
return key.GetPubKey();
}
bool CKeyStore::AddKey(const CKey& key)
bool CBasicKeyStore::AddKey(const CKey& key)
{
CRITICAL_BLOCK(cs_mapKeys)
CRITICAL_BLOCK(cs_mapPubKeys)
CRITICAL_BLOCK(cs_KeyStore)
{
mapKeys[key.GetPubKey()] = key.GetPrivKey();
mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();
@ -32,3 +27,121 @@ bool CKeyStore::AddKey(const CKey& key)
return true;
}
std::vector<unsigned char> CCryptoKeyStore::GenerateNewKey()
{
RandAddSeedPerfmon();
CKey key;
key.MakeNewKey();
if (!AddKey(key))
throw std::runtime_error("CCryptoKeyStore::GenerateNewKey() : AddKey failed");
return key.GetPubKey();
}
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{
CRITICAL_BLOCK(cs_vMasterKey)
{
if (!SetCrypted())
return false;
std::map<std::vector<unsigned char>, std::vector<unsigned char> >::const_iterator mi = mapCryptedKeys.begin();
for (; mi != mapCryptedKeys.end(); ++mi)
{
const std::vector<unsigned char> &vchPubKey = (*mi).first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second;
CSecret vchSecret;
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret))
return false;
CKey key;
key.SetSecret(vchSecret);
if (key.GetPubKey() == vchPubKey)
break;
return false;
}
vMasterKey = vMasterKeyIn;
}
return true;
}
bool CCryptoKeyStore::AddKey(const CKey& key)
{
CRITICAL_BLOCK(cs_KeyStore)
CRITICAL_BLOCK(cs_vMasterKey)
{
if (!IsCrypted())
return CBasicKeyStore::AddKey(key);
if (IsLocked())
return false;
std::vector<unsigned char> vchCryptedSecret;
std::vector<unsigned char> vchPubKey = key.GetPubKey();
if (!EncryptSecret(vMasterKey, key.GetSecret(), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
return false;
if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
return false;
}
return true;
}
bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
CRITICAL_BLOCK(cs_mapPubKeys)
CRITICAL_BLOCK(cs_KeyStore)
{
if (!SetCrypted())
return false;
mapCryptedKeys[vchPubKey] = vchCryptedSecret;
mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
}
return true;
}
bool CCryptoKeyStore::GetPrivKey(const std::vector<unsigned char> &vchPubKey, CKey& keyOut) const
{
CRITICAL_BLOCK(cs_vMasterKey)
{
if (!IsCrypted())
return CBasicKeyStore::GetPrivKey(vchPubKey, keyOut);
std::map<std::vector<unsigned char>, std::vector<unsigned char> >::const_iterator mi = mapCryptedKeys.find(vchPubKey);
if (mi != mapCryptedKeys.end())
{
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second;
CSecret vchSecret;
if (!DecryptSecret(vMasterKey, (*mi).second, Hash((*mi).first.begin(), (*mi).first.end()), vchSecret))
return false;
keyOut.SetSecret(vchSecret);
return true;
}
}
return false;
}
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
CRITICAL_BLOCK(cs_KeyStore)
CRITICAL_BLOCK(cs_vMasterKey)
{
if (!mapCryptedKeys.empty() || IsCrypted())
return false;
fUseCrypto = true;
CKey key;
BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
{
if (!key.SetPrivKey(mKey.second))
return false;
std::vector<unsigned char> vchCryptedSecret;
if (!EncryptSecret(vMasterKeyIn, key.GetSecret(), Hash(mKey.first.begin(), mKey.first.end()), vchCryptedSecret))
return false;
if (!AddCryptedKey(mKey.first, vchCryptedSecret))
return false;
}
mapKeys.clear();
}
return true;
}

View File

@ -4,27 +4,112 @@
#ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H
#include "crypter.h"
class CKeyStore
{
public:
std::map<std::vector<unsigned char>, CPrivKey> mapKeys;
mutable CCriticalSection cs_mapKeys;
virtual bool AddKey(const CKey& key);
mutable CCriticalSection cs_KeyStore;
virtual bool AddKey(const CKey& key) =0;
virtual bool HaveKey(const std::vector<unsigned char> &vchPubKey) const =0;
virtual bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CKey& keyOut) const =0;
virtual std::vector<unsigned char> GenerateNewKey();
};
typedef std::map<std::vector<unsigned char>, CPrivKey> KeyMap;
class CBasicKeyStore : public CKeyStore
{
protected:
KeyMap mapKeys;
public:
bool AddKey(const CKey& key);
bool HaveKey(const std::vector<unsigned char> &vchPubKey) const
{
return (mapKeys.count(vchPubKey) > 0);
}
bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CPrivKey& keyOut) const
bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CKey& keyOut) const
{
std::map<std::vector<unsigned char>, CPrivKey>::const_iterator mi = mapKeys.find(vchPubKey);
if (mi != mapKeys.end())
{
keyOut = (*mi).second;
keyOut.SetPrivKey((*mi).second);
return true;
}
return false;
}
};
class CCryptoKeyStore : public CBasicKeyStore
{
private:
std::map<std::vector<unsigned char>, std::vector<unsigned char> > mapCryptedKeys;
CKeyingMaterial vMasterKey;
// if fUseCrypto is true, mapKeys must be empty
// if fUseCrypto is false, vMasterKey must be empty
bool fUseCrypto;
protected:
bool SetCrypted()
{
if (fUseCrypto)
return true;
if (!mapKeys.empty())
return false;
fUseCrypto = true;
return true;
}
// will encrypt previously unencrypted keys
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
public:
mutable CCriticalSection cs_vMasterKey; //No guarantees master key wont get locked before you can use it, so lock this first
CCryptoKeyStore() : fUseCrypto(false)
{
}
bool IsCrypted() const
{
return fUseCrypto;
}
bool IsLocked() const
{
if (!IsCrypted())
return false;
return vMasterKey.empty();
}
bool Lock()
{
CRITICAL_BLOCK(cs_vMasterKey)
{
if (!SetCrypted())
return false;
vMasterKey.clear();
}
return true;
}
virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
std::vector<unsigned char> GenerateNewKey();
bool AddKey(const CKey& key);
bool HaveKey(const std::vector<unsigned char> &vchPubKey) const
{
if (!IsCrypted())
return CBasicKeyStore::HaveKey(vchPubKey);
return mapCryptedKeys.count(vchPubKey) > 0;
}
bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CKey& keyOut) const;
};
#endif

View File

@ -55,7 +55,6 @@ int64 nHPSTimerStart;
// Settings
int fGenerateBitcoins = false;
int64 nTransactionFee = 0;
CAddress addrIncoming;
int fLimitProcessors = false;
int nLimitProcessors = 1;
int fMinimizeToTray = true;
@ -1689,7 +1688,7 @@ string GetWarnings(string strFor)
return strStatusBar;
else if (strFor == "rpc")
return strRPC;
assert(("GetWarnings() : invalid parameter", false));
assert(!"GetWarnings() : invalid parameter");
return "error";
}
@ -1900,6 +1899,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return error("message addr size() = %d", vAddr.size());
// Store the new addresses
CAddrDB addrDB;
addrDB.TxnBegin();
int64 nNow = GetAdjustedTime();
int64 nSince = nNow - 10 * 60;
BOOST_FOREACH(CAddress& addr, vAddr)
@ -1911,7 +1912,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
continue;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
AddAddress(addr, 2 * 60 * 60);
AddAddress(addr, 2 * 60 * 60, &addrDB);
pfrom->AddAddressKnown(addr);
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
@ -1942,6 +1943,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
}
}
addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
}
@ -2213,7 +2215,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip))
mapReuseKey[pfrom->addr.ip] = pwalletMain->GetKeyFromKeyPool();
mapReuseKey[pfrom->addr.ip] = pwalletMain->GetOrReuseKeyFromPool();
// Send back approval of order and pubkey to use
CScript scriptPubKey;

View File

@ -70,7 +70,6 @@ extern std::set<CWallet*> setpwalletRegistered;
// Settings
extern int fGenerateBitcoins;
extern int64 nTransactionFee;
extern CAddress addrIncoming;
extern int fLimitProcessors;
extern int nLimitProcessors;
extern int fMinimizeToTray;

View File

@ -4,6 +4,8 @@
DEPSDIR:=/usr/i586-mingw32msvc
USE_UPNP:=0
INCLUDEPATHS= \
-I"$(DEPSDIR)/boost_1_43_0" \
-I"$(DEPSDIR)/db-4.7.25.NC/build_unix" \
@ -34,23 +36,15 @@ DEFS=-D_MT -DWIN32 -D__WXMSW__ -D_WINDOWS -DNOPCH -DUSE_SSL
DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h init.h
script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h \
crypter.h init.h
bitcoin.exe: USE_UPNP:=1
ifdef USE_UPNP
INCLUDEPATHS += -I"$(DEPSDIR)/upnpc-exe-win32-20110215"
LIBPATHS += -L"$(DEPSDIR)/upnpc-exe-win32-20110215"
LIBS += -l miniupnpc -l iphlpapi
DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif
bitcoind.exe: USE_UPNP:=0
ifdef USE_UPNP
INCLUDEPATHS += -I"$(DEPSDIR)/upnpc-exe-win32-20110215"
LIBPATHS += -L"$(DEPSDIR)/upnpc-exe-win32-20110215"
LIBS += -l miniupnpc -l iphlpapi
DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif
ifdef USE_UPNP
INCLUDEPATHS += -I"$(DEPSDIR)/upnpc-exe-win32-20110215"
LIBPATHS += -L"$(DEPSDIR)/upnpc-exe-win32-20110215"
LIBS += -l miniupnpc -l iphlpapi
DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif
LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi
@ -65,6 +59,7 @@ OBJS= \
obj/wallet.o \
obj/rpc.o \
obj/init.o \
obj/crypter.o \
cryptopp/obj/sha.o \
cryptopp/obj/cpu.o

View File

@ -33,7 +33,8 @@ DEFS=-DWIN32 -D__WXMSW__ -D_WINDOWS -DNOPCH -DUSE_SSL
DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h init.h
script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h \
init.h crypter.h
ifdef USE_UPNP
INCLUDEPATHS += -I"C:\upnpc-exe-win32-20110215"
@ -55,6 +56,7 @@ OBJS= \
obj/wallet.o \
obj/rpc.o \
obj/init.o \
obj/crypter.o \
cryptopp/obj/sha.o \
cryptopp/obj/cpu.o

View File

@ -33,7 +33,8 @@ DEBUGFLAGS=-g -DwxDEBUG_LEVEL=0
# ppc doesn't work because we don't support big-endian
CFLAGS=-mmacosx-version-min=10.5 -arch i386 -arch x86_64 -O3 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h init.h
script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h \
init.h crypter.h
OBJS= \
obj/util.o \
@ -46,6 +47,7 @@ OBJS= \
obj/wallet.o \
obj/rpc.o \
obj/init.o \
obj/crypter.o \
cryptopp/obj/sha.o \
cryptopp/obj/cpu.o

View File

@ -39,7 +39,8 @@ LIBS+= \
DEBUGFLAGS=-g -D__WXDEBUG__
CXXFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h init.h
script.h db.h net.h irc.h keystore.h main.h wallet.h rpc.h uibase.h ui.h noui.h \
init.h crypter.h
OBJS= \
obj/util.o \
@ -52,6 +53,7 @@ OBJS= \
obj/wallet.o \
obj/rpc.o \
obj/init.o \
obj/crypter.o \
cryptopp/obj/sha.o \
cryptopp/obj/cpu.o

View File

@ -440,7 +440,7 @@ void ThreadGetMyExternalIP(void* parg)
bool AddAddress(CAddress addr, int64 nTimePenalty)
bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
{
if (!addr.IsRoutable())
return false;
@ -455,7 +455,10 @@ bool AddAddress(CAddress addr, int64 nTimePenalty)
// New address
printf("AddAddress(%s)\n", addr.ToString().c_str());
mapAddresses.insert(make_pair(addr.GetKey(), addr));
CAddrDB().WriteAddress(addr);
if (pAddrDB)
pAddrDB->WriteAddress(addr);
else
CAddrDB().WriteAddress(addr);
return true;
}
else
@ -477,7 +480,12 @@ bool AddAddress(CAddress addr, int64 nTimePenalty)
fUpdated = true;
}
if (fUpdated)
CAddrDB().WriteAddress(addrFound);
{
if (pAddrDB)
pAddrDB->WriteAddress(addrFound);
else
CAddrDB().WriteAddress(addrFound);
}
}
}
return false;
@ -831,7 +839,7 @@ void ThreadSocketHandler2(void* parg)
{
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (pnode->hSocket == INVALID_SOCKET || pnode->hSocket < 0)
if (pnode->hSocket == INVALID_SOCKET)
continue;
FD_SET(pnode->hSocket, &fdsetRecv);
FD_SET(pnode->hSocket, &fdsetError);
@ -1158,6 +1166,8 @@ void DNSAddressSeed()
if (!fTestNet)
{
printf("Loading addresses from DNS seeds (could take a while)\n");
CAddrDB addrDB;
addrDB.TxnBegin();
for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
vector<CAddress> vaddr;
@ -1168,12 +1178,14 @@ void DNSAddressSeed()
if (addr.GetByte(3) != 127)
{
addr.nTime = 0;
AddAddress(addr);
AddAddress(addr, 0, &addrDB);
found++;
}
}
}
}
addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
}
printf("%d addresses found from DNS seeds\n", found);
@ -1700,7 +1712,7 @@ void StartNode(void* parg)
printf("Error: CreateThread(ThreadIRCSeed) failed\n");
// Send and receive from sockets, accept connections
pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
CreateThread(ThreadSocketHandler, NULL, true);
// Initiate outbound connections
if (!CreateThread(ThreadOpenConnections, NULL))

View File

@ -15,6 +15,7 @@
class CMessageHeader;
class CAddress;
class CAddrDB;
class CInv;
class CRequestTracker;
class CNode;
@ -40,7 +41,7 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout
bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
bool GetMyExternalIP(unsigned int& ipRet);
bool AddAddress(CAddress addr, int64 nTimePenalty=0);
bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
void AddressCurrentlyConnected(const CAddress& addr);
CNode* FindNode(unsigned int ip);
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);

View File

@ -38,7 +38,7 @@ struct AddressTablePriv
{
cachedAddressTable.clear();
CRITICAL_BLOCK(wallet->cs_mapKeys)
CRITICAL_BLOCK(cs_mapPubKeys)
CRITICAL_BLOCK(wallet->cs_mapAddressBook)
{
BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, wallet->mapAddressBook)
@ -255,14 +255,15 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
{
// Generate a new address to associate with given label, optionally
// set as default receiving address.
strAddress = PubKeyToAddress(wallet->GetKeyFromKeyPool());
strAddress = PubKeyToAddress(wallet->GetOrReuseKeyFromPool());
}
else
{
return QString();
}
// Add entry and update list
wallet->SetAddressBookName(strAddress, strLabel);
CRITICAL_BLOCK(wallet->cs_mapAddressBook)
wallet->SetAddressBookName(strAddress, strLabel);
updateList();
return QString::fromStdString(strAddress);
}

View File

@ -580,6 +580,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
case OP_ABS: if (bn < bnZero) bn = -bn; break;
case OP_NOT: bn = (bn == bnZero); break;
case OP_0NOTEQUAL: bn = (bn != bnZero); break;
default: assert(!"invalid opcode"); break;
}
popstack(stack);
stack.push_back(bn.getvch());
@ -659,6 +660,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break;
case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break;
case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break;
default: assert(!"invalid opcode"); break;
}
popstack(stack);
popstack(stack);
@ -1030,7 +1032,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
return false;
// Compile solution
CRITICAL_BLOCK(keystore.cs_mapKeys)
CRITICAL_BLOCK(keystore.cs_KeyStore)
{
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
@ -1038,13 +1040,13 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
{
// Sign
const valtype& vchPubKey = item.second;
CPrivKey privkey;
if (!keystore.GetPrivKey(vchPubKey, privkey))
CKey key;
if (!keystore.GetPrivKey(vchPubKey, key))
return false;
if (hash != 0)
{
vector<unsigned char> vchSig;
if (!CKey::Sign(privkey, hash, vchSig))
if (!key.Sign(hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig;
@ -1057,13 +1059,13 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
if (mi == mapPubKeys.end())
return false;
const vector<unsigned char>& vchPubKey = (*mi).second;
CPrivKey privkey;
if (!keystore.GetPrivKey(vchPubKey, privkey))
CKey key;
if (!keystore.GetPrivKey(vchPubKey, key))
return false;
if (hash != 0)
{
vector<unsigned char> vchSig;
if (!CKey::Sign(privkey, hash, vchSig))
if (!key.Sign(hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig << vchPubKey;
@ -1089,8 +1091,40 @@ bool IsStandard(const CScript& scriptPubKey)
bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{
CScript scriptSig;
return Solver(keystore, scriptPubKey, 0, 0, scriptSig);
vector<pair<opcodetype, valtype> > vSolution;
if (!Solver(scriptPubKey, vSolution))
return false;
// Compile solution
CRITICAL_BLOCK(keystore.cs_KeyStore)
{
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
if (item.first == OP_PUBKEY)
{
// Sign
const valtype& vchPubKey = item.second;
if (!keystore.HaveKey(vchPubKey))
return false;
}
else if (item.first == OP_PUBKEYHASH)
{
// Sign and give pubkey
map<uint160, valtype>::iterator mi = mapPubKeys.find(uint160(item.second));
if (mi == mapPubKeys.end())
return false;
const vector<unsigned char>& vchPubKey = (*mi).second;
if (!keystore.HaveKey(vchPubKey))
return false;
}
else
{
return false;
}
}
}
return true;
}

View File

@ -486,7 +486,7 @@ public:
{
// I'm not sure if this should push the script or concatenate scripts.
// If there's ever a use for pushing a script onto a script, delete this member fn
assert(("warning: pushing a CScript onto a CScript with << is probably not intended, use + to concatenate", false));
assert(!"warning: pushing a CScript onto a CScript with << is probably not intended, use + to concatenate");
return *this;
}

View File

@ -28,12 +28,36 @@ typedef unsigned long long uint64;
#if defined(_MSC_VER) && _MSC_VER < 1300
#define for if (false) ; else for
#endif
#ifdef __WXMSW__
// This is used to attempt to keep keying material out of swap
// Note that VirtualLock does not provide this as a guarantee on Windows,
// but, in practice, memory that has been VirtualLock'd almost never gets written to
// the pagefile except in rare circumstances where memory is extremely low.
#define mlock(p, n) VirtualLock((p), (n));
#define munlock(p, n) VirtualUnlock((p), (n));
#else
#include <sys/mman.h>
#include <limits.h>
/* This comes from limits.h if it's not defined there set a sane default */
#ifndef PAGESIZE
#include <unistd.h>
#define PAGESIZE sysconf(_SC_PAGESIZE)
#endif
#define mlock(a,b) \
mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
(((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
#define munlock(a,b) \
munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
(((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
#endif
class CScript;
class CDataStream;
class CAutoFile;
static const unsigned int MAX_SIZE = 0x02000000;
static const int VERSION = 32400;
static const int VERSION = 32500;
static const char* pszSubVer = "";
static const bool VERSION_IS_BETA = true;
@ -755,7 +779,8 @@ struct ser_streamplaceholder
//
// Allocator that clears its contents before deletion
// Allocator that locks its contents from being paged
// out of memory and clears its contents before deletion.
//
template<typename T>
struct secure_allocator : public std::allocator<T>
@ -777,10 +802,22 @@ struct secure_allocator : public std::allocator<T>
template<typename _Other> struct rebind
{ typedef secure_allocator<_Other> other; };
T* allocate(std::size_t n, const void *hint = 0)
{
T *p;
p = std::allocator<T>::allocate(n, hint);
if (p != NULL)
mlock(p, sizeof(T) * n);
return p;
}
void deallocate(T* p, std::size_t n)
{
if (p != NULL)
{
memset(p, 0, sizeof(T) * n);
munlock(p, sizeof(T) * n);
}
std::allocator<T>::deallocate(p, n);
}
};

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

View File

@ -59,6 +59,8 @@ protected:
void OnMenuFileExit(wxCommandEvent& event);
void OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event);
void OnMenuOptionsChangeYourAddress(wxCommandEvent& event);
void OnMenuOptionsEncryptWallet(wxCommandEvent& event);
void OnMenuOptionsChangeWalletPassphrase(wxCommandEvent& event);
void OnMenuOptionsOptions(wxCommandEvent& event);
void OnMenuHelpAbout(wxCommandEvent& event);
void OnButtonSend(wxCommandEvent& event);

View File

@ -32,6 +32,12 @@ CMainFrameBase::CMainFrameBase( wxWindow* parent, wxWindowID id, const wxString&
m_menuOptionsChangeYourAddress = new wxMenuItem( m_menuOptions, wxID_ANY, wxString( _("&Your Receiving Addresses...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsChangeYourAddress );
m_menuOptionsEncryptWallet = new wxMenuItem( m_menuOptions, wxID_ANY, wxString( _("&Encrypt Wallet...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsEncryptWallet );
m_menuOptionsChangeWalletPassphrase = new wxMenuItem( m_menuOptions, wxID_ANY, wxString( _("&Change Wallet Encryption Passphrase...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsChangeWalletPassphrase );
wxMenuItem* m_menuOptionsOptions;
m_menuOptionsOptions = new wxMenuItem( m_menuOptions, wxID_PREFERENCES, wxString( _("&Options...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsOptions );
@ -187,6 +193,8 @@ CMainFrameBase::CMainFrameBase( wxWindow* parent, wxWindowID id, const wxString&
this->Connect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaint ) );
this->Connect( m_menuFileExit->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuFileExit ) );
this->Connect( m_menuOptionsChangeYourAddress->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeYourAddress ) );
this->Connect( m_menuOptionsEncryptWallet->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsEncryptWallet ) );
this->Connect( m_menuOptionsChangeWalletPassphrase->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeWalletPassphrase ) );
this->Connect( m_menuOptionsOptions->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsOptions ) );
this->Connect( m_menuHelpAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuHelpAbout ) );
this->Connect( wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonSend ) );
@ -245,6 +253,8 @@ CMainFrameBase::~CMainFrameBase()
this->Disconnect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaint ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuFileExit ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeYourAddress ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsEncryptWallet ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeWalletPassphrase ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsOptions ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuHelpAbout ) );
this->Disconnect( wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonSend ) );

View File

@ -98,6 +98,8 @@ class CMainFrameBase : public wxFrame
virtual void OnPaint( wxPaintEvent& event ) { event.Skip(); }
virtual void OnMenuFileExit( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuOptionsChangeYourAddress( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuOptionsEncryptWallet( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuOptionsChangeWalletPassphrase( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuOptionsOptions( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuHelpAbout( wxCommandEvent& event ) { event.Skip(); }
virtual void OnButtonSend( wxCommandEvent& event ) { event.Skip(); }
@ -115,6 +117,8 @@ class CMainFrameBase : public wxFrame
public:
wxMenu* m_menuOptions;
wxMenuItem* m_menuOptionsEncryptWallet;
wxMenuItem* m_menuOptionsChangeWalletPassphrase;
wxStatusBar* m_statusBar;
wxTextCtrl* m_textCtrlAddress;
wxListCtrl* m_listCtrlAll;

View File

@ -758,8 +758,8 @@ string GetPidFile()
void CreatePidFile(string pidFile, pid_t pid)
{
FILE* file;
if (file = fopen(pidFile.c_str(), "w"))
FILE* file = fopen(pidFile.c_str(), "w");
if (file)
{
fprintf(file, "%d\n", pid);
fclose(file);
@ -788,7 +788,9 @@ void ShrinkDebugFile()
fseek(file, -sizeof(pch), SEEK_END);
int nBytes = fread(pch, 1, sizeof(pch), file);
fclose(file);
if (file = fopen(strFile.c_str(), "w"))
file = fopen(strFile.c_str(), "w");
if (file)
{
fwrite(pch, 1, nBytes, file);
fclose(file);

View File

@ -262,7 +262,7 @@ public:
// I'd rather be careful than suffer the other more error prone syntax.
// The compiler will optimise away all this loop junk.
#define CRITICAL_BLOCK(cs) \
for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by CRITICAL_BLOCK!", !fcriticalblockonce)), fcriticalblockonce=false) \
for (bool fcriticalblockonce=true; fcriticalblockonce; assert("break caught by CRITICAL_BLOCK!" && !fcriticalblockonce), fcriticalblockonce=false) \
for (CCriticalBlock criticalblock(cs); fcriticalblockonce && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
class CTryCriticalBlock
@ -276,7 +276,7 @@ public:
};
#define TRY_CRITICAL_BLOCK(cs) \
for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by TRY_CRITICAL_BLOCK!", !fcriticalblockonce)), fcriticalblockonce=false) \
for (bool fcriticalblockonce=true; fcriticalblockonce; assert("break caught by TRY_CRITICAL_BLOCK!" && !fcriticalblockonce), fcriticalblockonce=false) \
for (CTryCriticalBlock criticalblock(cs); fcriticalblockonce && (fcriticalblockonce = criticalblock.Entered()) && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
@ -646,7 +646,7 @@ inline bool TerminateThread(pthread_t hthread, unsigned int nExitCode)
return (pthread_cancel(hthread) == 0);
}
inline void ExitThread(unsigned int nExitCode)
inline void ExitThread(size_t nExitCode)
{
pthread_exit((void*)nExitCode);
}

View File

@ -5,11 +5,11 @@
#include "headers.h"
#include "db.h"
#include "cryptopp/sha.h"
#include "crypter.h"
using namespace std;
//////////////////////////////////////////////////////////////////////////////
//
// mapWallet
@ -17,10 +17,181 @@ using namespace std;
bool CWallet::AddKey(const CKey& key)
{
this->CKeyStore::AddKey(key);
if (!CCryptoKeyStore::AddKey(key))
return false;
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
if (!IsCrypted())
return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
return true;
}
bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
if (!fFileBacked)
return true;
CRITICAL_BLOCK(cs_pwalletdbEncryption)
{
if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
else
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
}
}
bool CWallet::Unlock(const string& strWalletPassphrase)
{
CRITICAL_BLOCK(cs_vMasterKey)
{
if (!IsLocked())
return false;
CCrypter crypter;
CKeyingMaterial vMasterKey;
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
return false;
if (CCryptoKeyStore::Unlock(vMasterKey))
return true;
}
}
return false;
}
bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase)
{
CRITICAL_BLOCK(cs_vMasterKey)
{
bool fWasLocked = IsLocked();
Lock();
CCrypter crypter;
CKeyingMaterial vMasterKey;
BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if(!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
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;
CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
if (fWasLocked)
Lock();
return true;
}
}
}
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)
{
CRITICAL_BLOCK(cs_mapPubKeys)
CRITICAL_BLOCK(cs_KeyStore)
CRITICAL_BLOCK(cs_vMasterKey)
CRITICAL_BLOCK(cs_pwalletdbEncryption)
{
if (IsCrypted())
return false;
CKeyingMaterial vMasterKey;
RandAddSeedPerfmon();
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
CMasterKey kMasterKey;
RandAddSeedPerfmon();
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
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))
return false;
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked)
{
pwalletdbEncryption = new CWalletDB(strWalletFile);
pwalletdbEncryption->TxnBegin();
pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
}
if (!EncryptKeys(vMasterKey))
{
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();
}
return true;
}
void CWallet::WalletUpdateSpent(const CTransaction &tx)
@ -98,7 +269,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
if (txout.scriptPubKey == scriptDefaultKey)
SetDefaultKey(GetKeyFromKeyPool());
{
SetDefaultKey(GetOrReuseKeyFromPool());
SetAddressBookName(PubKeyToAddress(vchDefaultKey), "");
}
}
#endif
// Notify UI
@ -552,8 +726,6 @@ void CWallet::ResendWalletTransactions()
int64 CWallet::GetBalance() const
{
int64 nStart = GetTimeMillis();
int64 nTotal = 0;
CRITICAL_BLOCK(cs_mapWallet)
{
@ -566,7 +738,6 @@ int64 CWallet::GetBalance() const
}
}
//printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);
return nTotal;
}
@ -798,7 +969,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW
// Reserve a new key pair from key pool
vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
assert(mapKeys.count(vchPubKey));
// assert(mapKeys.count(vchPubKey));
// Fill a vout to ourself, using same address type as the payment
CScript scriptChange;
@ -918,15 +1089,24 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
{
CReserveKey reservekey(this);
int64 nFeeRequired;
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
CRITICAL_BLOCK(cs_vMasterKey)
{
string strError;
if (nValue + nFeeRequired > GetBalance())
strError = strprintf(_("Error: 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
strError = _("Error: Transaction creation failed ");
printf("SendMoney() : %s", strError.c_str());
return strError;
if (IsLocked())
{
string strError = _("Error: Wallet locked, unable to create transaction ");
printf("SendMoney() : %s", strError.c_str());
return strError;
}
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
{
string strError;
if (nValue + nFeeRequired > GetBalance())
strError = strprintf(_("Error: 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
strError = _("Error: Transaction creation failed ");
printf("SendMoney() : %s", strError.c_str());
return strError;
}
}
if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
@ -961,27 +1141,28 @@ string CWallet::SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWall
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 (!mapKeys.count(vchDefaultKey))
if (!HaveKey(vchDefaultKey))
{
// Create new default key
// Create new keyUser and set as default key
RandAddSeedPerfmon();
SetDefaultKey(GetKeyFromKeyPool());
SetDefaultKey(GetOrReuseKeyFromPool());
if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), ""))
return false;
return DB_LOAD_FAIL;
}
CreateThread(ThreadFlushWalletDB, &strWalletFile);
return true;
return DB_LOAD_OK;
}
@ -1048,14 +1229,16 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
return true;
}
void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
bool CWallet::TopUpKeyPool()
{
nIndex = -1;
keypool.vchPubKey.clear();
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_setKeyPool)
CRITICAL_BLOCK(cs_vMasterKey)
{
if (IsLocked())
return false;
CWalletDB walletdb(strWalletFile);
// Top up key pool
@ -1066,18 +1249,36 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed");
throw runtime_error("TopUpKeyPool() : writing generated key failed");
setKeyPool.insert(nEnd);
printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
}
}
return true;
}
void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
{
nIndex = -1;
keypool.vchPubKey.clear();
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_setKeyPool)
{
if (!IsLocked())
TopUpKeyPool();
// Get the oldest key
assert(!setKeyPool.empty());
if(setKeyPool.empty())
return;
CWalletDB walletdb(strWalletFile);
nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
throw runtime_error("ReserveKeyFromKeyPool() : read failed");
if (!mapKeys.count(keypool.vchPubKey))
if (!HaveKey(keypool.vchPubKey))
throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
assert(!keypool.vchPubKey.empty());
printf("keypool reserve %"PRI64d"\n", nIndex);
@ -1106,11 +1307,13 @@ void CWallet::ReturnKey(int64 nIndex)
printf("keypool return %"PRI64d"\n", nIndex);
}
vector<unsigned char> CWallet::GetKeyFromKeyPool()
vector<unsigned char> CWallet::GetOrReuseKeyFromPool()
{
int64 nIndex = 0;
CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool);
if(nIndex == -1)
return vchDefaultKey;
KeepKey(nIndex);
return keypool.vchPubKey;
}
@ -1120,6 +1323,8 @@ int64 CWallet::GetOldestKeyPoolTime()
int64 nIndex = 0;
CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
return GetTime();
ReturnKey(nIndex);
return keypool.nTime;
}
@ -1130,7 +1335,13 @@ vector<unsigned char> CReserveKey::GetReservedKey()
{
CKeyPool keypool;
pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
vchPubKey = keypool.vchPubKey;
if (nIndex != -1)
vchPubKey = keypool.vchPubKey;
else
{
printf("CReserveKey::GetReservedKey(): Warning: using default key instead of a new key, top up your keypool.");
vchPubKey = pwallet->vchDefaultKey;
}
}
assert(!vchPubKey.empty());
return vchPubKey;

View File

@ -12,12 +12,14 @@ class CWalletTx;
class CReserveKey;
class CWalletDB;
class CWallet : public CKeyStore
class CWallet : public CCryptoKeyStore
{
private:
bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
CWalletDB *pwalletdbEncryption;
CCriticalSection cs_pwalletdbEncryption;
public:
bool fFileBacked;
@ -26,14 +28,22 @@ public:
std::set<int64> setKeyPool;
CCriticalSection cs_setKeyPool;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID;
CWallet()
{
fFileBacked = false;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
}
CWallet(std::string strWalletFileIn)
{
strWalletFile = strWalletFileIn;
fFileBacked = true;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
}
mutable CCriticalSection cs_mapWallet;
@ -48,7 +58,16 @@ public:
std::vector<unsigned char> vchDefaultKey;
// keystore implementation
bool AddKey(const CKey& key);
bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
bool Unlock(const std::string& strWalletPassphrase);
bool ChangeWalletPassphrase(const std::string& strOldWalletPassphrase, const std::string& strNewWalletPassphrase);
bool EncryptWallet(const std::string& strWalletPassphrase);
bool AddToWallet(const CWalletTx& wtxIn);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false);
bool EraseFromWallet(uint256 hash);
@ -65,10 +84,11 @@ public:
std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
std::string SendMoneyToBitcoinAddress(std::string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
bool TopUpKeyPool();
void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
void KeepKey(int64 nIndex);
void ReturnKey(int64 nIndex);
std::vector<unsigned char> GetKeyFromKeyPool();
std::vector<unsigned char> GetOrReuseKeyFromPool();
int64 GetOldestKeyPoolTime();
bool IsMine(const CTxIn& txin) const;
@ -148,7 +168,7 @@ public:
walletdb.WriteBestBlock(loc);
}
bool LoadWallet(bool& fFirstRunRet);
int LoadWallet(bool& fFirstRunRet);
// bool BackupWallet(const std::string& strDest);
// requires cs_mapAddressBook lock
@ -175,6 +195,11 @@ public:
}
}
int GetKeyPoolSize()
{
return setKeyPool.size();
}
bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx);
bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey);