30
30
31
31
#include <algorithm>
32
32
#include <numeric>
33
+ #include <optional>
33
34
#include <string>
34
35
#include <tuple>
35
36
#include <queue>
@@ -1098,50 +1099,46 @@ uint64_t gamma_picker::pick()
1098
1099
};
1099
1100
1100
1101
boost::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):
1103
1104
w(w),
1104
- locked(password != boost::none )
1105
+ should_relock(true )
1105
1106
{
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 ())
1110
1111
{
1111
- locked = false;
1112
+ should_relock = false;
1112
1113
return;
1113
1114
}
1114
- const epee::wipeable_string pass = password->password();
1115
- w.generate_chacha_key_from_password(pass, key);
1116
- w.decrypt_keys(key);
1117
- }
1118
1115
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
+
1123
1118
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)
1127
1120
return;
1128
- w.generate_chacha_key_from_password(password, key);
1121
+
1129
1122
w.decrypt_keys(key);
1130
1123
}
1131
1124
1132
1125
wallet_keys_unlocker::~wallet_keys_unlocker()
1133
1126
{
1127
+ if (!should_relock)
1128
+ return;
1129
+
1134
1130
try
1135
1131
{
1136
1132
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)
1138
1135
{
1139
1136
MERROR("There are no lockers in wallet_keys_unlocker dtor");
1140
1137
return;
1141
1138
}
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) ;
1145
1142
w.encrypt_keys(key);
1146
1143
}
1147
1144
catch (...)
@@ -2206,7 +2203,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
2206
2203
boost::optional<epee::wipeable_string> pwd = m_callback->on_get_password(pool ? "output found in pool" : "output received");
2207
2204
THROW_WALLET_EXCEPTION_IF(!pwd, error::password_needed, tr("Password is needed to compute key image for incoming monero"));
2208
2205
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));
2210
2207
}
2211
2208
}
2212
2209
@@ -5438,6 +5435,14 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip
5438
5435
return r;
5439
5436
}
5440
5437
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
+
5441
5446
void wallet2::encrypt_keys(const crypto::chacha_key &key)
5442
5447
{
5443
5448
m_account.encrypt_keys(key);
@@ -5838,27 +5843,6 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p
5838
5843
}
5839
5844
}
5840
5845
//----------------------------------------------------------------------------------------------------
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
- //----------------------------------------------------------------------------------------------------
5862
5846
void wallet2::get_uninitialized_multisig_account(multisig::multisig_account &account_out) const
5863
5847
{
5864
5848
// create uninitialized multisig account
@@ -5904,7 +5888,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
5904
5888
const std::uint32_t threshold)
5905
5889
{
5906
5890
// 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);
5908
5892
5909
5893
// create multisig account
5910
5894
multisig::multisig_account multisig_account;
@@ -5982,7 +5966,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
5982
5966
m_account_public_address.m_spend_public_key = multisig_account.get_multisig_pubkey();
5983
5967
5984
5968
// re-encrypt keys
5985
- keys_reencryptor = epee::misc_utils::auto_scope_leave_caller ();
5969
+ unlocker.reset ();
5986
5970
5987
5971
if (!m_wallet_file.empty())
5988
5972
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
6003
5987
CHECK_AND_ASSERT_THROW_MES(ms_status.multisig_is_active, "The wallet is not multisig");
6004
5988
6005
5989
// 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);
6007
5991
6008
5992
// reconstruct multisig account
6009
5993
multisig::multisig_account multisig_account;
@@ -6055,7 +6039,7 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor
6055
6039
if (multisig_account.multisig_is_ready())
6056
6040
{
6057
6041
// keys are encrypted again
6058
- keys_reencryptor = epee::misc_utils::auto_scope_leave_caller ();
6042
+ unlocker.reset ();
6059
6043
6060
6044
if (!m_wallet_file.empty())
6061
6045
{
@@ -6101,7 +6085,7 @@ std::string wallet2::get_multisig_key_exchange_booster(const epee::wipeable_stri
6101
6085
CHECK_AND_ASSERT_THROW_MES(kex_messages.size() > 0, "No key exchange messages passed in.");
6102
6086
6103
6087
// 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);
6105
6089
6106
6090
// prepare multisig account
6107
6091
multisig::multisig_account multisig_account;
@@ -6489,7 +6473,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
6489
6473
THROW_WALLET_EXCEPTION_IF(true, error::file_read_error, "failed to load keys from buffer");
6490
6474
}
6491
6475
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);
6493
6477
6494
6478
//keys loaded ok!
6495
6479
//try to load wallet cache. but even if we failed, it is not big problem
0 commit comments