Merge pull request #4103

bcab579 wallet: allow adjusting number of rounds for the key derivation function (stoffu)
This commit is contained in:
luigi1111 2018-08-15 17:09:52 -05:00
commit 017e07a035
No known key found for this signature in database
GPG Key ID: F4ACA0183641E010
14 changed files with 76 additions and 52 deletions

View File

@ -69,22 +69,26 @@ namespace crypto {
chacha20(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher); chacha20(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher);
} }
inline void generate_chacha_key(const void *data, size_t size, chacha_key& key) { inline void generate_chacha_key(const void *data, size_t size, chacha_key& key, uint64_t kdf_rounds) {
static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key"); static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key");
tools::scrubbed_arr<char, HASH_SIZE> pwd_hash; tools::scrubbed_arr<char, HASH_SIZE> pwd_hash;
crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 0/*prehashed*/); crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 0/*prehashed*/);
for (uint64_t n = 1; n < kdf_rounds; ++n)
crypto::cn_slow_hash(pwd_hash.data(), pwd_hash.size(), pwd_hash.data(), 0/*variant*/, 0/*prehashed*/);
memcpy(&unwrap(key), pwd_hash.data(), sizeof(key)); memcpy(&unwrap(key), pwd_hash.data(), sizeof(key));
} }
inline void generate_chacha_key_prehashed(const void *data, size_t size, chacha_key& key) { inline void generate_chacha_key_prehashed(const void *data, size_t size, chacha_key& key, uint64_t kdf_rounds) {
static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key"); static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key");
tools::scrubbed_arr<char, HASH_SIZE> pwd_hash; tools::scrubbed_arr<char, HASH_SIZE> pwd_hash;
crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 1/*prehashed*/); crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 1/*prehashed*/);
for (uint64_t n = 1; n < kdf_rounds; ++n)
crypto::cn_slow_hash(pwd_hash.data(), pwd_hash.size(), pwd_hash.data(), 0/*variant*/, 0/*prehashed*/);
memcpy(&unwrap(key), pwd_hash.data(), sizeof(key)); memcpy(&unwrap(key), pwd_hash.data(), sizeof(key));
} }
inline void generate_chacha_key(std::string password, chacha_key& key) { inline void generate_chacha_key(std::string password, chacha_key& key, uint64_t kdf_rounds) {
return generate_chacha_key(password.data(), password.size(), key); return generate_chacha_key(password.data(), password.size(), key, kdf_rounds);
} }
} }

View File

@ -125,7 +125,7 @@ namespace hw {
/* ======================================================================= */ /* ======================================================================= */
virtual bool get_public_address(cryptonote::account_public_address &pubkey) = 0; virtual bool get_public_address(cryptonote::account_public_address &pubkey) = 0;
virtual bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) = 0; virtual bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) = 0;
virtual bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) = 0; virtual bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) = 0;
/* ======================================================================= */ /* ======================================================================= */
/* SUB ADDRESS */ /* SUB ADDRESS */

View File

