1313#include < util/strencodings.h>
1414#include < util/system.h>
1515#include < util/translation.h>
16+ #include < wallet/bip39.h>
1617#include < wallet/scriptpubkeyman.h>
1718
1819namespace wallet {
@@ -1849,6 +1850,7 @@ bool DescriptorScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master
18491850 keyFail = true ;
18501851 break ;
18511852 }
1853+ // TODO: test for mnemonics
18521854 keyPass = true ;
18531855 if (m_decryption_thoroughly_checked)
18541856 break ;
@@ -1875,15 +1877,34 @@ bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, Walle
18751877 {
18761878 const CKey &key = key_in.second ;
18771879 CPubKey pubkey = key.GetPubKey ();
1880+ assert (pubkey.GetID () == key_in.first );
1881+ const auto mnemonic_in = m_mnemonics.find (key_in.first );
18781882 CKeyingMaterial secret (key.begin (), key.end ());
18791883 std::vector<unsigned char > crypted_secret;
18801884 if (!EncryptSecret (master_key, secret, pubkey.GetHash (), crypted_secret)) {
18811885 return false ;
18821886 }
1887+ std::vector<unsigned char > crypted_mnemonic;
1888+ std::vector<unsigned char > crypted_mnemonic_passphrase;
1889+ if (mnemonic_in != m_mnemonics.end ()) {
1890+ const Mnemonic mnemonic = mnemonic_in->second ;
1891+
1892+ CKeyingMaterial mnemonic_secret (mnemonic.first .begin (), mnemonic.first .end ());
1893+ CKeyingMaterial mnemonic_passphrase_secret (mnemonic.second .begin (), mnemonic.second .end ());
1894+ if (!EncryptSecret (master_key, mnemonic_secret, pubkey.GetHash (), crypted_mnemonic)) {
1895+ return false ;
1896+ }
1897+ if (!EncryptSecret (master_key, mnemonic_passphrase_secret, pubkey.GetHash (), crypted_mnemonic_passphrase)) {
1898+ return false ;
1899+ }
1900+ }
1901+
18831902 m_map_crypted_keys[pubkey.GetID ()] = make_pair (pubkey, crypted_secret);
1884- batch->WriteCryptedDescriptorKey (GetID (), pubkey, crypted_secret);
1903+ m_crypted_mnemonics[pubkey.GetID ()] = make_pair (crypted_mnemonic, crypted_mnemonic_passphrase);
1904+ batch->WriteCryptedDescriptorKey (GetID (), pubkey, crypted_secret, crypted_mnemonic, crypted_mnemonic_passphrase);
18851905 }
18861906 m_map_keys.clear ();
1907+ m_mnemonics.clear ();
18871908 return true ;
18881909}
18891910
@@ -2008,12 +2029,12 @@ void DescriptorScriptPubKeyMan::AddDescriptorKey(const CKey& key, const CPubKey
20082029{
20092030 LOCK (cs_desc_man);
20102031 WalletBatch batch (m_storage.GetDatabase ());
2011- if (!AddDescriptorKeyWithDB (batch, key, pubkey)) {
2032+ if (!AddDescriptorKeyWithDB (batch, key, pubkey, " " , " " )) {
20122033 throw std::runtime_error (std::string (__func__) + " : writing descriptor private key failed" );
20132034 }
20142035}
20152036
2016- bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB (WalletBatch& batch, const CKey& key, const CPubKey &pubkey)
2037+ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB (WalletBatch& batch, const CKey& key, const CPubKey &pubkey, const SecureString& mnemonic, const SecureString& mnemonic_passphrase )
20172038{
20182039 AssertLockHeld (cs_desc_man);
20192040 assert (!m_storage.IsWalletFlagSet (WALLET_FLAG_DISABLE_PRIVATE_KEYS));
@@ -2030,22 +2051,37 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
20302051 }
20312052
20322053 std::vector<unsigned char > crypted_secret;
2054+ std::vector<unsigned char > crypted_mnemonic;
2055+ std::vector<unsigned char > crypted_mnemonic_passphrase;
20332056 CKeyingMaterial secret (key.begin (), key.end ());
2057+ CKeyingMaterial mnemonic_secret (mnemonic.begin (), mnemonic.end ());
2058+ CKeyingMaterial mnemonic_passphrase_secret (mnemonic_passphrase.begin (), mnemonic_passphrase.end ());
20342059 if (!m_storage.WithEncryptionKey ([&](const CKeyingMaterial& encryption_key) {
2035- return EncryptSecret (encryption_key, secret, pubkey.GetHash (), crypted_secret);
2060+ if (!EncryptSecret (encryption_key, secret, pubkey.GetHash (), crypted_secret)) return false ;
2061+ if (!mnemonic.empty ()) {
2062+ if (!EncryptSecret (encryption_key, mnemonic_secret, pubkey.GetHash (), crypted_mnemonic)) {
2063+ return false ;
2064+ }
2065+ if (!EncryptSecret (encryption_key, mnemonic_passphrase_secret, pubkey.GetHash (), crypted_mnemonic_passphrase)) {
2066+ return false ;
2067+ }
2068+ }
2069+ return true ;
20362070 })) {
20372071 return false ;
20382072 }
20392073
20402074 m_map_crypted_keys[pubkey.GetID ()] = make_pair (pubkey, crypted_secret);
2041- return batch.WriteCryptedDescriptorKey (GetID (), pubkey, crypted_secret);
2075+ m_crypted_mnemonics[pubkey.GetID ()] = make_pair (crypted_mnemonic, crypted_mnemonic_passphrase);
2076+ return batch.WriteCryptedDescriptorKey (GetID (), pubkey, crypted_secret, crypted_mnemonic, crypted_mnemonic_passphrase);
20422077 } else {
20432078 m_map_keys[pubkey.GetID ()] = key;
2044- return batch.WriteDescriptorKey (GetID (), pubkey, key.GetPrivKey ());
2079+ m_mnemonics[pubkey.GetID ()] = make_pair (mnemonic, mnemonic_passphrase);
2080+ return batch.WriteDescriptorKey (GetID (), pubkey, key.GetPrivKey (), mnemonic, mnemonic_passphrase);
20452081 }
20462082}
20472083
2048- bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration (const CExtKey& master_key, bool internal)
2084+ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration (const CExtKey& master_key, const SecureString& secure_mnemonic, const SecureString& secure_mnemonic_passphrase, bool internal)
20492085{
20502086 LOCK (cs_desc_man);
20512087 assert (m_storage.IsWalletFlagSet (WALLET_FLAG_DESCRIPTORS));
@@ -2055,6 +2091,16 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
20552091 return false ;
20562092 }
20572093
2094+ if (!secure_mnemonic.empty ()) {
2095+ // TODO: remove duplicated code with AddKey()
2096+ SecureVector seed_key_tmp;
2097+ CMnemonic::ToSeed (secure_mnemonic, secure_mnemonic_passphrase, seed_key_tmp);
2098+
2099+ CExtKey master_key_tmp;
2100+ master_key_tmp.SetSeed (MakeByteSpan (seed_key_tmp));
2101+ assert (master_key == master_key_tmp);
2102+ }
2103+
20582104 int64_t creation_time = GetTime ();
20592105
20602106 std::string xpub = EncodeExtPubKey (master_key.Neuter ());
@@ -2075,7 +2121,7 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
20752121
20762122 // Store the master private key, and descriptor
20772123 WalletBatch batch (m_storage.GetDatabase ());
2078- if (!AddDescriptorKeyWithDB (batch, master_key.key , master_key.key .GetPubKey ())) {
2124+ if (!AddDescriptorKeyWithDB (batch, master_key.key , master_key.key .GetPubKey (), secure_mnemonic, secure_mnemonic_passphrase )) {
20792125 throw std::runtime_error (std::string (__func__) + " : writing descriptor master private key failed" );
20802126 }
20812127 if (!batch.WriteDescriptor (GetID (), m_wallet_descriptor)) {
@@ -2356,21 +2402,34 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
23562402 }
23572403}
23582404
2359- bool DescriptorScriptPubKeyMan::AddKey (const CKeyID& key_id, const CKey& key)
2405+ bool DescriptorScriptPubKeyMan::AddKey (const CKeyID& key_id, const CKey& key, const SecureString& mnemonic, const SecureString& mnemonic_passphrase )
23602406{
23612407 LOCK (cs_desc_man);
2408+ if (!mnemonic.empty ()) {
2409+ // TODO: remove duplicated code with AddKey()
2410+ SecureVector seed_key_tmp;
2411+ CMnemonic::ToSeed (mnemonic, mnemonic_passphrase, seed_key_tmp);
2412+
2413+ CExtKey master_key_tmp;
2414+ master_key_tmp.SetSeed (MakeByteSpan (seed_key_tmp));
2415+ assert (key == master_key_tmp.key );
2416+ }
2417+
23622418 m_map_keys[key_id] = key;
2419+ m_mnemonics[key_id] = make_pair (mnemonic, mnemonic_passphrase);
2420+
23632421 return true ;
23642422}
23652423
2366- bool DescriptorScriptPubKeyMan::AddCryptedKey (const CKeyID& key_id, const CPubKey& pubkey, const std::vector<unsigned char >& crypted_key)
2424+ bool DescriptorScriptPubKeyMan::AddCryptedKey (const CKeyID& key_id, const CPubKey& pubkey, const std::vector<unsigned char >& crypted_key, const std::vector< unsigned char >& mnemonic, const std::vector< unsigned char >& mnemonic_passphrase )
23672425{
23682426 LOCK (cs_desc_man);
23692427 if (!m_map_keys.empty ()) {
23702428 return false ;
23712429 }
23722430
23732431 m_map_crypted_keys[key_id] = make_pair (pubkey, crypted_key);
2432+ m_crypted_mnemonics[key_id] = make_pair (mnemonic, mnemonic_passphrase);
23742433 return true ;
23752434}
23762435
@@ -2412,7 +2471,6 @@ bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, const bool
24122471
24132472 FlatSigningProvider provider;
24142473 provider.keys = GetKeys ();
2415-
24162474 if (priv) {
24172475 // For the private version, always return the master key to avoid
24182476 // exposing child private keys. The risk implications of exposing child
@@ -2423,6 +2481,65 @@ bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, const bool
24232481 return m_wallet_descriptor.descriptor ->ToNormalizedString (provider, out, &m_wallet_descriptor.cache );
24242482}
24252483
2484+ bool DescriptorScriptPubKeyMan::GetMnemonicString (SecureString& mnemonic_out, SecureString& mnemonic_passphrase_out) const
2485+ {
2486+ LOCK (cs_desc_man);
2487+
2488+ mnemonic_out.clear ();
2489+ mnemonic_passphrase_out.clear ();
2490+
2491+ if (m_mnemonics.empty () && m_crypted_mnemonics.empty ()) {
2492+ WalletLogPrintf (" %s: Descriptor wallet has no mnemonic defined\n " , __func__);
2493+ return false ;
2494+ }
2495+ if (m_storage.IsLocked (false )) return false ;
2496+
2497+ if (m_mnemonics.size () + m_crypted_mnemonics.size () > 1 ) {
2498+ WalletLogPrintf (" %s: ERROR: One descriptor has multiple mnemonics. Can't match it\n " , __func__);
2499+ return false ;
2500+ }
2501+ if (m_storage.HasEncryptionKeys () && !m_storage.IsLocked (true )) {
2502+ if (!m_crypted_mnemonics.empty () && m_map_crypted_keys.size () != 1 ) {
2503+ WalletLogPrintf (" %s: ERROR: can't choose encryption key for mnemonic out of %lld\n " , __func__, m_map_crypted_keys.size ());
2504+ return false ;
2505+ }
2506+ const CPubKey& pubkey = m_map_crypted_keys.begin ()->second .first ;
2507+ const auto mnemonic = m_crypted_mnemonics.begin ()->second ;
2508+ const std::vector<unsigned char >& crypted_mnemonic = mnemonic.first ;
2509+ const std::vector<unsigned char >& crypted_mnemonic_passphrase = mnemonic.second ;
2510+
2511+ SecureVector mnemonic_v;
2512+ SecureVector mnemonic_passphrase_v;
2513+ if (!m_storage.WithEncryptionKey ([&](const CKeyingMaterial& encryption_key) {
2514+ return DecryptSecret (encryption_key, crypted_mnemonic, pubkey.GetHash (), mnemonic_v);
2515+ })) {
2516+ LogPrintf (" can't decrypt mnemonic pubkey %s crypted: %s\n " , pubkey.GetHash ().ToString (), HexStr (crypted_mnemonic));
2517+ return false ;
2518+ }
2519+ if (!crypted_mnemonic_passphrase.empty ()) {
2520+ if (!m_storage.WithEncryptionKey ([&](const CKeyingMaterial& encryption_key) {
2521+ return DecryptSecret (encryption_key, crypted_mnemonic_passphrase, pubkey.GetHash (), mnemonic_passphrase_v);
2522+ })) {
2523+ LogPrintf (" can't decrypt mnemonic-passphrase\n " );
2524+ return false ;
2525+ }
2526+ }
2527+
2528+ std::copy (mnemonic_v.begin (), mnemonic_v.end (), std::back_inserter (mnemonic_out));
2529+ std::copy (mnemonic_passphrase_v.begin (), mnemonic_passphrase_v.end (), std::back_inserter (mnemonic_passphrase_out));
2530+
2531+ return true ;
2532+ }
2533+ if (m_mnemonics.empty ()) return false ;
2534+
2535+ const auto mnemonic_it = m_mnemonics.begin ();
2536+
2537+ mnemonic_out = mnemonic_it->second .first ;
2538+ mnemonic_passphrase_out = mnemonic_it->second .second ;
2539+
2540+ return true ;
2541+ }
2542+
24262543void DescriptorScriptPubKeyMan::UpgradeDescriptorCache ()
24272544{
24282545 LOCK (cs_desc_man);
0 commit comments