3030
3131#include <algorithm>
3232#include <numeric>
33+ #include <optional>
3334#include <string>
3435#include <tuple>
3536#include <queue>
@@ -1098,50 +1099,46 @@ uint64_t gamma_picker::pick()
10981099};
10991100
11001101boost::mutex wallet_keys_unlocker::lockers_lock;
1101- unsigned int wallet_keys_unlocker::lockers = 0 ;
1102- wallet_keys_unlocker::wallet_keys_unlocker(wallet2 &w, const boost::optional<tools::password_container> & password):
1102+ std::map<wallet2*, std::size_t> wallet_keys_unlocker::lockers_per_wallet = {} ;
1103+ wallet_keys_unlocker::wallet_keys_unlocker(wallet2 &w, const epee::wipeable_string * password):
11031104 w(w),
1104- locked(password != boost::none )
1105+ should_relock(true )
11051106{
1106- boost::lock_guard<boost::mutex> lock(lockers_lock);
1107- if (lockers++ > 0)
1108- locked = false;
1109- if (!locked || w.is_unattended() || w.ask_password() != tools::wallet2::AskPasswordToDecrypt || w.watch_only() || w.is_background_syncing ())
1107+ static_assert(!std::is_move_assignable_v<wallet2> && !std::is_move_constructible_v<wallet2>,
1108+ "Keeping track of wallet instances by pointer doesn't work if wallet2 can be moved");
1109+
1110+ if (password == nullptr || !w.is_key_encryption_enabled ())
11101111 {
1111- locked = false;
1112+ should_relock = false;
11121113 return;
11131114 }
1114- const epee::wipeable_string pass = password->password();
1115- w.generate_chacha_key_from_password(pass, key);
1116- w.decrypt_keys(key);
1117- }
11181115
1119- wallet_keys_unlocker::wallet_keys_unlocker(wallet2 &w, bool locked, const epee::wipeable_string &password):
1120- w(w),
1121- locked(locked)
1122- {
1116+ w.generate_chacha_key_from_password(*password, key);
1117+
11231118 boost::lock_guard<boost::mutex> lock(lockers_lock);
1124- if (lockers++ > 0)
1125- locked = false;
1126- if (!locked)
1119+ if (lockers_per_wallet[std::addressof(w)]++ > 0)
11271120 return;
1128- w.generate_chacha_key_from_password(password, key);
1121+
11291122 w.decrypt_keys(key);
11301123}
11311124
11321125wallet_keys_unlocker::~wallet_keys_unlocker()
11331126{
1127+ if (!should_relock)
1128+ return;
1129+
11341130 try
11351131 {
11361132 boost::lock_guard<boost::mutex> lock(lockers_lock);
1137- if (lockers == 0)
1133+ wallet2* w_ptr = std::addressof(w);
1134+ if (lockers_per_wallet[w_ptr] == 0)
11381135 {
11391136 MERROR("There are no lockers in wallet_keys_unlocker dtor");
11401137 return;
11411138 }
1142- --lockers;
1143- if (!locked)
1144- return ;
1139+ if (--lockers_per_wallet[w_ptr] > 0)
1140+ return; // there are other unlock-ers for this wallet, do nothing for now
1141+ lockers_per_wallet.erase(w_ptr) ;
11451142 w.encrypt_keys(key);
11461143 }
11471144 catch (...)
@@ -2206,7 +2203,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
22062203 boost::optional<epee::wipeable_string> pwd = m_callback->on_get_password(pool ? "output found in pool" : "output received");
22072204 THROW_WALLET_EXCEPTION_IF(!pwd, error::password_needed, tr("Password is needed to compute key image for incoming monero"));
22082205 THROW_WALLET_EXCEPTION_IF(!verify_password(*pwd), error::password_needed, tr("Invalid password: password is needed to compute key image for incoming monero"));
2209- m_encrypt_keys_after_refresh.reset(new wallet_keys_unlocker(*this, m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only, *pwd));
2206+ m_encrypt_keys_after_refresh.reset(new wallet_keys_unlocker(*this, & *pwd));
22102207 }
22112208 }
22122209
@@ -5438,6 +5435,14 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip
54385435 return r;
54395436}
54405437
5438+ bool wallet2::is_key_encryption_enabled() const
5439+ {
5440+ return !is_unattended()
5441+ && ask_password() == tools::wallet2::AskPasswordToDecrypt
5442+ && !watch_only()
5443+ && !is_background_syncing();
5444+ }
5445+
54415446void wallet2::encrypt_keys(const crypto::chacha_key &key)
54425447{
54435448 m_account.encrypt_keys(key);
@@ -5838,27 +5843,6 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p
58385843 }
58395844}
58405845//----------------------------------------------------------------------------------------------------
5841- epee::misc_utils::auto_scope_leave_caller wallet2::decrypt_account_for_multisig(const epee::wipeable_string &password)
5842- {
5843- // decrypt account keys
5844- // note: this conditional's clauses are old and undocumented
5845- epee::misc_utils::auto_scope_leave_caller keys_reencryptor;
5846- if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
5847- {
5848- crypto::chacha_key chacha_key;
5849- crypto::generate_chacha_key(password.data(), password.size(), chacha_key, m_kdf_rounds);
5850- this->decrypt_keys(chacha_key);
5851- keys_reencryptor = epee::misc_utils::create_scope_leave_handler(
5852- [this, chacha_key]()
5853- {
5854- this->encrypt_keys(chacha_key);
5855- }
5856- );
5857- }
5858-
5859- return keys_reencryptor;
5860- }
5861- //----------------------------------------------------------------------------------------------------
58625846void wallet2::get_uninitialized_multisig_account(multisig::multisig_account &account_out) const
58635847{
58645848 // create uninitialized multisig account
@@ -5904,7 +5888,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
59045888 const std::uint32_t threshold)
59055889{
59065890 // decrypt account keys
5907- epee::misc_utils::auto_scope_leave_caller keys_reencryptor{ this->decrypt_account_for_multisig( password)} ;
5891+ std::optional<wallet_keys_unlocker> unlocker(std::in_place, * this, & password);
59085892
59095893 // create multisig account
59105894 multisig::multisig_account multisig_account;
@@ -5982,7 +5966,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
59825966 m_account_public_address.m_spend_public_key = multisig_account.get_multisig_pubkey();
59835967
59845968 // re-encrypt keys
5985- keys_reencryptor = epee::misc_utils::auto_scope_leave_caller ();
5969+ unlocker.reset ();
59865970
59875971 if (!m_wallet_file.empty())
59885972 this->create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
@@ -6003,7 +5987,7 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor
60035987 CHECK_AND_ASSERT_THROW_MES(ms_status.multisig_is_active, "The wallet is not multisig");
60045988
60055989 // decrypt account keys
6006- epee::misc_utils::auto_scope_leave_caller keys_reencryptor{ this->decrypt_account_for_multisig( password)} ;
5990+ std::optional<wallet_keys_unlocker> unlocker(std::in_place, * this, & password);
60075991
60085992 // reconstruct multisig account
60095993 multisig::multisig_account multisig_account;
@@ -6055,7 +6039,7 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor
60556039 if (multisig_account.multisig_is_ready())
60566040 {
60576041 // keys are encrypted again
6058- keys_reencryptor = epee::misc_utils::auto_scope_leave_caller ();
6042+ unlocker.reset ();
60596043
60606044 if (!m_wallet_file.empty())
60616045 {
@@ -6101,7 +6085,7 @@ std::string wallet2::get_multisig_key_exchange_booster(const epee::wipeable_stri
61016085 CHECK_AND_ASSERT_THROW_MES(kex_messages.size() > 0, "No key exchange messages passed in.");
61026086
61036087 // decrypt account keys
6104- epee::misc_utils::auto_scope_leave_caller keys_reencryptor{this->decrypt_account_for_multisig( password)} ;
6088+ wallet_keys_unlocker unlocker(*this, & password);
61056089
61066090 // prepare multisig account
61076091 multisig::multisig_account multisig_account;
@@ -6489,7 +6473,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
64896473 THROW_WALLET_EXCEPTION_IF(true, error::file_read_error, "failed to load keys from buffer");
64906474 }
64916475
6492- wallet_keys_unlocker unlocker(*this, m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only && !m_is_background_wallet, password);
6476+ wallet_keys_unlocker unlocker(*this, & password);
64936477
64946478 //keys loaded ok!
64956479 //try to load wallet cache. but even if we failed, it is not big problem
0 commit comments