|
|
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
|
|
// Copyright (c) 2009-2012 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 "wallet.h"
|
|
|
|
#include "walletdb.h"
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
#include "crypter.h"
|
|
|
|
#include "ui_interface.h"
|
|
|
|
#include "base58.h"
|
|
|
|
#include <boost/algorithm/string/replace.hpp>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// mapWallet
|
|
|
|
//
|
|
|
|
|
|
|
|
struct CompareValueOnly
|
|
|
|
{
|
|
|
|
bool operator()(const pair<int64, pair<const CWalletTx*, unsigned int> >& t1,
|
|
|
|
const pair<int64, pair<const CWalletTx*, unsigned int> >& t2) const
|
|
|
|
{
|
|
|
|
return t1.first < t2.first;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
CPubKey CWallet::GenerateNewKey(std::string username)
|
|
|
|
{
|
|
|
|
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
|
|
|
|
|
|
|
|
RandAddSeedPerfmon();
|
|
|
|
CKey secret;
|
|
|
|
secret.MakeNewKey(fCompressed);
|
|
|
|
|
|
|
|
// Compressed public keys were introduced in version 0.6.0
|
|
|
|
if (fCompressed)
|
|
|
|
SetMinVersion(FEATURE_COMPRPUBKEY);
|
|
|
|
|
|
|
|
CPubKey pubkey = secret.GetPubKey();
|
|
|
|
|
|
|
|
// Create new metadata
|
|
|
|
int64 nCreationTime = GetTime();
|
|
|
|
mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime, username);
|
|
|
|
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
|
|
|
|
nTimeFirstKey = nCreationTime;
|
|
|
|
|
|
|
|
if (!AddKeyPubKey(secret, pubkey))
|
|
|
|
throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
|
|
|
|
|
|
|
|
if (!vchDefaultKey.IsValid())
|
|
|
|
vchDefaultKey = pubkey;
|
|
|
|
return pubkey;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
|
|
|
|
{
|
|
|
|
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
|
|
|
|
return false;
|
|
|
|
if (!fFileBacked)
|
|
|
|
return true;
|
|
|
|
if (!IsCrypted()) {
|
|
|
|
return CWalletDB(strWalletFile).WriteKey(pubkey,
|
|
|
|
secret.GetPrivKey(),
|
|
|
|
mapKeyMetadata[pubkey.GetID()]);
|
|
|
|
}
|
|
|
|
return true;
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
|
|
|
|
const vector<unsigned char> &vchCryptedSecret)
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
{
|
|
|
|
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
|
|
|
|
return false;
|
|
|
|
if (!fFileBacked)
|
|
|
|
return true;
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
|
|
|
if (pwalletdbEncryption)
|
|
|
|
return pwalletdbEncryption->WriteCryptedKey(vchPubKey,
|
|
|
|
vchCryptedSecret,
|
|
|
|
mapKeyMetadata[vchPubKey.GetID()]);
|
|
|
|
else
|
|
|
|
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey,
|
|
|
|
vchCryptedSecret,
|
|
|
|
mapKeyMetadata[vchPubKey.GetID()]);
|
|
|
|
}
|
|
|
|
return false;
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
|
|
|
|
{
|
|
|
|
if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
|
|
|
|
nTimeFirstKey = meta.nCreateTime;
|
|
|
|
|
|
|
|
mapKeyMetadata[pubkey.GetID()] = meta;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::GetKeyIdFromUsername(std::string username, CKeyID &keyid)
|
|
|
|
{
|
|
|
|
for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++) {
|
|
|
|
if (it->second.username == username) {
|
|
|
|
keyid = it->first;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
|
|
|
|
{
|
|
|
|
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
{
|
|
|
|
CCrypter crypter;
|
|
|
|
CKeyingMaterial vMasterKey;
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
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))
|
|
|
|
continue; // try another master key
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
if (CCryptoKeyStore::Unlock(vMasterKey))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
{
|
|
|
|
bool fWasLocked = IsLocked();
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
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))
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
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);
|
|
|
|
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWallet::SetBestChain(const CBlockLocator& loc)
|
|
|
|
{
|
|
|
|
CWalletDB walletdb(strWalletFile);
|
|
|
|
walletdb.WriteBestBlock(loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
|
|
|
|
{
|
|
|
|
if (nWalletVersion >= nVersion)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
|
|
|
|
if (fExplicit && nVersion > nWalletMaxVersion)
|
|
|
|
nVersion = FEATURE_LATEST;
|
|
|
|
|
|
|
|
nWalletVersion = nVersion;
|
|
|
|
|
|
|
|
if (nVersion > nWalletMaxVersion)
|
|
|
|
nWalletMaxVersion = nVersion;
|
|
|
|
|
|
|
|
if (fFileBacked)
|
|
|
|
{
|
|
|
|
CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
|
|
|
|
if (nWalletVersion >= 40000)
|
|
|
|
{
|
|
|
|
// Versions prior to 0.4.0 did not support the "minversion" record.
|
|
|
|
// Use a CCorruptAddress to make them crash instead.
|
|
|
|
CCorruptAddress corruptAddress;
|
|
|
|
pwalletdb->WriteSetting("addrIncoming", corruptAddress);
|
|
|
|
}
|
|
|
|
if (nWalletVersion > 40000)
|
|
|
|
pwalletdb->WriteMinVersion(nWalletVersion);
|
|
|
|
if (!pwalletdbIn)
|
|
|
|
delete pwalletdb;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::SetMaxVersion(int nVersion)
|
|
|
|
{
|
|
|
|
// cannot downgrade below current version
|
|
|
|
if (nWalletVersion > nVersion)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
nWalletMaxVersion = nVersion;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
{
|
|
|
|
if (IsCrypted())
|
|
|
|
return false;
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
CKeyingMaterial vMasterKey;
|
|
|
|
RandAddSeedPerfmon();
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
|
|
|
|
RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
CMasterKey kMasterKey;
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
RandAddSeedPerfmon();
|
|
|
|
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
|
|
|
|
RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
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;
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
|
|
|
|
if (fFileBacked)
|
|
|
|
{
|
|
|
|
pwalletdbEncryption = new CWalletDB(strWalletFile);
|
|
|
|
if (!pwalletdbEncryption->TxnBegin())
|
|
|
|
return false;
|
|
|
|
pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
}
|
|
|
|
|
|
|
|
// Encryption was introduced in version 0.4.0
|
|
|
|
SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
|
|
|
|
|
|
|
|
if (fFileBacked)
|
|
|
|
{
|
|
|
|
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.
|
|
|
|
|
|
|
|
delete pwalletdbEncryption;
|
|
|
|
pwalletdbEncryption = NULL;
|
|
|
|
}
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
Lock();
|
|
|
|
Unlock(strWalletPassphrase);
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
Lock();
|
|
|
|
|
|
|
|
// Need to completely rewrite the wallet file; if we don't, bdb might keep
|
|
|
|
// bits of the unencrypted private key in slack space in the database file.
|
|
|
|
CDB::Rewrite(strWalletFile);
|
|
|
|
|
|
|
|
}
|
|
|
|
NotifyStatusChanged(this);
|
|
|
|
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64 CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
|
|
|
|
{
|
|
|
|
int64 nRet = nOrderPosNext++;
|
|
|
|
if (pwalletdb) {
|
|
|
|
pwalletdb->WriteOrderPosNext(nOrderPosNext);
|
|
|
|
} else {
|
|
|
|
CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext);
|
|
|
|
}
|
|
|
|
return nRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWallet::MarkDirty()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
|
|
|
/*
|
|
|
|
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
|
|
|
|
item.second.MarkDirty();
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::AddToWallet(const CWalletTx& wtxIn)
|
|
|
|
{
|
|
|
|
uint256 hash = wtxIn.GetHash();
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
|
|
|
// Inserts only if not already there, returns tx inserted or tx found
|
|
|
|
pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
|
|
|
|
CWalletTx& wtx = (*ret.first).second;
|
|
|
|
wtx.BindWallet(this);
|
|
|
|
bool fInsertedNew = ret.second;
|
|
|
|
if (fInsertedNew)
|
|
|
|
{
|
|
|
|
wtx.nTimeReceived = GetAdjustedTime();
|
|
|
|
wtx.nOrderPos = IncOrderPosNext();
|
|
|
|
|
|
|
|
wtx.nTimeSmart = wtx.nTimeReceived;
|
|
|
|
if (wtxIn.hashBlock != 0)
|
|
|
|
{
|
|
|
|
if (mapBlockIndex.count(wtxIn.hashBlock))
|
|
|
|
{
|
|
|
|
unsigned int& blocktime = mapBlockIndex[wtxIn.hashBlock]->nTime;
|
|
|
|
wtx.nTimeSmart = blocktime;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
printf("AddToWallet() : found %s in block %s not in index\n",
|
|
|
|
wtxIn.GetHash().ToString().c_str(),
|
|
|
|
wtxIn.hashBlock.ToString().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool fUpdated = false;
|
|
|
|
if (!fInsertedNew)
|
|
|
|
{
|
|
|
|
// Merge
|
|
|
|
if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
|
|
|
|
{
|
|
|
|
wtx.hashBlock = wtxIn.hashBlock;
|
|
|
|
fUpdated = true;
|
|
|
|
}
|
|
|
|
if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
|
|
|
|
{
|
|
|
|
wtx.vMerkleBranch = wtxIn.vMerkleBranch;
|
|
|
|
wtx.nIndex = wtxIn.nIndex;
|
|
|
|
fUpdated = true;
|
|
|
|
}
|
|
|
|
if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
|
|
|
|
{
|
|
|
|
wtx.fFromMe = wtxIn.fFromMe;
|
|
|
|
fUpdated = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//// debug print
|
|
|
|
printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
|
|
|
|
|
|
|
|
// Write to disk
|
|
|
|
if (fInsertedNew || fUpdated)
|
|
|
|
if (!wtx.WriteToDisk())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!fHaveGUI) {
|
|
|
|
// If default receiving address gets used, replace it with a new one
|
|
|
|
if (vchDefaultKey.IsValid()) {
|
|
|
|
CScript scriptDefaultKey;
|
|
|
|
scriptDefaultKey.SetDestination(vchDefaultKey.GetID());
|
|
|
|
/*
|
|
|
|
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
|
|
|
{
|
|
|
|
if (txout.scriptPubKey == scriptDefaultKey)
|
|
|
|
{
|
|
|
|
CPubKey newDefaultKey;
|
|
|
|
if (GetKeyFromPool(newDefaultKey, false))
|
|
|
|
{
|
|
|
|
SetDefaultKey(newDefaultKey);
|
|
|
|
SetAddressBookName(vchDefaultKey.GetID(), "");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify UI of new or updated transaction
|
|
|
|
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
|
|
|
|
|
|
|
|
// notify an external script when a wallet transaction comes in or is updated
|
|
|
|
std::string strCmd = GetArg("-walletnotify", "");
|
|
|
|
|
|
|
|
if ( !strCmd.empty())
|
|
|
|
{
|
|
|
|
boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
|
|
|
|
boost::thread t(runCommand, strCmd); // thread runs free
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add a transaction to the wallet, or update it.
|
|
|
|
// pblock is optional, but should be provided if the transaction is known to be in a block.
|
|
|
|
// If fUpdate is true, existing transactions will be updated.
|
|
|
|
bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
|
|
|
bool fExisted = mapWallet.count(hash);
|
|
|
|
if (fExisted && !fUpdate) return false;
|
|
|
|
if (fExisted || IsMine(tx) || IsFromMe(tx))
|
|
|
|
{
|
|
|
|
CWalletTx wtx(this,tx);
|
|
|
|
// Get merkle branch if transaction was found in a block
|
|
|
|
if (pblock)
|
|
|
|
wtx.SetMerkleBranch(pblock);
|
|
|
|
return AddToWallet(wtx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWallet::EraseFromWallet(uint256 hash)
|
|
|
|
{
|
|
|
|
if (!fFileBacked)
|
|
|
|
return false;
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
|
|
|
if (mapWallet.erase(hash))
|
|
|
|
CWalletDB(strWalletFile).EraseTx(hash);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int64 CWalletTx::GetTxTime() const
|
|
|
|
{
|
|
|
|
int64 n = nTimeSmart;
|
|
|
|
return n ? n : nTimeReceived;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CWalletTx::GetRequestCount() const
|
|
|
|
{
|
|
|
|
// Returns -1 if it wasn't being tracked
|
|
|
|
int nRequests = -1;
|
|
|
|
{
|
|
|
|
LOCK(pwallet->cs_wallet);
|
|
|
|
if (IsSpamMessage())
|
|
|
|
{
|
|
|
|
// Generated block
|
|
|
|
if (hashBlock != 0)
|
|
|
|
{
|
|
|
|
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
|
|
|
|
if (mi != pwallet->mapRequestCount.end())
|
|
|
|
nRequests = (*mi).second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Did anyone request this transaction?
|
|
|
|
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
|
|
|
|
if (mi != pwallet->mapRequestCount.end())
|
|
|
|
{
|
|
|
|
nRequests = (*mi).second;
|
|
|
|
|
|
|
|
// How about the block it's in?
|
|
|
|
if (nRequests == 0 && hashBlock != 0)
|
|
|
|
{
|
|
|
|
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
|
|
|
|
if (mi != pwallet->mapRequestCount.end())
|
|
|
|
nRequests = (*mi).second;
|
|
|
|
else
|
|
|
|
nRequests = 1; // If it's in someone else's block it must have got out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nRequests;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
13 years ago
|
|
|
void CWalletTx::AddSupportingTransactions()
|
|
|
|
{
|
|
|
|
// [MF] remove me
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWalletTx::WriteToDisk()
|
|
|
|
{
|
|
|
|
return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scan the block chain (starting in pindexStart) for transactions
|
|
|
|
// from or to us. If fUpdate is true, found transactions that already
|
|
|
|
// exist in the wallet will be updated.
|
|
|
|
int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
CBlockIndex* pindex = pindexStart;
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
|
|
|
while (pindex)
|
|
|
|
{
|
|
|
|
// no need to read and scan block, if block was created before
|
|
|
|
// our wallet birthday (as adjusted for block time variability)
|
|
|
|
if (nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200))) {
|
|
|
|
pindex = pindex->GetNextInMainChain();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
CBlock block;
|
|
|
|
ReadBlockFromDisk(block, pindex);
|
|
|
|
BOOST_FOREACH(CTransaction& tx, block.vtx)
|
|
|
|
{
|
|
|
|
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
pindex = pindex->GetNextInMainChain();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWallet::ReacceptWalletTransactions()
|
|
|
|
{
|
|
|
|
bool fRepeat = true;
|
|
|
|
while (fRepeat)
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
|
|
|
fRepeat = false;
|
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
13 years ago
|
|
|
bool fMissing = false;
|
|
|
|
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
|
|
|
|
{
|
|
|
|
CWalletTx& wtx = item.second;
|
|
|
|
if (wtx.IsSpamMessage() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
CTransaction tx;
|
|
|
|
uint256 hashBlock;
|
|
|
|
bool fUpdated = false;
|
|
|
|
bool fFound = false;
|
|
|
|
// [MF] can't use GetTransaction from main.cpp here. so?
|
|
|
|
// GetTransaction(wtx.GetUsernameHash(), tx, hashBlock);
|
|
|
|
if (fFound || wtx.GetDepthInMainChain() > 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
|
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
13 years ago
|
|
|
for (unsigned int i = 0; i < wtx.vout.size(); i++)
|
|
|
|
{
|
|
|
|
if (wtx.IsSpent(i))
|
|
|
|
continue;
|
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
13 years ago
|
|
|
if ((i >= coins.vout.size() || coins.vout[i].IsNull()) && IsMine(wtx.vout[i]))
|
|
|
|
{
|
|
|
|
wtx.MarkSpent(i);
|
|
|
|
fUpdated = true;
|
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
13 years ago
|
|
|
fMissing = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (fUpdated)
|
|
|
|
{
|
|
|
|
printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
|
|
|
|
wtx.MarkDirty();
|
|
|
|
wtx.WriteToDisk();
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Re-accept any txes of ours that aren't already in a block
|
|
|
|
if (!wtx.IsSpamMessage())
|
|
|
|
wtx.AcceptWalletTransaction();
|
|
|
|
}
|
|
|
|
}
|
Ultraprune
This switches bitcoin's transaction/block verification logic to use a
"coin database", which contains all unredeemed transaction output scripts,
amounts and heights.
The name ultraprune comes from the fact that instead of a full transaction
index, we only (need to) keep an index with unspent outputs. For now, the
blocks themselves are kept as usual, although they are only necessary for
serving, rescanning and reorganizing.
The basic datastructures are CCoins (representing the coins of a single
transaction), and CCoinsView (representing a state of the coins database).
There are several implementations for CCoinsView. A dummy, one backed by
the coins database (coins.dat), one backed by the memory pool, and one
that adds a cache on top of it. FetchInputs, ConnectInputs, ConnectBlock,
DisconnectBlock, ... now operate on a generic CCoinsView.
The block switching logic now builds a single cached CCoinsView with
changes to be committed to the database before any changes are made.
This means no uncommitted changes are ever read from the database, and
should ease the transition to another database layer which does not
support transactions (but does support atomic writes), like LevelDB.
For the getrawtransaction() RPC call, access to a txid-to-disk index
would be preferable. As this index is not necessary or even useful
for any other part of the implementation, it is not provided. Instead,
getrawtransaction() uses the coin database to find the block height,
and then scans that block to find the requested transaction. This is
slow, but should suffice for debug purposes.
13 years ago
|
|
|
if (fMissing)
|
|
|
|
{
|
|
|
|
// TODO: optimize this to scan just part of the block chain?
|
|
|
|
if (ScanForWalletTransactions(pindexGenesisBlock))
|
|
|
|
fRepeat = true; // Found missing transactions: re-do re-accept.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWalletTx::RelayWalletTransaction()
|
|
|
|
{
|
|
|
|
if (!IsSpamMessage())
|
|
|
|
{
|
|
|
|
if (GetDepthInMainChain() == 0) {
|
|
|
|
uint256 hash = GetUsernameHash();
|
|
|
|
printf("Relaying wtx %s\n", hash.ToString().c_str());
|
|
|
|
RelayTransaction((CTransaction)*this, hash);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWallet::ResendWalletTransactions()
|
|
|
|
{
|
|
|
|
// Do this infrequently and randomly to avoid giving away
|
|
|
|
// that these are our transactions.
|
|
|
|
static int64 nNextTime;
|
|
|
|
if (GetTime() < nNextTime)
|
|
|
|
return;
|
|
|
|
bool fFirst = (nNextTime == 0);
|
|
|
|
nNextTime = GetTime() + GetRand(30 * 60);
|
|
|
|
if (fFirst)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Only do it if there's been a new block since last time
|
|
|
|
static int64 nLastTime;
|
|
|
|
if (nTimeBestReceived < nLastTime)
|
|
|
|
return;
|
|
|
|
nLastTime = GetTime();
|
|
|
|
|
|
|
|
// Rebroadcast any of our txes that aren't in a block yet
|
|
|
|
printf("ResendWalletTransactions()\n");
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
|
|
|
// Sort them in chronological order
|
|
|
|
multimap<unsigned int, CWalletTx*> mapSorted;
|
|
|
|
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
|
|
|
|
{
|
|
|
|
CWalletTx& wtx = item.second;
|
|
|
|
// Don't rebroadcast until it's had plenty of time that
|
|
|
|
// it should have gotten in already by now.
|
|
|
|
if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
|
|
|
|
mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
|
|
|
|
}
|
|
|
|
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
|
|
|
|
{
|
|
|
|
CWalletTx& wtx = *item.second;
|
|
|
|
wtx.RelayWalletTransaction();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Actions
|
|
|
|
//
|
|
|
|
|
|
|
|
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
|
|
|
{
|
|
|
|
if (!fFileBacked)
|
|
|
|
return DB_LOAD_OK;
|
|
|
|
fFirstRunRet = false;
|
|
|
|
DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
|
|
|
|
if (nLoadWalletRet == DB_NEED_REWRITE)
|
|
|
|
{
|
|
|
|
if (CDB::Rewrite(strWalletFile, "\x04pool"))
|
|
|
|
{
|
|
|
|
setKeyPool.clear();
|
|
|
|
// Note: can't top-up keypool here, because wallet is locked.
|
|
|
|
// User will be prompted to unlock wallet the next operation
|
|
|
|
// the requires a new key.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nLoadWalletRet != DB_LOAD_OK)
|
|
|
|
return nLoadWalletRet;
|
|
|
|
fFirstRunRet = !vchDefaultKey.IsValid();
|
|
|
|
|
|
|
|
return DB_LOAD_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
|
|
|
|
{
|
|
|
|
if (fFileBacked)
|
|
|
|
{
|
|
|
|
if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
vchDefaultKey = vchPubKey;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
|
|
|
|
{
|
|
|
|
if (!pwallet->fFileBacked)
|
|
|
|
return false;
|
|
|
|
strWalletFileOut = pwallet->strWalletFile;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
14 years ago
|
|
|
|
|
|
|
|
|
|
|
void CWallet::UpdatedTransaction(const uint256 &hashTx)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
LOCK(cs_wallet);
|
|
|
|
// Only notify UI if this transaction is in this wallet
|
|
|
|
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
|
|
|
|
if (mi != mapWallet.end())
|
|
|
|
NotifyTransactionChanged(this, hashTx, CT_UPDATED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const {
|
|
|
|
mapKeyBirth.clear();
|
|
|
|
|
|
|
|
// get birth times for keys with metadata
|
|
|
|
for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
|
|
|
|
if (it->second.nCreateTime)
|
|
|
|
mapKeyBirth[it->first] = it->second.nCreateTime;
|
|
|
|
|
|
|
|
// map in which we'll infer heights of other keys
|
|
|
|
CBlockIndex *pindexMax = FindBlockByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin
|
|
|
|
std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
|
|
|
|
std::set<CKeyID> setKeys;
|
|
|
|
GetKeys(setKeys);
|
|
|
|
BOOST_FOREACH(const CKeyID &keyid, setKeys) {
|
|
|
|
if (mapKeyBirth.count(keyid) == 0)
|
|
|
|
mapKeyFirstBlock[keyid] = pindexMax;
|
|
|
|
}
|
|
|
|
setKeys.clear();
|
|
|
|
|
|
|
|
// if there are no such keys, we're done
|
|
|
|
if (mapKeyFirstBlock.empty())
|
|
|
|
return;
|
|
|
|
/*
|
|
|
|
// find first block that affects those keys, if there are any left
|
|
|
|
std::vector<CKeyID> vAffected;
|
|
|
|
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
|
|
|
|
// iterate over all wallet transactions...
|
|
|
|
const CWalletTx &wtx = (*it).second;
|
|
|
|
std::map<uint256, CBlockIndex*>::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
|
|
|
|
if (blit != mapBlockIndex.end() && blit->second->IsInMainChain()) {
|
|
|
|
// ... which are already in a block
|
|
|
|
int nHeight = blit->second->nHeight;
|
|
|
|
BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
|
|
|
|
// iterate over all their outputs
|
|
|
|
::ExtractAffectedKeys(*this, txout.scriptPubKey, vAffected);
|
|
|
|
BOOST_FOREACH(const CKeyID &keyid, vAffected) {
|
|
|
|
// ... and all their affected keys
|
|
|
|
std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
|
|
|
|
if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
|
|
|
|
rit->second = blit->second;
|
|
|
|
}
|
|
|
|
vAffected.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
// Extract block timestamps for those keys
|
|
|
|
for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
|
|
|
|
mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off
|
|
|
|
}
|