wallet: fix wallet_keys_unlocker

Fix four issues with wallet_keys_unlocker:
1. It won't decrypt if there are unlockers open simulataneously on multiple `wallet2` instances
2. It won't decrypt if the first unlocker was disabled (i.e. `locked=false`), even with a second non-disabled unlocker
3. If a destructor of an earlier unlocker is triggered before the destructor of a later unlocker, it will re-encrypt too early, while the second unlocker is still in scope
4. Calling the 3-parameter constructor with `locked=true` after an unlocker already exists will "double-encrypt"  the spend key after its destructor since the local variable is `locked=false` and the field member is `locked=true`

Also, replace `wallet2::decrypt_account_for_multisig` with `wallet_keys_unlocker`.
This commit is contained in:
jeffro256
2025-03-23 02:01:28 -05:00
parent f90a267fa3
commit dbc8402da6
4 changed files with 254 additions and 62 deletions
+4 -9
View File
@@ -113,15 +113,14 @@ private:
class wallet_keys_unlocker
{
public:
wallet_keys_unlocker(wallet2 &w, const boost::optional<tools::password_container> &password);
wallet_keys_unlocker(wallet2 &w, bool locked, const epee::wipeable_string &password);
wallet_keys_unlocker(wallet2 &w, const epee::wipeable_string *password);
~wallet_keys_unlocker();
private:
wallet2 &w;
bool locked;
bool should_relock;
crypto::chacha_key key;
static boost::mutex lockers_lock;
static unsigned int lockers;
static std::map<wallet2*, std::size_t> lockers_per_wallet;
};
class i_wallet2_callback
@@ -952,11 +951,6 @@ private:
void restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name, bool create_address_file = false);
private:
/*!
* \brief Decrypts the account keys
* \return an RAII reencryptor for the account keys
*/
epee::misc_utils::auto_scope_leave_caller decrypt_account_for_multisig(const epee::wipeable_string &password);
/*!
* \brief Creates an uninitialized multisig account
* \outparam: the uninitialized multisig account
@@ -1061,6 +1055,7 @@ private:
cryptonote::account_base& get_account(){return m_account;}
const cryptonote::account_base& get_account()const{return m_account;}
bool is_key_encryption_enabled() const;
void encrypt_keys(const crypto::chacha_key &key);
void encrypt_keys(const epee::wipeable_string &password);
void decrypt_keys(const crypto::chacha_key &key);