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
1819bool LegacyScriptPubKeyMan::GetNewDestination (CTxDestination& dest, bilingual_str& error)
@@ -1844,6 +1845,7 @@ bool DescriptorScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master
18441845 keyFail = true ;
18451846 break ;
18461847 }
1848+ // TODO: test for mnemonics
18471849 keyPass = true ;
18481850 if (m_decryption_thoroughly_checked)
18491851 break ;
@@ -1870,15 +1872,34 @@ bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, Walle
18701872 {
18711873 const CKey &key = key_in.second ;
18721874 CPubKey pubkey = key.GetPubKey ();
1875+ assert (pubkey.GetID () == key_in.first );
1876+ const auto mnemonic_in = m_mnemonics.find (key_in.first );
18731877 CKeyingMaterial secret (key.begin (), key.end ());
18741878 std::vector<unsigned char > crypted_secret;
18751879 if (!EncryptSecret (master_key, secret, pubkey.GetHash (), crypted_secret)) {
18761880 return false ;
18771881 }
1882+ std::vector<unsigned char > crypted_mnemonic;
1883+ std::vector<unsigned char > crypted_mnemonic_passphrase;
1884+ if (mnemonic_in != m_mnemonics.end ()) {
1885+ const Mnemonic mnemonic = mnemonic_in->second ;
1886+
1887+ CKeyingMaterial mnemonic_secret (mnemonic.first .begin (), mnemonic.first .end ());
1888+ CKeyingMaterial mnemonic_passphrase_secret (mnemonic.second .begin (), mnemonic.second .end ());
1889+ if (!EncryptSecret (master_key, mnemonic_secret, pubkey.GetHash (), crypted_mnemonic)) {
1890+ return false ;
1891+ }
1892+ if (!EncryptSecret (master_key, mnemonic_passphrase_secret, pubkey.GetHash (), crypted_mnemonic_passphrase)) {
1893+ return false ;
1894+ }
1895+ }
1896+
18781897 m_map_crypted_keys[pubkey.GetID ()] = make_pair (pubkey, crypted_secret);
1879- batch->WriteCryptedDescriptorKey (GetID (), pubkey, crypted_secret);
1898+ m_crypted_mnemonics[pubkey.GetID ()] = make_pair (crypted_mnemonic, crypted_mnemonic_passphrase);
1899+ batch->WriteCryptedDescriptorKey (GetID (), pubkey, crypted_secret, crypted_mnemonic, crypted_mnemonic_passphrase);
18801900 }
18811901 m_map_keys.clear ();
1902+ m_mnemonics.clear ();
18821903 return true ;
18831904}
18841905
@@ -2003,12 +2024,13 @@ void DescriptorScriptPubKeyMan::AddDescriptorKey(const CKey& key, const CPubKey
20032024{
20042025 LOCK (cs_desc_man);
20052026 WalletBatch batch (m_storage.GetDatabase ());
2006- if (!AddDescriptorKeyWithDB (batch, key, pubkey)) {
2027+ // TODO: add mnemonic here too
2028+ if (!AddDescriptorKeyWithDB (batch, key, pubkey, " " , " " )) {
20072029 throw std::runtime_error (std::string (__func__) + " : writing descriptor private key failed" );
20082030 }
20092031}
20102032
2011- bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB (WalletBatch& batch, const CKey& key, const CPubKey &pubkey)
2033+ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB (WalletBatch& batch, const CKey& key, const CPubKey &pubkey, const SecureString& mnemonic, const SecureString& mnemonic_passphrase )
20122034{
20132035 AssertLockHeld (cs_desc_man);
20142036 assert (!m_storage.IsWalletFlagSet (WALLET_FLAG_DISABLE_PRIVATE_KEYS));
@@ -2025,22 +2047,37 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
20252047 }
20262048
20272049 std::vector<unsigned char > crypted_secret;
2050+ std::vector<unsigned char > crypted_mnemonic;
2051+ std::vector<unsigned char > crypted_mnemonic_passphrase;
20282052 CKeyingMaterial secret (key.begin (), key.end ());
2053+ CKeyingMaterial mnemonic_secret (mnemonic.begin (), mnemonic.end ());
2054+ CKeyingMaterial mnemonic_passphrase_secret (mnemonic_passphrase.begin (), mnemonic_passphrase.end ());
20292055 if (!m_storage.WithEncryptionKey ([&](const CKeyingMaterial& encryption_key) {
2030- return EncryptSecret (encryption_key, secret, pubkey.GetHash (), crypted_secret);
2056+ if (!EncryptSecret (encryption_key, secret, pubkey.GetHash (), crypted_secret)) return false ;
2057+ if (!mnemonic.empty ()) {
2058+ if (!EncryptSecret (encryption_key, mnemonic_secret, pubkey.GetHash (), crypted_mnemonic)) {
2059+ return false ;
2060+ }
2061+ if (!EncryptSecret (encryption_key, mnemonic_passphrase_secret, pubkey.GetHash (), crypted_mnemonic_passphrase)) {
2062+ return false ;
2063+ }
2064+ }
2065+ return true ;
20312066 })) {
20322067 return false ;
20332068 }
20342069
20352070 m_map_crypted_keys[pubkey.GetID ()] = make_pair (pubkey, crypted_secret);
2036- return batch.WriteCryptedDescriptorKey (GetID (), pubkey, crypted_secret);
2071+ m_crypted_mnemonics[pubkey.GetID ()] = make_pair (crypted_mnemonic, crypted_mnemonic_passphrase);
2072+ return batch.WriteCryptedDescriptorKey (GetID (), pubkey, crypted_secret, crypted_mnemonic, crypted_mnemonic_passphrase);
20372073 } else {
20382074 m_map_keys[pubkey.GetID ()] = key;
2039- return batch.WriteDescriptorKey (GetID (), pubkey, key.GetPrivKey ());
2075+ m_mnemonics[pubkey.GetID ()] = make_pair (mnemonic, mnemonic_passphrase);
2076+ return batch.WriteDescriptorKey (GetID (), pubkey, key.GetPrivKey (), mnemonic, mnemonic_passphrase);
20402077 }
20412078}
20422079
2043- bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration (const CExtKey& master_key, bool internal)
2080+ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration (const CExtKey& master_key, const SecureString& secure_mnemonic, const SecureString& secure_mnemonic_passphrase, bool internal)
20442081{
20452082 LOCK (cs_desc_man);
20462083 assert (m_storage.IsWalletFlagSet (WALLET_FLAG_DESCRIPTORS));
@@ -2050,6 +2087,16 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
20502087 return false ;
20512088 }
20522089
2090+ if (!secure_mnemonic.empty ()) {
2091+ // TODO: remove duplicated code with AddKey()
2092+ SecureVector seed_key_tmp;
2093+ CMnemonic::ToSeed (secure_mnemonic, secure_mnemonic_passphrase, seed_key_tmp);
2094+
2095+ CExtKey master_key_tmp;
2096+ master_key_tmp.SetSeed (MakeByteSpan (seed_key_tmp));
2097+ assert (master_key == master_key_tmp);
2098+ }
2099+
20532100 int64_t creation_time = GetTime ();
20542101
20552102 std::string xpub = EncodeExtPubKey (master_key.Neuter ());
@@ -2070,7 +2117,7 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
20702117
20712118 // Store the master private key, and descriptor
20722119 WalletBatch batch (m_storage.GetDatabase ());
2073- if (!AddDescriptorKeyWithDB (batch, master_key.key , master_key.key .GetPubKey ())) {
2120+ if (!AddDescriptorKeyWithDB (batch, master_key.key , master_key.key .GetPubKey (), secure_mnemonic, secure_mnemonic_passphrase )) {
20742121 throw std::runtime_error (std::string (__func__) + " : writing descriptor master private key failed" );
20752122 }
20762123 if (!batch.WriteDescriptor (GetID (), m_wallet_descriptor)) {
@@ -2354,21 +2401,34 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
23542401 }
23552402}
23562403
2357- bool DescriptorScriptPubKeyMan::AddKey (const CKeyID& key_id, const CKey& key)
2404+ bool DescriptorScriptPubKeyMan::AddKey (const CKeyID& key_id, const CKey& key, const SecureString& mnemonic, const SecureString& mnemonic_passphrase )
23582405{
23592406 LOCK (cs_desc_man);
2407+ if (!mnemonic.empty ()) {
2408+ // TODO: remove duplicated code with AddKey()
2409+ SecureVector seed_key_tmp;
2410+ CMnemonic::ToSeed (mnemonic, mnemonic_passphrase, seed_key_tmp);
2411+
2412+ CExtKey master_key_tmp;
2413+ master_key_tmp.SetSeed (MakeByteSpan (seed_key_tmp));
2414+ assert (key == master_key_tmp.key );
2415+ }
2416+
23602417 m_map_keys[key_id] = key;
2418+ m_mnemonics[key_id] = make_pair (mnemonic, mnemonic_passphrase);
2419+
23612420 return true ;
23622421}
23632422
2364- bool DescriptorScriptPubKeyMan::AddCryptedKey (const CKeyID& key_id, const CPubKey& pubkey, const std::vector<unsigned char >& crypted_key)
2423+ 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 )
23652424{
23662425 LOCK (cs_desc_man);
23672426 if (!m_map_keys.empty ()) {
23682427 return false ;
23692428 }
23702429
23712430 m_map_crypted_keys[key_id] = make_pair (pubkey, crypted_key);
2431+ m_crypted_mnemonics[key_id] = make_pair (mnemonic, mnemonic_passphrase);
23722432 return true ;
23732433}
23742434
@@ -2410,7 +2470,6 @@ bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, const bool
24102470
24112471 FlatSigningProvider provider;
24122472 provider.keys = GetKeys ();
2413-
24142473 if (priv) {
24152474 // For the private version, always return the master key to avoid
24162475 // exposing child private keys. The risk implications of exposing child
@@ -2421,6 +2480,65 @@ bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, const bool
24212480 return m_wallet_descriptor.descriptor ->ToNormalizedString (provider, out, &m_wallet_descriptor.cache );
24222481}
24232482
2483+ bool DescriptorScriptPubKeyMan::GetMnemonicString (SecureString& mnemonic_out, SecureString& mnemonic_passphrase_out) const
2484+ {
2485+ LOCK (cs_desc_man);
2486+
2487+ mnemonic_out.clear ();
2488+ mnemonic_passphrase_out.clear ();
2489+
2490+ if (m_mnemonics.empty () && m_crypted_mnemonics.empty ()) {
2491+ WalletLogPrintf (" %s: Descriptor wallet has no mnemonic defined\n " , __func__);
2492+ return false ;
2493+ }
2494+ if (m_storage.IsLocked (false )) return false ;
2495+
2496+ if (m_mnemonics.size () + m_crypted_mnemonics.size () > 1 ) {
2497+ WalletLogPrintf (" %s: ERROR: One descriptor has multiple mnemonics. Can't match it\n " , __func__);
2498+ return false ;
2499+ }
2500+ if (m_storage.HasEncryptionKeys () && !m_storage.IsLocked (true )) {
2501+ if (!m_crypted_mnemonics.empty () && m_map_crypted_keys.size () != 1 ) {
2502+ WalletLogPrintf (" %s: ERROR: can't choose encryption key for mnemonic out of %lld\n " , __func__, m_map_crypted_keys.size ());
2503+ return false ;
2504+ }
2505+ const CPubKey& pubkey = m_map_crypted_keys.begin ()->second .first ;
2506+ const auto mnemonic = m_crypted_mnemonics.begin ()->second ;
2507+ const std::vector<unsigned char >& crypted_mnemonic = mnemonic.first ;
2508+ const std::vector<unsigned char >& crypted_mnemonic_passphrase = mnemonic.second ;
2509+
2510+ SecureVector mnemonic_v;
2511+ SecureVector mnemonic_passphrase_v;
2512+ if (!m_storage.WithEncryptionKey ([&](const CKeyingMaterial& encryption_key) {
2513+ return DecryptSecret (encryption_key, crypted_mnemonic, pubkey.GetHash (), mnemonic_v);
2514+ })) {
2515+ LogPrintf (" can't decrypt mnemonic pubkey %s crypted: %s\n " , pubkey.GetHash ().ToString (), HexStr (crypted_mnemonic));
2516+ return false ;
2517+ }
2518+ if (!crypted_mnemonic_passphrase.empty ()) {
2519+ if (!m_storage.WithEncryptionKey ([&](const CKeyingMaterial& encryption_key) {
2520+ return DecryptSecret (encryption_key, crypted_mnemonic_passphrase, pubkey.GetHash (), mnemonic_passphrase_v);
2521+ })) {
2522+ LogPrintf (" can't decrypt mnemonic-passphrase\n " );
2523+ return false ;
2524+ }
2525+ }
2526+
2527+ std::copy (mnemonic_v.begin (), mnemonic_v.end (), std::back_inserter (mnemonic_out));
2528+ std::copy (mnemonic_passphrase_v.begin (), mnemonic_passphrase_v.end (), std::back_inserter (mnemonic_passphrase_out));
2529+
2530+ return true ;
2531+ }
2532+ if (m_mnemonics.empty ()) return false ;
2533+
2534+ const auto mnemonic_it = m_mnemonics.begin ();
2535+
2536+ mnemonic_out = mnemonic_it->second .first ;
2537+ mnemonic_passphrase_out = mnemonic_it->second .second ;
2538+
2539+ return true ;
2540+ }
2541+
24242542void DescriptorScriptPubKeyMan::UpgradeDescriptorCache ()
24252543{
24262544 LOCK (cs_desc_man);
0 commit comments