diff options
author | luigi1111 <luigi1111w@gmail.com> | 2022-09-15 00:34:05 -0500 |
---|---|---|
committer | luigi1111 <luigi1111w@gmail.com> | 2022-09-15 00:34:05 -0500 |
commit | df37c148d47611b173e75ae858fe51395175b21d (patch) | |
tree | 1438c6203e9f5a55bc296907d8c316e9352639a3 | |
parent | Merge pull request #8554 (diff) | |
parent | Fix segfault restoring encrypted multisig seed (diff) | |
download | monero-df37c148d47611b173e75ae858fe51395175b21d.tar.xz |
Merge pull request #8551
eca7f6a Fix segfault restoring encrypted multisig seed (j-berman)
f713c3c Require user ack multisig is experimental to restore (j-berman)
564a7a3 multisig: fix #8537 seed restore (suggestions by @UkoeHB) (j-berman)
-rw-r--r-- | src/multisig/multisig_account.cpp | 9 | ||||
-rw-r--r-- | src/multisig/multisig_account.h | 9 | ||||
-rw-r--r-- | src/multisig/multisig_account_kex_impl.cpp | 2 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 45 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.h | 2 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 12 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 3 | ||||
-rw-r--r-- | tests/unit_tests/multisig.cpp | 2 |
8 files changed, 56 insertions, 28 deletions
diff --git a/src/multisig/multisig_account.cpp b/src/multisig/multisig_account.cpp index 9bdcf2dbc..f3e78da18 100644 --- a/src/multisig/multisig_account.cpp +++ b/src/multisig/multisig_account.cpp @@ -127,7 +127,7 @@ namespace multisig bool multisig_account::multisig_is_ready() const { if (main_kex_rounds_done()) - return m_kex_rounds_complete >= multisig_kex_rounds_required(m_signers.size(), m_threshold) + 1; + return m_kex_rounds_complete >= multisig_setup_rounds_required(m_signers.size(), m_threshold); else return false; } @@ -200,4 +200,11 @@ namespace multisig return num_signers - threshold + 1; } //---------------------------------------------------------------------------------------------------------------------- + // EXTERNAL + //---------------------------------------------------------------------------------------------------------------------- + std::uint32_t multisig_setup_rounds_required(const std::uint32_t num_signers, const std::uint32_t threshold) + { + return multisig_kex_rounds_required(num_signers, threshold) + 1; + } + //---------------------------------------------------------------------------------------------------------------------- } //namespace multisig diff --git a/src/multisig/multisig_account.h b/src/multisig/multisig_account.h index 7b372bbff..7beb594b4 100644 --- a/src/multisig/multisig_account.h +++ b/src/multisig/multisig_account.h @@ -245,4 +245,13 @@ namespace multisig * return: number of kex rounds required */ std::uint32_t multisig_kex_rounds_required(const std::uint32_t num_signers, const std::uint32_t threshold); + + /** + * brief: multisig_setup_rounds_required - The number of setup rounds required to produce an M-of-N shared key. + * - A participant must complete all kex rounds and 1 initialization round. + * param: num_signers - number of participants in multisig (N) + * param: threshold - threshold of multisig (M) + * return: number of setup rounds required + */ + std::uint32_t multisig_setup_rounds_required(const std::uint32_t num_signers, const std::uint32_t threshold); } //namespace multisig diff --git a/src/multisig/multisig_account_kex_impl.cpp b/src/multisig/multisig_account_kex_impl.cpp index be9ed9cb2..443e84631 100644 --- a/src/multisig/multisig_account_kex_impl.cpp +++ b/src/multisig/multisig_account_kex_impl.cpp @@ -74,7 +74,7 @@ namespace multisig "Multisig threshold may not be larger than number of signers."); CHECK_AND_ASSERT_THROW_MES(threshold > 0, "Multisig threshold must be > 0."); CHECK_AND_ASSERT_THROW_MES(round > 0, "Multisig kex round must be > 0."); - CHECK_AND_ASSERT_THROW_MES(round <= multisig_kex_rounds_required(num_signers, threshold) + 1, + CHECK_AND_ASSERT_THROW_MES(round <= multisig_setup_rounds_required(num_signers, threshold), "Trying to process multisig kex for an invalid round."); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 9b63ceca6..116b5d71f 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -4118,6 +4118,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) epee::wipeable_string multisig_keys; epee::wipeable_string password; + epee::wipeable_string seed_pass; if (!handle_command_line(vm)) return false; @@ -4134,6 +4135,17 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if(!ask_wallet_create_if_needed()) return false; } + bool enable_multisig = false; + if (m_restore_multisig_wallet) { + fail_msg_writer() << tr("Multisig is disabled."); + fail_msg_writer() << tr("Multisig is an experimental feature and may have bugs. Things that could go wrong include: funds sent to a multisig wallet can't be spent at all, can only be spent with the participation of a malicious group member, or can be stolen by a malicious group member."); + if (!command_line::is_yes(input_line("Do you want to continue restoring a multisig wallet?", true))) { + message_writer() << tr("You have canceled restoring a multisig wallet."); + return false; + } + enable_multisig = true; + } + if (!m_generate_new.empty() || m_restoring) { if (!m_subaddress_lookahead.empty() && !parse_subaddress_lookahead(m_subaddress_lookahead)) @@ -4213,19 +4225,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) auto pwd_container = password_prompter(tr("Enter seed offset passphrase, empty if none"), false); if (std::cin.eof() || !pwd_container) return false; - epee::wipeable_string seed_pass = pwd_container->password(); - if (!seed_pass.empty()) - { - if (m_restore_multisig_wallet) - { - crypto::secret_key key; - crypto::cn_slow_hash(seed_pass.data(), seed_pass.size(), (crypto::hash&)key); - sc_reduce32((unsigned char*)key.data); - multisig_keys = m_wallet->decrypt<epee::wipeable_string>(std::string(multisig_keys.data(), multisig_keys.size()), key, true); - } - else - m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass); - } + seed_pass = pwd_container->password(); + if (!seed_pass.empty() && !m_restore_multisig_wallet) + m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass); } if (!m_generate_from_view_key.empty()) { @@ -4568,7 +4570,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) m_wallet_file = m_generate_new; boost::optional<epee::wipeable_string> r; if (m_restore_multisig_wallet) - r = new_wallet(vm, multisig_keys, old_language); + r = new_wallet(vm, multisig_keys, seed_pass, old_language); else r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); @@ -4667,6 +4669,8 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) } m_wallet->set_refresh_from_block_height(m_restore_height); } + if (enable_multisig) + m_wallet->enable_multisig(true); m_wallet->rewrite(m_wallet_file, password); } else @@ -5057,7 +5061,7 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr } //---------------------------------------------------------------------------------------------------- boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm, - const epee::wipeable_string &multisig_keys, const std::string &old_language) + const epee::wipeable_string &multisig_keys, const epee::wipeable_string &seed_pass, const std::string &old_language) { std::pair<std::unique_ptr<tools::wallet2>, tools::password_container> rc; try { rc = tools::wallet2::make_new(vm, false, password_prompter); } @@ -5091,7 +5095,16 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr try { - m_wallet->generate(m_wallet_file, std::move(rc.second).password(), multisig_keys, create_address_file); + if (seed_pass.empty()) + m_wallet->generate(m_wallet_file, std::move(rc.second).password(), multisig_keys, create_address_file); + else + { + crypto::secret_key key; + crypto::cn_slow_hash(seed_pass.data(), seed_pass.size(), (crypto::hash&)key); + sc_reduce32((unsigned char*)key.data); + const epee::wipeable_string &msig_keys = m_wallet->decrypt<epee::wipeable_string>(std::string(multisig_keys.data(), multisig_keys.size()), key, true); + m_wallet->generate(m_wallet_file, std::move(rc.second).password(), msig_keys, create_address_file); + } bool ready; uint32_t threshold, total; if (!m_wallet->multisig(&ready, &threshold, &total) || !ready) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 6a9fa149d..b18fa2dd6 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -101,7 +101,7 @@ namespace cryptonote boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address, const boost::optional<crypto::secret_key>& spendkey, const crypto::secret_key& viewkey); boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, - const epee::wipeable_string &multisig_keys, const std::string &old_language); + const epee::wipeable_string &multisig_keys, const epee::wipeable_string &seed_pass, const std::string &old_language); boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm); boost::optional<epee::wipeable_string> open_wallet(const boost::program_options::variables_map& vm); bool close_wallet(); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index b6d95b6b7..6ebb21924 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -4691,7 +4691,8 @@ void wallet2::init_type(hw::device::device_type device_type) } /*! - * \brief Generates a wallet or restores one. + * \brief Generates a wallet or restores one. Assumes the multisig setup + * has already completed for the provided multisig info. * \param wallet_ Name of wallet file * \param password Password of wallet file * \param multisig_data The multisig restore info and keys @@ -4750,11 +4751,6 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& crypto::public_key local_signer; THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(spend_secret_key, local_signer), error::invalid_multisig_seed); THROW_WALLET_EXCEPTION_IF(std::find(multisig_signers.begin(), multisig_signers.end(), local_signer) == multisig_signers.end(), error::invalid_multisig_seed); - rct::key skey = rct::zero(); - for (const auto &msk: multisig_keys) - sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes); - THROW_WALLET_EXCEPTION_IF(!(rct::rct2sk(skey) == spend_secret_key), error::invalid_multisig_seed); - memwipe(&skey, sizeof(rct::key)); m_account.make_multisig(view_secret_key, spend_secret_key, spend_public_key, multisig_keys); @@ -4765,6 +4761,8 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& m_multisig = true; m_multisig_threshold = threshold; m_multisig_signers = multisig_signers; + // wallet is assumed already finalized + m_multisig_rounds_passed = multisig::multisig_setup_rounds_required(m_multisig_signers.size(), m_multisig_threshold); setup_keys(password); create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file); @@ -5215,7 +5213,7 @@ bool wallet2::multisig(bool *ready, uint32_t *threshold, uint32_t *total) const if (ready) { *ready = !(get_account().get_keys().m_account_address.m_spend_public_key == rct::rct2pk(rct::identity())) && - (m_multisig_rounds_passed == multisig::multisig_kex_rounds_required(m_multisig_signers.size(), m_multisig_threshold) + 1); + (m_multisig_rounds_passed == multisig::multisig_setup_rounds_required(m_multisig_signers.size(), m_multisig_threshold)); } return true; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 1f84458a6..38b3b2e72 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -817,7 +817,8 @@ private: }; /*! - * \brief Generates a wallet or restores one. + * \brief Generates a wallet or restores one. Assumes the multisig setup + * has already completed for the provided multisig info. * \param wallet_ Name of wallet file * \param password Password of wallet file * \param multisig_data The multisig restore info and keys diff --git a/tests/unit_tests/multisig.cpp b/tests/unit_tests/multisig.cpp index 5ddd78955..8f8ad52e1 100644 --- a/tests/unit_tests/multisig.cpp +++ b/tests/unit_tests/multisig.cpp @@ -171,7 +171,7 @@ static void make_wallets(std::vector<tools::wallet2>& wallets, unsigned int M) { ASSERT_TRUE(wallets.size() > 1 && wallets.size() <= KEYS_COUNT); ASSERT_TRUE(M <= wallets.size()); - std::uint32_t total_rounds_required = multisig::multisig_kex_rounds_required(wallets.size(), M) + 1; + std::uint32_t total_rounds_required = multisig::multisig_setup_rounds_required(wallets.size(), M); std::uint32_t rounds_complete{0}; // initialize wallets, get first round multisig kex msgs |