2015-12-13 14:51:43 +01:00
|
|
|
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
2014-12-13 05:09:33 +01:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
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
2011-07-08 15:47:35 +02:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2020-03-19 23:46:56 +01:00
|
|
|
#include <wallet/crypter.h>
|
2013-04-13 07:13:08 +02:00
|
|
|
|
2020-03-19 23:46:56 +01:00
|
|
|
#include <crypto/aes.h>
|
|
|
|
#include <crypto/sha512.h>
|
2021-06-27 08:33:13 +02:00
|
|
|
#include <util/system.h>
|
2013-11-30 06:09:32 +01:00
|
|
|
|
2013-04-13 07:13:08 +02:00
|
|
|
#include <vector>
|
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
2011-07-08 15:47:35 +02:00
|
|
|
|
2016-06-01 18:22:20 +02:00
|
|
|
int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const
|
|
|
|
{
|
|
|
|
// This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc
|
|
|
|
// cipher and sha512 message digest. Because sha512's output size (64b) is
|
|
|
|
// greater than the aes256 block size (16b) + aes256 key size (32b),
|
|
|
|
// there's no need to process more than once (D_0).
|
|
|
|
|
|
|
|
if(!count || !key || !iv)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unsigned char buf[CSHA512::OUTPUT_SIZE];
|
|
|
|
CSHA512 di;
|
|
|
|
|
2019-10-28 13:41:45 +01:00
|
|
|
di.Write((const unsigned char*)strKeyData.data(), strKeyData.size());
|
2017-09-08 01:11:23 +02:00
|
|
|
di.Write(chSalt.data(), chSalt.size());
|
2016-06-01 18:22:20 +02:00
|
|
|
di.Finalize(buf);
|
|
|
|
|
|
|
|
for(int i = 0; i != count - 1; i++)
|
|
|
|
di.Reset().Write(buf, sizeof(buf)).Finalize(buf);
|
|
|
|
|
|
|
|
memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
|
|
|
|
memcpy(iv, buf + WALLET_CRYPTO_KEY_SIZE, WALLET_CRYPTO_IV_SIZE);
|
|
|
|
memory_cleanse(buf, sizeof(buf));
|
|
|
|
return WALLET_CRYPTO_KEY_SIZE;
|
|
|
|
}
|
|
|
|
|
2011-11-26 07:02:04 +01:00
|
|
|
bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
|
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
2011-07-08 15:47:35 +02:00
|
|
|
{
|
|
|
|
if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
if (nDerivationMethod == 0)
|
2016-11-02 11:16:19 +01:00
|
|
|
i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());
|
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
2011-07-08 15:47:35 +02:00
|
|
|
|
2012-04-15 23:00:20 +02:00
|
|
|
if (i != (int)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
2011-07-08 15:47:35 +02:00
|
|
|
{
|
2016-11-02 11:16:19 +01:00
|
|
|
memory_cleanse(vchKey.data(), vchKey.size());
|
|
|
|
memory_cleanse(vchIV.data(), vchIV.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
2011-07-08 15:47:35 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fKeySet = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
|
|
|
|
{
|
2016-06-01 18:22:20 +02:00
|
|
|
if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_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
2011-07-08 15:47:35 +02:00
|
|
|
return false;
|
|
|
|
|
2016-11-02 11:16:19 +01:00
|
|
|
memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
|
|
|
|
memcpy(vchIV.data(), chNewIV.data(), chNewIV.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
2011-07-08 15:47:35 +02:00
|
|
|
|
|
|
|
fKeySet = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-01 18:22:20 +02:00
|
|
|
bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
|
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
2011-07-08 15:47:35 +02:00
|
|
|
{
|
|
|
|
if (!fKeySet)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// max ciphertext len for a n bytes of plaintext is
|
2016-06-01 18:22:20 +02:00
|
|
|
// n + AES_BLOCKSIZE bytes
|
|
|
|
vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
|
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
2011-07-08 15:47:35 +02:00
|
|
|
|
2016-11-02 11:16:19 +01:00
|
|
|
AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
|
2017-09-08 01:11:23 +02:00
|
|
|
size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), vchCiphertext.data());
|
2016-06-01 18:22:20 +02:00
|
|
|
if(nLen < vchPlaintext.size())
|
|
|
|
return false;
|
|
|
|
vchCiphertext.resize(nLen);
|
2012-04-05 01:02:49 +02:00
|
|
|
|
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
2011-07-08 15:47:35 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-01 18:22:20 +02:00
|
|
|
bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
|
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
2011-07-08 15:47:35 +02:00
|
|
|
{
|
|
|
|
if (!fKeySet)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// plaintext will always be equal to or lesser than length of ciphertext
|
|
|
|
int nLen = vchCiphertext.size();
|
|
|
|
|
2016-06-01 18:22:20 +02:00
|
|
|
vchPlaintext.resize(nLen);
|
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
2011-07-08 15:47:35 +02:00
|
|
|
|
2016-11-02 11:16:19 +01:00
|
|
|
AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
|
2017-09-08 01:11:23 +02:00
|
|
|
nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), &vchPlaintext[0]);
|
2016-06-01 18:22:20 +02:00
|
|
|
if(nLen == 0)
|
|
|
|
return false;
|
|
|
|
vchPlaintext.resize(nLen);
|
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
2011-07-08 15:47:35 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-04 21:37:26 +01:00
|
|
|
static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
|
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
2011-07-08 15:47:35 +02:00
|
|
|
{
|
|
|
|
CCrypter cKeyCrypter;
|
2016-06-01 18:22:20 +02:00
|
|
|
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
|
2017-09-08 01:11:23 +02:00
|
|
|
memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_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
2011-07-08 15:47:35 +02:00
|
|
|
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
|
|
|
|
return false;
|
2013-05-01 06:52:05 +02:00
|
|
|
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
|
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
2011-07-08 15:47:35 +02:00
|
|
|
}
|
|
|
|
|
2014-12-26 12:53:29 +01:00
|
|
|
|
|
|
|
// General secure AES 256 CBC encryption routine
|
|
|
|
bool EncryptAES256(const SecureString& sKey, const SecureString& sPlaintext, const std::string& sIV, std::string& sCiphertext)
|
|
|
|
{
|
|
|
|
// Verify key sizes
|
2017-12-28 23:10:34 +01:00
|
|
|
if(sKey.size() != 32 || sIV.size() != AES_BLOCKSIZE) {
|
2014-12-26 12:53:29 +01:00
|
|
|
LogPrintf("crypter EncryptAES256 - Invalid key or block size: Key: %d sIV:%d\n", sKey.size(), sIV.size());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-28 23:10:34 +01:00
|
|
|
// max ciphertext len for a n bytes of plaintext is
|
|
|
|
// n + AES_BLOCKSIZE bytes
|
|
|
|
sCiphertext.resize(sPlaintext.size() + AES_BLOCKSIZE);
|
2014-12-26 12:53:29 +01:00
|
|
|
|
2017-12-28 23:10:34 +01:00
|
|
|
AES256CBCEncrypt enc((const unsigned char*) &sKey[0], (const unsigned char*) &sIV[0], true);
|
|
|
|
size_t nLen = enc.Encrypt((const unsigned char*) &sPlaintext[0], sPlaintext.size(), (unsigned char*) &sCiphertext[0]);
|
|
|
|
if(nLen < sPlaintext.size())
|
|
|
|
return false;
|
|
|
|
sCiphertext.resize(nLen);
|
2014-12-26 12:53:29 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-04 21:37:26 +01:00
|
|
|
static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
|
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
2011-07-08 15:47:35 +02:00
|
|
|
{
|
|
|
|
CCrypter cKeyCrypter;
|
2016-06-01 18:22:20 +02:00
|
|
|
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
|
2017-09-08 01:11:23 +02:00
|
|
|
memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_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
2011-07-08 15:47:35 +02:00
|
|
|
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
|
|
|
|
return false;
|
|
|
|
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
|
|
|
|
}
|
2013-11-30 06:09:32 +01:00
|
|
|
|
2017-12-28 23:10:34 +01:00
|
|
|
// General secure AES 256 CBC decryption routine
|
2014-12-26 12:53:29 +01:00
|
|
|
bool DecryptAES256(const SecureString& sKey, const std::string& sCiphertext, const std::string& sIV, SecureString& sPlaintext)
|
|
|
|
{
|
|
|
|
// Verify key sizes
|
2017-12-28 23:10:34 +01:00
|
|
|
if(sKey.size() != 32 || sIV.size() != AES_BLOCKSIZE) {
|
2014-12-26 12:53:29 +01:00
|
|
|
LogPrintf("crypter DecryptAES256 - Invalid key or block size\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-28 23:10:34 +01:00
|
|
|
// plaintext will always be equal to or lesser than length of ciphertext
|
|
|
|
int nLen = sCiphertext.size();
|
2014-12-26 12:53:29 +01:00
|
|
|
|
2017-12-28 23:10:34 +01:00
|
|
|
sPlaintext.resize(nLen);
|
2014-12-26 12:53:29 +01:00
|
|
|
|
2017-12-28 23:10:34 +01:00
|
|
|
AES256CBCDecrypt dec((const unsigned char*) &sKey[0], (const unsigned char*) &sIV[0], true);
|
|
|
|
nLen = dec.Decrypt((const unsigned char*) &sCiphertext[0], sCiphertext.size(), (unsigned char*) &sPlaintext[0]);
|
|
|
|
if(nLen == 0)
|
|
|
|
return false;
|
|
|
|
sPlaintext.resize(nLen);
|
2014-12-26 12:53:29 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-04 21:37:26 +01:00
|
|
|
static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
|
|
|
|
{
|
|
|
|
CKeyingMaterial vchSecret;
|
|
|
|
if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vchSecret.size() != 32)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
|
|
|
|
return key.VerifyPubKey(vchPubKey);
|
|
|
|
}
|
|
|
|
|
2013-11-30 06:09:32 +01:00
|
|
|
bool CCryptoKeyStore::SetCrypted()
|
|
|
|
{
|
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
if (fUseCrypto)
|
|
|
|
return true;
|
|
|
|
if (!mapKeys.empty())
|
|
|
|
return false;
|
|
|
|
fUseCrypto = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-02-04 13:33:36 +01:00
|
|
|
// This function should be used in a different combinations to determine
|
|
|
|
// if CCryptoKeyStore is fully locked so that no operations requiring access
|
|
|
|
// to private keys are possible:
|
|
|
|
// IsLocked(true)
|
|
|
|
// or if CCryptoKeyStore's private keys are available for mixing only:
|
|
|
|
// !IsLocked(true) && IsLocked()
|
|
|
|
// or if they are available for everything:
|
|
|
|
// !IsLocked()
|
|
|
|
bool CCryptoKeyStore::IsLocked(bool fForMixing) const
|
|
|
|
{
|
|
|
|
if (!IsCrypted())
|
|
|
|
return false;
|
|
|
|
bool result;
|
|
|
|
{
|
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
result = vMasterKey.empty();
|
|
|
|
}
|
|
|
|
// fForMixing fOnlyMixingAllowed return
|
|
|
|
// ---------------------------------------
|
|
|
|
// true true result
|
|
|
|
// true false result
|
|
|
|
// false true true
|
|
|
|
// false false result
|
|
|
|
|
|
|
|
if(!fForMixing && fOnlyMixingAllowed) return true;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-09-11 11:02:54 +02:00
|
|
|
bool CCryptoKeyStore::Lock(bool fAllowMixing)
|
2013-11-30 06:09:32 +01:00
|
|
|
{
|
|
|
|
if (!SetCrypted())
|
|
|
|
return false;
|
|
|
|
|
2016-09-11 11:02:54 +02:00
|
|
|
if(!fAllowMixing) {
|
2013-11-30 06:09:32 +01:00
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
vMasterKey.clear();
|
|
|
|
}
|
|
|
|
|
2016-09-11 11:02:54 +02:00
|
|
|
fOnlyMixingAllowed = fAllowMixing;
|
2013-11-30 06:09:32 +01:00
|
|
|
NotifyStatusChanged(this);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-01-31 17:07:45 +01:00
|
|
|
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly, bool accept_no_keys)
|
2013-11-30 06:09:32 +01:00
|
|
|
{
|
|
|
|
{
|
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
if (!SetCrypted())
|
|
|
|
return false;
|
|
|
|
|
2019-02-10 20:07:17 +01:00
|
|
|
bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
|
2014-04-06 09:18:52 +02:00
|
|
|
bool keyFail = false;
|
2013-11-30 06:09:32 +01:00
|
|
|
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
|
|
|
|
for (; mi != mapCryptedKeys.end(); ++mi)
|
|
|
|
{
|
|
|
|
const CPubKey &vchPubKey = (*mi).second.first;
|
|
|
|
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
|
|
|
|
CKey key;
|
2014-12-04 21:37:26 +01:00
|
|
|
if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
|
2014-04-06 09:18:52 +02:00
|
|
|
{
|
|
|
|
keyFail = true;
|
2013-11-30 06:09:32 +01:00
|
|
|
break;
|
2014-04-06 09:18:52 +02:00
|
|
|
}
|
|
|
|
keyPass = true;
|
2014-08-10 03:49:07 +02:00
|
|
|
if (fDecryptionThoroughlyChecked)
|
2013-11-30 06:09:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2014-04-06 09:18:52 +02:00
|
|
|
if (keyPass && keyFail)
|
|
|
|
{
|
2015-07-31 16:41:06 +02:00
|
|
|
LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
|
2018-11-14 17:26:51 +01:00
|
|
|
throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
|
2014-04-06 09:18:52 +02:00
|
|
|
}
|
2019-01-31 17:07:45 +01:00
|
|
|
if (keyFail || (!keyPass && cryptedHDChain.IsNull() && !accept_no_keys))
|
2014-04-06 09:18:52 +02:00
|
|
|
return false;
|
2017-05-29 13:51:40 +02:00
|
|
|
|
2013-11-30 06:09:32 +01:00
|
|
|
vMasterKey = vMasterKeyIn;
|
2017-05-29 13:51:40 +02:00
|
|
|
|
|
|
|
if(!cryptedHDChain.IsNull()) {
|
|
|
|
bool chainPass = false;
|
|
|
|
// try to decrypt seed and make sure it matches
|
|
|
|
CHDChain hdChainTmp;
|
|
|
|
if (DecryptHDChain(hdChainTmp)) {
|
|
|
|
// make sure seed matches this chain
|
|
|
|
chainPass = cryptedHDChain.GetID() == hdChainTmp.GetSeedHash();
|
|
|
|
}
|
|
|
|
if (!chainPass) {
|
|
|
|
vMasterKey.clear();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2014-08-10 03:49:07 +02:00
|
|
|
fDecryptionThoroughlyChecked = true;
|
2013-11-30 06:09:32 +01:00
|
|
|
}
|
2016-09-11 11:02:54 +02:00
|
|
|
fOnlyMixingAllowed = fForMixingOnly;
|
2013-11-30 06:09:32 +01:00
|
|
|
NotifyStatusChanged(this);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
|
|
|
|
{
|
2020-02-04 13:33:36 +01:00
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
if (!IsCrypted()) {
|
|
|
|
return CBasicKeyStore::AddKeyPubKey(key, pubkey);
|
|
|
|
}
|
2013-11-30 06:09:32 +01:00
|
|
|
|
2020-02-04 13:33:36 +01:00
|
|
|
if (IsLocked(true)) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-11-30 06:09:32 +01:00
|
|
|
|
2020-02-04 13:33:36 +01:00
|
|
|
std::vector<unsigned char> vchCryptedSecret;
|
|
|
|
CKeyingMaterial vchSecret(key.begin(), key.end());
|
|
|
|
if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-11-30 06:09:32 +01:00
|
|
|
|
2020-02-04 13:33:36 +01:00
|
|
|
if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
|
|
|
|
return false;
|
2013-11-30 06:09:32 +01:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
|
|
|
|
{
|
2020-02-04 13:33:36 +01:00
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
if (!SetCrypted()) {
|
|
|
|
return false;
|
2013-11-30 06:09:32 +01:00
|
|
|
}
|
2020-02-04 13:33:36 +01:00
|
|
|
|
|
|
|
mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
|
2013-11-30 06:09:32 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-02-04 13:33:36 +01:00
|
|
|
bool CCryptoKeyStore::HaveKey(const CKeyID &address) const
|
|
|
|
{
|
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
if (!IsCrypted()) {
|
|
|
|
return CBasicKeyStore::HaveKey(address);
|
|
|
|
}
|
|
|
|
return mapCryptedKeys.count(address) > 0;
|
|
|
|
}
|
|
|
|
|
2013-11-30 06:09:32 +01:00
|
|
|
bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
|
|
|
|
{
|
2020-02-04 13:33:36 +01:00
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
if (!IsCrypted()) {
|
|
|
|
return CBasicKeyStore::GetKey(address, keyOut);
|
|
|
|
}
|
2013-11-30 06:09:32 +01:00
|
|
|
|
2020-02-04 13:33:36 +01:00
|
|
|
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
|
|
|
|
if (mi != mapCryptedKeys.end())
|
|
|
|
{
|
|
|
|
const CPubKey &vchPubKey = (*mi).second.first;
|
|
|
|
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
|
|
|
|
return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
|
2013-11-30 06:09:32 +01:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
|
|
|
|
{
|
2020-02-04 13:33:36 +01:00
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
if (!IsCrypted())
|
|
|
|
return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
|
|
|
|
|
|
|
|
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
|
|
|
|
if (mi != mapCryptedKeys.end())
|
2013-11-30 06:09:32 +01:00
|
|
|
{
|
2020-02-04 13:33:36 +01:00
|
|
|
vchPubKeyOut = (*mi).second.first;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Check for watch-only pubkeys
|
|
|
|
return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
|
|
|
|
}
|
2013-11-30 06:09:32 +01:00
|
|
|
|
2020-02-04 13:33:36 +01:00
|
|
|
std::set<CKeyID> CCryptoKeyStore::GetKeys() const
|
|
|
|
{
|
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
if (!IsCrypted()) {
|
|
|
|
return CBasicKeyStore::GetKeys();
|
|
|
|
}
|
|
|
|
std::set<CKeyID> set_address;
|
|
|
|
for (const auto& mi : mapCryptedKeys) {
|
|
|
|
set_address.insert(mi.first);
|
2013-11-30 06:09:32 +01:00
|
|
|
}
|
2020-02-04 13:33:36 +01:00
|
|
|
return set_address;
|
2013-11-30 06:09:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
|
|
|
|
{
|
2020-02-04 13:33:36 +01:00
|
|
|
LOCK(cs_KeyStore);
|
|
|
|
if (!mapCryptedKeys.empty() || IsCrypted())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
fUseCrypto = true;
|
2018-09-04 15:36:09 +02:00
|
|
|
for (const KeyMap::value_type& mKey : mapKeys)
|
2013-11-30 06:09:32 +01:00
|
|
|
{
|
2020-02-04 13:33:36 +01:00
|
|
|
const CKey &key = mKey.second;
|
|
|
|
CPubKey vchPubKey = key.GetPubKey();
|
|
|
|
CKeyingMaterial vchSecret(key.begin(), key.end());
|
|
|
|
std::vector<unsigned char> vchCryptedSecret;
|
|
|
|
if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
|
|
|
|
return false;
|
|
|
|
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
|
2013-11-30 06:09:32 +01:00
|
|
|
return false;
|
|
|
|
}
|
2020-02-04 13:33:36 +01:00
|
|
|
mapKeys.clear();
|
2013-11-30 06:09:32 +01:00
|
|
|
return true;
|
|
|
|
}
|
2017-05-29 13:51:40 +02:00
|
|
|
|
2021-01-25 04:03:33 +01:00
|
|
|
bool CCryptoKeyStore::EncryptHDChain(const CKeyingMaterial& vMasterKeyIn, const CHDChain& chain)
|
2017-05-29 13:51:40 +02:00
|
|
|
{
|
2020-07-18 14:34:09 +02:00
|
|
|
LOCK(cs_KeyStore);
|
2017-05-29 13:51:40 +02:00
|
|
|
// should call EncryptKeys first
|
|
|
|
if (!IsCrypted())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!cryptedHDChain.IsNull())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (cryptedHDChain.IsCrypted())
|
|
|
|
return true;
|
|
|
|
|
2021-01-25 04:03:33 +01:00
|
|
|
if (hdChain.IsNull() && !chain.IsNull()) {
|
|
|
|
// Encrypting a new HDChain for an already encrypted non-HD wallet
|
|
|
|
hdChain = chain;
|
|
|
|
}
|
|
|
|
|
2017-05-29 13:51:40 +02:00
|
|
|
// make sure seed matches this chain
|
|
|
|
if (hdChain.GetID() != hdChain.GetSeedHash())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::vector<unsigned char> vchCryptedSeed;
|
|
|
|
if (!EncryptSecret(vMasterKeyIn, hdChain.GetSeed(), hdChain.GetID(), vchCryptedSeed))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
hdChain.Debug(__func__);
|
|
|
|
cryptedHDChain = hdChain;
|
|
|
|
cryptedHDChain.SetCrypted(true);
|
|
|
|
|
|
|
|
SecureVector vchSecureCryptedSeed(vchCryptedSeed.begin(), vchCryptedSeed.end());
|
|
|
|
if (!cryptedHDChain.SetSeed(vchSecureCryptedSeed, false))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SecureVector vchMnemonic;
|
|
|
|
SecureVector vchMnemonicPassphrase;
|
|
|
|
|
|
|
|
// it's ok to have no mnemonic if wallet was initialized via hdseed
|
|
|
|
if (hdChain.GetMnemonic(vchMnemonic, vchMnemonicPassphrase)) {
|
|
|
|
std::vector<unsigned char> vchCryptedMnemonic;
|
|
|
|
std::vector<unsigned char> vchCryptedMnemonicPassphrase;
|
|
|
|
|
|
|
|
if (!vchMnemonic.empty() && !EncryptSecret(vMasterKeyIn, vchMnemonic, hdChain.GetID(), vchCryptedMnemonic))
|
|
|
|
return false;
|
|
|
|
if (!vchMnemonicPassphrase.empty() && !EncryptSecret(vMasterKeyIn, vchMnemonicPassphrase, hdChain.GetID(), vchCryptedMnemonicPassphrase))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SecureVector vchSecureCryptedMnemonic(vchCryptedMnemonic.begin(), vchCryptedMnemonic.end());
|
|
|
|
SecureVector vchSecureCryptedMnemonicPassphrase(vchCryptedMnemonicPassphrase.begin(), vchCryptedMnemonicPassphrase.end());
|
|
|
|
if (!cryptedHDChain.SetMnemonic(vchSecureCryptedMnemonic, vchSecureCryptedMnemonicPassphrase, false))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hdChain.SetNull())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCryptoKeyStore::DecryptHDChain(CHDChain& hdChainRet) const
|
|
|
|
{
|
2020-07-18 14:34:09 +02:00
|
|
|
LOCK(cs_KeyStore);
|
2017-05-29 13:51:40 +02:00
|
|
|
if (!IsCrypted())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (cryptedHDChain.IsNull())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!cryptedHDChain.IsCrypted())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SecureVector vchSecureSeed;
|
|
|
|
SecureVector vchSecureCryptedSeed = cryptedHDChain.GetSeed();
|
|
|
|
std::vector<unsigned char> vchCryptedSeed(vchSecureCryptedSeed.begin(), vchSecureCryptedSeed.end());
|
|
|
|
if (!DecryptSecret(vMasterKey, vchCryptedSeed, cryptedHDChain.GetID(), vchSecureSeed))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
hdChainRet = cryptedHDChain;
|
|
|
|
if (!hdChainRet.SetSeed(vchSecureSeed, false))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// hash of decrypted seed must match chain id
|
|
|
|
if (hdChainRet.GetSeedHash() != cryptedHDChain.GetID())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SecureVector vchSecureCryptedMnemonic;
|
|
|
|
SecureVector vchSecureCryptedMnemonicPassphrase;
|
|
|
|
|
|
|
|
// it's ok to have no mnemonic if wallet was initialized via hdseed
|
|
|
|
if (cryptedHDChain.GetMnemonic(vchSecureCryptedMnemonic, vchSecureCryptedMnemonicPassphrase)) {
|
|
|
|
SecureVector vchSecureMnemonic;
|
|
|
|
SecureVector vchSecureMnemonicPassphrase;
|
|
|
|
|
|
|
|
std::vector<unsigned char> vchCryptedMnemonic(vchSecureCryptedMnemonic.begin(), vchSecureCryptedMnemonic.end());
|
|
|
|
std::vector<unsigned char> vchCryptedMnemonicPassphrase(vchSecureCryptedMnemonicPassphrase.begin(), vchSecureCryptedMnemonicPassphrase.end());
|
|
|
|
|
|
|
|
if (!vchCryptedMnemonic.empty() && !DecryptSecret(vMasterKey, vchCryptedMnemonic, cryptedHDChain.GetID(), vchSecureMnemonic))
|
|
|
|
return false;
|
|
|
|
if (!vchCryptedMnemonicPassphrase.empty() && !DecryptSecret(vMasterKey, vchCryptedMnemonicPassphrase, cryptedHDChain.GetID(), vchSecureMnemonicPassphrase))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!hdChainRet.SetMnemonic(vchSecureMnemonic, vchSecureMnemonicPassphrase, false))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
hdChainRet.SetCrypted(false);
|
|
|
|
hdChainRet.Debug(__func__);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCryptoKeyStore::SetHDChain(const CHDChain& chain)
|
|
|
|
{
|
2020-07-18 14:34:09 +02:00
|
|
|
LOCK(cs_KeyStore);
|
2017-05-29 13:51:40 +02:00
|
|
|
if (IsCrypted())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (chain.IsCrypted())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
hdChain = chain;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCryptoKeyStore::SetCryptedHDChain(const CHDChain& chain)
|
|
|
|
{
|
2020-07-18 14:34:09 +02:00
|
|
|
LOCK(cs_KeyStore);
|
2017-05-29 13:51:40 +02:00
|
|
|
if (!SetCrypted())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!chain.IsCrypted())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
cryptedHDChain = chain;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCryptoKeyStore::GetHDChain(CHDChain& hdChainRet) const
|
|
|
|
{
|
2020-07-18 14:34:09 +02:00
|
|
|
LOCK(cs_KeyStore);
|
2017-05-29 13:51:40 +02:00
|
|
|
if(IsCrypted()) {
|
|
|
|
hdChainRet = cryptedHDChain;
|
|
|
|
return !cryptedHDChain.IsNull();
|
|
|
|
}
|
|
|
|
|
|
|
|
hdChainRet = hdChain;
|
|
|
|
return !hdChain.IsNull();
|
|
|
|
}
|