@ -100,14 +100,14 @@ namespace hw {
/* WALLET & ADDRESS */ /* WALLET & ADDRESS */
/* ======================================================================= */ /* ======================================================================= */
bool device_default::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) { bool device_default::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) {
const crypto::secret_key &view_key = keys.m_view_secret_key; const crypto::secret_key &view_key = keys.m_view_secret_key;
const crypto::secret_key &spend_key = keys.m_spend_secret_key; const crypto::secret_key &spend_key = keys.m_spend_secret_key;
tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data; tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data;
memcpy(data.data(), &view_key, sizeof(view_key)); memcpy(data.data(), &view_key, sizeof(view_key));
memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key)); memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key));
data[sizeof(data) - 1] = CHACHA8_KEY_TAIL; data[sizeof(data) - 1] = CHACHA8_KEY_TAIL;
crypto::generate_chacha_key(data.data(), sizeof(data), key); crypto::generate_chacha_key(data.data(), sizeof(data), key, kdf_rounds);
return true; return true;
} }
bool device_default::get_public_address(cryptonote::account_public_address &pubkey) { bool device_default::get_public_address(cryptonote::account_public_address &pubkey) {

View File

@ -73,7 +73,7 @@ namespace hw {
/* ======================================================================= */ /* ======================================================================= */
bool get_public_address(cryptonote::account_public_address &pubkey) override; bool get_public_address(cryptonote::account_public_address &pubkey) override;
bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override; bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override;
bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override; bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) override;
/* ======================================================================= */ /* ======================================================================= */
/* SUB ADDRESS */ /* SUB ADDRESS */

View File

@ -531,20 +531,20 @@ namespace hw {
return true; return true;
} }
bool device_ledger::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) { bool device_ledger::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) {
AUTO_LOCK_CMD(); AUTO_LOCK_CMD();
#ifdef DEBUG_HWDEVICE #ifdef DEBUG_HWDEVICE
crypto::chacha_key key_x; crypto::chacha_key key_x;
cryptonote::account_keys keys_x = hw::ledger::decrypt(keys); cryptonote::account_keys keys_x = hw::ledger::decrypt(keys);
this->controle_device->generate_chacha_key(keys_x, key_x); this->controle_device->generate_chacha_key(keys_x, key_x, kdf_rounds);
#endif #endif
send_simple(INS_GET_CHACHA8_PREKEY); send_simple(INS_GET_CHACHA8_PREKEY);
char prekey[200]; char prekey[200];
memmove(prekey, &this->buffer_recv[0], 200); memmove(prekey, &this->buffer_recv[0], 200);
crypto::generate_chacha_key_prehashed(&prekey[0], sizeof(prekey), key); crypto::generate_chacha_key_prehashed(&prekey[0], sizeof(prekey), key, kdf_rounds);
#ifdef DEBUG_HWDEVICE #ifdef DEBUG_HWDEVICE
hw::ledger::check32("generate_chacha_key_prehashed", "key", (char*)key_x.data(), (char*)key.data()); hw::ledger::check32("generate_chacha_key_prehashed", "key", (char*)key_x.data(), (char*)key.data());

View File

@ -156,7 +156,7 @@ namespace hw {
/* ======================================================================= */ /* ======================================================================= */
bool get_public_address(cryptonote::account_public_address &pubkey) override; bool get_public_address(cryptonote::account_public_address &pubkey) override;
bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override; bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override;
bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override; bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) override;
/* ======================================================================= */ /* ======================================================================= */

View File

@ -366,7 +366,7 @@ void Wallet::error(const std::string &category, const std::string &str) {
} }
///////////////////////// WalletImpl implementation //////////////////////// ///////////////////////// WalletImpl implementation ////////////////////////
WalletImpl::WalletImpl(NetworkType nettype) WalletImpl::WalletImpl(NetworkType nettype, bool restricted, uint64_t kdf_rounds)
:m_wallet(nullptr) :m_wallet(nullptr)
, m_status(Wallet::Status_Ok) , m_status(Wallet::Status_Ok)
, m_trustedDaemon(false) , m_trustedDaemon(false)
@ -377,7 +377,7 @@ WalletImpl::WalletImpl(NetworkType nettype)
, m_rebuildWalletCache(false) , m_rebuildWalletCache(false)
, m_is_connected(false) , m_is_connected(false)
{ {
m_wallet = new tools::wallet2(static_cast<cryptonote::network_type>(nettype)); m_wallet = new tools::wallet2(static_cast<cryptonote::network_type>(nettype), restricted, kdf_rounds);
m_history = new TransactionHistoryImpl(this); m_history = new TransactionHistoryImpl(this);
m_wallet2Callback = new Wallet2CallbackImpl(this); m_wallet2Callback = new Wallet2CallbackImpl(this);
m_wallet->callback(m_wallet2Callback); m_wallet->callback(m_wallet2Callback);

View File

@ -52,7 +52,7 @@ struct Wallet2CallbackImpl;
class WalletImpl : public Wallet class WalletImpl : public Wallet
{ {
public: public:
WalletImpl(NetworkType nettype = MAINNET); WalletImpl(NetworkType nettype = MAINNET, bool restricted = false, uint64_t kdf_rounds = 1);
~WalletImpl(); ~WalletImpl();
bool create(const std::string &path, const std::string &password, bool create(const std::string &path, const std::string &password,
const std::string &language); const std::string &language);

View File

@ -920,9 +920,10 @@ struct WalletManager
* \param password Password of wallet file * \param password Password of wallet file
* \param language Language to be used to generate electrum seed mnemonic * \param language Language to be used to generate electrum seed mnemonic
* \param nettype Network type * \param nettype Network type
* \param kdf_rounds Number of rounds for key derivation function
* \return Wallet instance (Wallet::status() needs to be called to check if created successfully) * \return Wallet instance (Wallet::status() needs to be called to check if created successfully)
*/ */
virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, NetworkType nettype) = 0; virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, NetworkType nettype, uint64_t kdf_rounds = 1) = 0;
Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet = false) // deprecated Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet = false) // deprecated
{ {
return createWallet(path, password, language, testnet ? TESTNET : MAINNET); return createWallet(path, password, language, testnet ? TESTNET : MAINNET);
@ -933,9 +934,10 @@ struct WalletManager
* \param path Name of wallet file * \param path Name of wallet file
* \param password Password of wallet file * \param password Password of wallet file
* \param nettype Network type * \param nettype Network type
* \param kdf_rounds Number of rounds for key derivation function
* \return Wallet instance (Wallet::status() needs to be called to check if opened successfully) * \return Wallet instance (Wallet::status() needs to be called to check if opened successfully)
*/ */
virtual Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype) = 0; virtual Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1) = 0;
Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) // deprecated Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) // deprecated
{ {
return openWallet(path, password, testnet ? TESTNET : MAINNET); return openWallet(path, password, testnet ? TESTNET : MAINNET);
@ -948,10 +950,11 @@ struct WalletManager
* \param mnemonic mnemonic (25 words electrum seed) * \param mnemonic mnemonic (25 words electrum seed)
* \param nettype Network type * \param nettype Network type
* \param restoreHeight restore from start height * \param restoreHeight restore from start height
* \param kdf_rounds Number of rounds for key derivation function
* \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully)
*/ */
virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic,
NetworkType nettype = MAINNET, uint64_t restoreHeight = 0) = 0; NetworkType nettype = MAINNET, uint64_t restoreHeight = 0, uint64_t kdf_rounds = 1) = 0;
Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic,
bool testnet = false, uint64_t restoreHeight = 0) // deprecated bool testnet = false, uint64_t restoreHeight = 0) // deprecated
{ {
@ -983,6 +986,7 @@ struct WalletManager
* \param addressString public address * \param addressString public address
* \param viewKeyString view key * \param viewKeyString view key
* \param spendKeyString spend key (optional) * \param spendKeyString spend key (optional)
* \param kdf_rounds Number of rounds for key derivation function
* \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully)
*/ */
virtual Wallet * createWalletFromKeys(const std::string &path, virtual Wallet * createWalletFromKeys(const std::string &path,
@ -992,7 +996,8 @@ struct WalletManager
uint64_t restoreHeight, uint64_t restoreHeight,
const std::string &addressString, const std::string &addressString,
const std::string &viewKeyString, const std::string &viewKeyString,
const std::string &spendKeyString = "") = 0; const std::string &spendKeyString = "",
uint64_t kdf_rounds = 1) = 0;
Wallet * createWalletFromKeys(const std::string &path, Wallet * createWalletFromKeys(const std::string &path,
const std::string &password, const std::string &password,
const std::string &language, const std::string &language,
@ -1043,6 +1048,7 @@ struct WalletManager
* \param deviceName Device name * \param deviceName Device name
* \param restoreHeight restore from start height (0 sets to current height) * \param restoreHeight restore from start height (0 sets to current height)
* \param subaddressLookahead Size of subaddress lookahead (empty sets to some default low value) * \param subaddressLookahead Size of subaddress lookahead (empty sets to some default low value)
* \param kdf_rounds Number of rounds for key derivation function
* \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully)
*/ */
virtual Wallet * createWalletFromDevice(const std::string &path, virtual Wallet * createWalletFromDevice(const std::string &path,
@ -1050,7 +1056,8 @@ struct WalletManager
NetworkType nettype, NetworkType nettype,
const std::string &deviceName, const std::string &deviceName,
uint64_t restoreHeight = 0, uint64_t restoreHeight = 0,
const std::string &subaddressLookahead = "") = 0; const std::string &subaddressLookahead = "",
uint64_t kdf_rounds = 1) = 0;
/*! /*!
* \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted * \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted
@ -1075,13 +1082,14 @@ struct WalletManager
* @param keys_file_name - location of keys file * @param keys_file_name - location of keys file
* @param password - password to verify * @param password - password to verify
* @param no_spend_key - verify only view keys? * @param no_spend_key - verify only view keys?
* @param kdf_rounds - number of rounds for key derivation function
* @return - true if password is correct * @return - true if password is correct
* *
* @note * @note
* This function will fail when the wallet keys file is opened because the wallet program locks the keys file. * This function will fail when the wallet keys file is opened because the wallet program locks the keys file.
* In this case, Wallet::unlockKeysFile() and Wallet::lockKeysFile() need to be called before and after the call to this function, respectively. * In this case, Wallet::unlockKeysFile() and Wallet::lockKeysFile() need to be called before and after the call to this function, respectively.
*/ */
virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const = 0; virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const = 0;
/*! /*!
* \brief findWallets - searches for the wallet files by given path name recursively * \brief findWallets - searches for the wallet files by given path name recursively

View File

@ -50,16 +50,16 @@ namespace epee {
namespace Monero { namespace Monero {
Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password, Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password,
const std::string &language, NetworkType nettype) const std::string &language, NetworkType nettype, uint64_t kdf_rounds)
{ {
WalletImpl * wallet = new WalletImpl(nettype); WalletImpl * wallet = new WalletImpl(nettype, false, kdf_rounds);
wallet->create(path, password, language); wallet->create(path, password, language);
return wallet; return wallet;
} }
Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, NetworkType nettype) Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds)
{ {
WalletImpl * wallet = new WalletImpl(nettype); WalletImpl * wallet = new WalletImpl(nettype, false, kdf_rounds);
wallet->open(path, password); wallet->open(path, password);
//Refresh addressBook //Refresh addressBook
wallet->addressBook()->refresh(); wallet->addressBook()->refresh();
@ -87,9 +87,10 @@ Wallet *WalletManagerImpl::recoveryWallet(const std::string &path,
const std::string &password, const std::string &password,
const std::string &mnemonic, const std::string &mnemonic,
NetworkType nettype, NetworkType nettype,
uint64_t restoreHeight) uint64_t restoreHeight,
uint64_t kdf_rounds)
{ {
WalletImpl * wallet = new WalletImpl(nettype); WalletImpl * wallet = new WalletImpl(nettype, false, kdf_rounds);
if(restoreHeight > 0){ if(restoreHeight > 0){
wallet->setRefreshFromBlockHeight(restoreHeight); wallet->setRefreshFromBlockHeight(restoreHeight);
} }
@ -104,9 +105,10 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path,
uint64_t restoreHeight, uint64_t restoreHeight,
const std::string &addressString, const std::string &addressString,
const std::string &viewKeyString, const std::string &viewKeyString,
const std::string &spendKeyString) const std::string &spendKeyString,
uint64_t kdf_rounds)
{ {
WalletImpl * wallet = new WalletImpl(nettype); WalletImpl * wallet = new WalletImpl(nettype, false, kdf_rounds);
if(restoreHeight > 0){ if(restoreHeight > 0){
wallet->setRefreshFromBlockHeight(restoreHeight); wallet->setRefreshFromBlockHeight(restoreHeight);
} }
@ -119,9 +121,10 @@ Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path,
NetworkType nettype, NetworkType nettype,
const std::string &deviceName, const std::string &deviceName,
uint64_t restoreHeight, uint64_t restoreHeight,
const std::string &subaddressLookahead) const std::string &subaddressLookahead,
uint64_t kdf_rounds)
{ {
WalletImpl * wallet = new WalletImpl(nettype); WalletImpl * wallet = new WalletImpl(nettype, false, kdf_rounds);
if(restoreHeight > 0){ if(restoreHeight > 0){
wallet->setRefreshFromBlockHeight(restoreHeight); wallet->setRefreshFromBlockHeight(restoreHeight);
} }
@ -159,9 +162,9 @@ bool WalletManagerImpl::walletExists(const std::string &path)
return false; return false;
} }
bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds) const
{ {
return tools::wallet2::verify_password(keys_file_name, password, no_spend_key, hw::get_device("default")); return tools::wallet2::verify_password(keys_file_name, password, no_spend_key, hw::get_device("default"), kdf_rounds);
} }
std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path) std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path)

View File

@ -39,13 +39,14 @@ class WalletManagerImpl : public WalletManager
{ {
public: public:
Wallet * createWallet(const std::string &path, const std::string &password, Wallet * createWallet(const std::string &path, const std::string &password,
const std::string &language, NetworkType nettype) override; const std::string &language, NetworkType nettype, uint64_t kdf_rounds = 1) override;
Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype) override; Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1) override;
virtual Wallet * recoveryWallet(const std::string &path, virtual Wallet * recoveryWallet(const std::string &path,
const std::string &password, const std::string &password,
const std::string &mnemonic, const std::string &mnemonic,
NetworkType nettype, NetworkType nettype,
uint64_t restoreHeight) override; uint64_t restoreHeight,
uint64_t kdf_rounds = 1) override;
virtual Wallet * createWalletFromKeys(const std::string &path, virtual Wallet * createWalletFromKeys(const std::string &path,
const std::string &password, const std::string &password,
const std::string &language, const std::string &language,
@ -53,7 +54,8 @@ public:
uint64_t restoreHeight, uint64_t restoreHeight,
const std::string &addressString, const std::string &addressString,
const std::string &viewKeyString, const std::string &viewKeyString,
const std::string &spendKeyString = "") override; const std::string &spendKeyString = "",
uint64_t kdf_rounds = 1) override;
// next two methods are deprecated - use the above version which allow setting of a password // next two methods are deprecated - use the above version which allow setting of a password
virtual Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, NetworkType nettype, uint64_t restoreHeight) override; virtual Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, NetworkType nettype, uint64_t restoreHeight) override;
// deprecated: use createWalletFromKeys(..., password, ...) instead // deprecated: use createWalletFromKeys(..., password, ...) instead
@ -69,10 +71,11 @@ public:
NetworkType nettype, NetworkType nettype,
const std::string &deviceName, const std::string &deviceName,
uint64_t restoreHeight = 0, uint64_t restoreHeight = 0,
const std::string &subaddressLookahead = "") override; const std::string &subaddressLookahead = "",
uint64_t kdf_rounds = 1) override;
virtual bool closeWallet(Wallet *wallet, bool store = true) override; virtual bool closeWallet(Wallet *wallet, bool store = true) override;
bool walletExists(const std::string &path) override; bool walletExists(const std::string &path) override;
bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const override; bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const override;
std::vector<std::string> findWallets(const std::string &path) override; std::vector<std::string> findWallets(const std::string &path) override;
std::string errorString() const override; std::string errorString() const override;
void setDaemonAddress(const std::string &address) override; void setDaemonAddress(const std::string &address) override;

View File

@ -160,6 +160,7 @@ struct options {
return val; return val;
} }
}; };
const command_line::arg_descriptor<uint64_t> kdf_rounds = {"kdf-rounds", tools::wallet2::tr("Number of rounds for the key derivation function"), 1};
}; };
void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file) void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file)
@ -203,6 +204,8 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
const bool stagenet = command_line::get_arg(vm, opts.stagenet); const bool stagenet = command_line::get_arg(vm, opts.stagenet);
const network_type nettype = testnet ? TESTNET : stagenet ? STAGENET : MAINNET; const network_type nettype = testnet ? TESTNET : stagenet ? STAGENET : MAINNET;
const bool restricted = command_line::get_arg(vm, opts.restricted); const bool restricted = command_line::get_arg(vm, opts.restricted);
const uint64_t kdf_rounds = command_line::get_arg(vm, opts.kdf_rounds);
THROW_WALLET_EXCEPTION_IF(kdf_rounds == 0, tools::error::wallet_internal_error, "KDF rounds must not be 0");
auto daemon_address = command_line::get_arg(vm, opts.daemon_address); auto daemon_address = command_line::get_arg(vm, opts.daemon_address);
auto daemon_host = command_line::get_arg(vm, opts.daemon_host); auto daemon_host = command_line::get_arg(vm, opts.daemon_host);
@ -236,7 +239,7 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
if (daemon_address.empty()) if (daemon_address.empty())
daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port); daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port);
std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(nettype, restricted)); std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(nettype, restricted, kdf_rounds));
wallet->init(std::move(daemon_address), std::move(login)); wallet->init(std::move(daemon_address), std::move(login));
boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir); boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir);
wallet->set_ring_database(ringdb_path.string()); wallet->set_ring_database(ringdb_path.string());
@ -647,7 +650,7 @@ const size_t MAX_SPLIT_ATTEMPTS = 30;
constexpr const std::chrono::seconds wallet2::rpc_timeout; constexpr const std::chrono::seconds wallet2::rpc_timeout;
const char* wallet2::tr(const char* str) { return i18n_translate(str, "tools::wallet2"); } const char* wallet2::tr(const char* str) { return i18n_translate(str, "tools::wallet2"); }
wallet2::wallet2(network_type nettype, bool restricted): wallet2::wallet2(network_type nettype, bool restricted, uint64_t kdf_rounds):
m_multisig_rescan_info(NULL), m_multisig_rescan_info(NULL),
m_multisig_rescan_k(NULL), m_multisig_rescan_k(NULL),
m_run(true), m_run(true),
@ -679,6 +682,7 @@ wallet2::wallet2(network_type nettype, bool restricted):
m_ignore_fractional_outputs(true), m_ignore_fractional_outputs(true),
m_is_initialized(false), m_is_initialized(false),
m_restricted(restricted), m_restricted(restricted),
m_kdf_rounds(kdf_rounds),
is_old_file_format(false), is_old_file_format(false),
m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex),
m_subaddress_lookahead_major(SUBADDRESS_LOOKAHEAD_MAJOR), m_subaddress_lookahead_major(SUBADDRESS_LOOKAHEAD_MAJOR),
@ -723,6 +727,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
command_line::add_arg(desc_params, opts.stagenet); command_line::add_arg(desc_params, opts.stagenet);
command_line::add_arg(desc_params, opts.restricted); command_line::add_arg(desc_params, opts.restricted);
command_line::add_arg(desc_params, opts.shared_ringdb_dir); command_line::add_arg(desc_params, opts.shared_ringdb_dir);
command_line::add_arg(desc_params, opts.kdf_rounds);
} }
std::unique_ptr<wallet2> wallet2::make_from_json(const boost::program_options::variables_map& vm, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) std::unique_ptr<wallet2> wallet2::make_from_json(const boost::program_options::variables_map& vm, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter)
@ -2844,7 +2849,7 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
// Encrypt the entire JSON object. // Encrypt the entire JSON object.
crypto::chacha_key key; crypto::chacha_key key;
crypto::generate_chacha_key(password.data(), password.size(), key); crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
std::string cipher; std::string cipher;
cipher.resize(account_data.size()); cipher.resize(account_data.size());
keys_file_data.iv = crypto::rand<crypto::chacha_iv>(); keys_file_data.iv = crypto::rand<crypto::chacha_iv>();
@ -2878,7 +2883,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
r = ::serialization::parse_binary(buf, keys_file_data); r = ::serialization::parse_binary(buf, keys_file_data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"'); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
crypto::chacha_key key; crypto::chacha_key key;
crypto::generate_chacha_key(password.data(), password.size(), key); crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
std::string account_data; std::string account_data;
account_data.resize(keys_file_data.account_data.size()); account_data.resize(keys_file_data.account_data.size());
crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
@ -3084,7 +3089,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password)
{ {
// this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded). // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded).
unlock_keys_file(); unlock_keys_file();
bool r = verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device()); bool r = verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device(), m_kdf_rounds);
lock_keys_file(); lock_keys_file();
return r; return r;
} }
@ -3102,7 +3107,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password)
* can be used prior to rewriting wallet keys file, to ensure user has entered the correct password * can be used prior to rewriting wallet keys file, to ensure user has entered the correct password
* *
*/ */
bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev) bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds)
{ {
rapidjson::Document json; rapidjson::Document json;
wallet2::keys_file_data keys_file_data; wallet2::keys_file_data keys_file_data;
@ -3114,7 +3119,7 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip
r = ::serialization::parse_binary(buf, keys_file_data); r = ::serialization::parse_binary(buf, keys_file_data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"'); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
crypto::chacha_key key; crypto::chacha_key key;
crypto::generate_chacha_key(password.data(), password.size(), key); crypto::generate_chacha_key(password.data(), password.size(), key, kdf_rounds);
std::string account_data; std::string account_data;
account_data.resize(keys_file_data.account_data.size()); account_data.resize(keys_file_data.account_data.size());
crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
@ -3982,7 +3987,7 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout)
bool wallet2::generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const bool wallet2::generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const
{ {
hw::device &hwdev = m_account.get_device(); hw::device &hwdev = m_account.get_device();
return hwdev.generate_chacha_key(m_account.get_keys(), key); return hwdev.generate_chacha_key(m_account.get_keys(), key, m_kdf_rounds);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void wallet2::load(const std::string& wallet_, const epee::wipeable_string& password) void wallet2::load(const std::string& wallet_, const epee::wipeable_string& password)
@ -10619,7 +10624,7 @@ size_t wallet2::import_multisig(std::vector<cryptonote::blobdata> blobs)
std::string wallet2::encrypt(const std::string &plaintext, const crypto::secret_key &skey, bool authenticated) const std::string wallet2::encrypt(const std::string &plaintext, const crypto::secret_key &skey, bool authenticated) const
{ {
crypto::chacha_key key; crypto::chacha_key key;
crypto::generate_chacha_key(&skey, sizeof(skey), key); crypto::generate_chacha_key(&skey, sizeof(skey), key, m_kdf_rounds);
std::string ciphertext; std::string ciphertext;
crypto::chacha_iv iv = crypto::rand<crypto::chacha_iv>(); crypto::chacha_iv iv = crypto::rand<crypto::chacha_iv>();
ciphertext.resize(plaintext.size() + sizeof(iv) + (authenticated ? sizeof(crypto::signature) : 0)); ciphertext.resize(plaintext.size() + sizeof(iv) + (authenticated ? sizeof(crypto::signature) : 0));
@ -10649,7 +10654,7 @@ std::string wallet2::decrypt(const std::string &ciphertext, const crypto::secret
error::wallet_internal_error, "Unexpected ciphertext size"); error::wallet_internal_error, "Unexpected ciphertext size");
crypto::chacha_key key; crypto::chacha_key key;
crypto::generate_chacha_key(&skey, sizeof(skey), key); crypto::generate_chacha_key(&skey, sizeof(skey), key, m_kdf_rounds);
const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0]; const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0];
std::string plaintext; std::string plaintext;
plaintext.resize(ciphertext.size() - prefix_size); plaintext.resize(ciphertext.size() - prefix_size);

View File

@ -165,9 +165,9 @@ namespace tools
//! Just parses variables. //! Just parses variables.
static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter); static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter);
static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev); static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds);
wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, bool restricted = false); wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, bool restricted = false, uint64_t kdf_rounds = 1);
~wallet2(); ~wallet2();
struct multisig_info struct multisig_info
@ -1258,6 +1258,7 @@ namespace tools
bool m_key_on_device; bool m_key_on_device;
cryptonote::network_type m_nettype; cryptonote::network_type m_nettype;
bool m_restricted; bool m_restricted;
uint64_t m_kdf_rounds;
std::string seed_language; /*!< Language of the mnemonics (seed). */ std::string seed_language; /*!< Language of the mnemonics (seed). */
bool is_old_file_format; /*!< Whether the wallet file is of an old file format */ bool is_old_file_format; /*!< Whether the wallet file is of an old file format */
bool m_watch_only; /*!< no spend key */ bool m_watch_only; /*!< no spend key */

View File

@ -810,7 +810,7 @@ TEST(Serialization, portability_outputs)
if(ciphertext.size() < prefix_size) if(ciphertext.size() < prefix_size)
return {}; return {};
crypto::chacha_key key; crypto::chacha_key key;
crypto::generate_chacha_key(&skey, sizeof(skey), key); crypto::generate_chacha_key(&skey, sizeof(skey), key, 1);
const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0]; const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0];
std::string plaintext; std::string plaintext;
plaintext.resize(ciphertext.size() - prefix_size); plaintext.resize(ciphertext.size() - prefix_size);