From 46b969fc077d929f6e73266fe7c0b5d1f9b42e18 Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Sat, 5 Mar 2016 01:24:45 +0300 Subject: [PATCH] Encryption/decryption support for malleable keys. --- src/key.cpp | 5 ++ src/key.h | 1 + src/keystore.cpp | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/keystore.h | 77 ++++++++++++++++++++++++++++++++++- src/rpcdump.cpp | 7 +++ src/wallet.cpp | 34 +++++++++++++++- src/wallet.h | 4 +- src/walletdb.cpp | 32 +++++++------- src/walletdb.h | 23 ++++++++++- 9 files changed, 275 insertions(+), 26 deletions(-) diff --git a/src/key.cpp b/src/key.cpp index c11da92..6c0a57d 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1002,6 +1002,11 @@ bool CMalleableKey::SetString(const std::string& strMutableKey) // CMalleableKeyView +CMalleableKeyView::CMalleableKeyView(const std::string &strMalleableKey) +{ + SetString(strMalleableKey); +} + CMalleableKeyView::CMalleableKeyView(const CMalleableKey &b) { if (b.vchSecretL.size() != 32) diff --git a/src/key.h b/src/key.h index 67c414e..3f9d8f1 100644 --- a/src/key.h +++ b/src/key.h @@ -324,6 +324,7 @@ private: public: CMalleableKeyView() { nVersion = 0; }; CMalleableKeyView(const CMalleableKey &b); + CMalleableKeyView(const std::string &strMalleableKey); CMalleableKeyView(const CMalleableKeyView &b); CMalleableKeyView& operator=(const CMalleableKey &b); diff --git a/src/keystore.cpp b/src/keystore.cpp index 451f7ea..215590e 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -29,11 +29,11 @@ bool CBasicKeyStore::AddKey(const CKey& key) return true; } -bool CBasicKeyStore::AddMalleableKey(const CMalleableKey& mKey) +bool CBasicKeyStore::AddMalleableKey(const CMalleableKeyView& keyView, const CSecret& vchSecretH) { { LOCK(cs_KeyStore); - mapMalleableKeys[CMalleableKeyView(mKey)] = mKey.GetSecretH(); + mapMalleableKeys[CMalleableKeyView(keyView)] = vchSecretH; } return true; } @@ -199,6 +199,28 @@ bool CCryptoKeyStore::AddKey(const CKey& key) return true; } +bool CCryptoKeyStore::AddMalleableKey(const CMalleableKeyView& keyView, const CSecret &vchSecretH) +{ + { + LOCK(cs_KeyStore); + if (!SetCrypted()) + return CBasicKeyStore::AddMalleableKey(keyView, vchSecretH); + + if (IsLocked()) + return false; + + CKey keyH; + keyH.SetSecret(vchSecretH, true); + + std::vector vchCryptedSecretH; + if (!EncryptSecret(vMasterKey, vchSecretH, keyH.GetPubKey().GetHash(), vchCryptedSecretH)) + return false; + + if (!AddCryptedMalleableKey(keyView, vchCryptedSecretH)) + return false; + } + return true; +} bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { @@ -212,6 +234,71 @@ bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector< return true; } +bool CCryptoKeyStore::AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector &vchCryptedSecretH) +{ + { + LOCK(cs_KeyStore); + if (!SetCrypted()) + return false; + + mapCryptedMalleableKeys[CMalleableKeyView(keyView)] = vchCryptedSecretH; + } + return true; +} + +bool CCryptoKeyStore::CreatePrivKey(const CPubKey &pubKeyVariant, const CPubKey &R, CKey &privKey) const +{ + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::CreatePrivKey(pubKeyVariant, R, privKey); + + for (CryptedMalleableKeyMap::const_iterator mi = mapCryptedMalleableKeys.begin(); mi != mapCryptedMalleableKeys.end(); mi++) + { + if (mi->first.CheckKeyVariant(R, pubKeyVariant)) + { + const CPubKey H = mi->first.GetMalleablePubKey().GetH(); + + CSecret vchSecretH; + if (!DecryptSecret(vMasterKey, mi->second, H.GetHash(), vchSecretH)) + return false; + if (vchSecretH.size() != 32) + return false; + + CMalleableKey mKey = mi->first.GetMalleableKey(vchSecretH); + return mKey.CheckKeyVariant(R, pubKeyVariant, privKey);; + } + } + + } + return true; +} + +bool CCryptoKeyStore::GetMalleableKey(const CMalleableKeyView &keyView, CMalleableKey &mKey) const +{ + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::GetMalleableKey(keyView, mKey); + CryptedMalleableKeyMap::const_iterator mi = mapCryptedMalleableKeys.find(keyView); + if (mi != mapCryptedMalleableKeys.end()) + { + const CPubKey H = keyView.GetMalleablePubKey().GetH(); + + CSecret vchSecretH; + if (!DecryptSecret(vMasterKey, mi->second, H.GetHash(), vchSecretH)) + return false; + + if (vchSecretH.size() != 32) + return false; + mKey = mi->first.GetMalleableKey(vchSecretH); + + return true; + } + } + return false; +} + bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const { { @@ -276,6 +363,17 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) return false; } mapKeys.clear(); + + BOOST_FOREACH(MalleableKeyMap::value_type& mKey, mapMalleableKeys) + { + const CPubKey vchPubKeyH = mKey.first.GetMalleablePubKey().GetH(); + std::vector vchCryptedSecretH; + if (!EncryptSecret(vMasterKeyIn, mKey.second, vchPubKeyH.GetHash(), vchCryptedSecretH)) + return false; + if (!AddCryptedMalleableKey(mKey.first, vchCryptedSecretH)) + return false; + } + mapMalleableKeys.clear(); } return true; } @@ -305,6 +403,22 @@ bool CCryptoKeyStore::DecryptKeys(const CKeyingMaterial& vMasterKeyIn) } mapCryptedKeys.clear(); + + CryptedMalleableKeyMap::const_iterator mi2 = mapCryptedMalleableKeys.begin(); + for(; mi2 != mapCryptedMalleableKeys.end(); ++mi2) + { + const CPubKey vchPubKeyH = mi2->first.GetMalleablePubKey().GetH(); + + CSecret vchSecretH; + if(!DecryptSecret(vMasterKeyIn, mi2->second, vchPubKeyH.GetHash(), vchSecretH)) + return false; + if (vchSecretH.size() != 32) + return false; + + if (!CBasicKeyStore::AddMalleableKey(mi2->first, vchSecretH)) + return false; + } + mapCryptedMalleableKeys.clear(); } return true; diff --git a/src/keystore.h b/src/keystore.h index d4ac615..438752f 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -40,7 +40,7 @@ public: virtual bool AddKey(const CKey& key) =0; // Add a malleable key to store. - virtual bool AddMalleableKey(const CMalleableKey& mKey) =0; + virtual bool AddMalleableKey(const CMalleableKeyView &keyView, const CSecret &vchSecretH) =0; virtual bool GetMalleableKey(const CMalleableKeyView &keyView, CMalleableKey &mKey) const =0; // Check whether a key corresponding to a given address is present in the store. @@ -92,7 +92,7 @@ protected: public: bool AddKey(const CKey& key); - bool AddMalleableKey(const CMalleableKey& mKey); + bool AddMalleableKey(const CMalleableKeyView& keyView, const CSecret &vchSecretH); bool GetMalleableKey(const CMalleableKeyView &keyView, CMalleableKey &mKey) const { { @@ -196,7 +196,6 @@ public: void ListMalleableViews(std::list &malleableViewList) const { malleableViewList.clear(); - { LOCK(cs_KeyStore); for (MalleableKeyMap::const_iterator mi = mapMalleableKeys.begin(); mi != mapMalleableKeys.end(); mi++) @@ -222,6 +221,7 @@ public: }; typedef std::map > > CryptedKeyMap; +typedef std::map > CryptedMalleableKeyMap; /** Keystore which keeps the private keys encrypted. * It derives from the basic key store, which is used if no encryption is active. @@ -230,6 +230,7 @@ class CCryptoKeyStore : public CBasicKeyStore { private: CryptedKeyMap mapCryptedKeys; + CryptedMalleableKeyMap mapCryptedMalleableKeys; CKeyingMaterial vMasterKey; @@ -269,7 +270,10 @@ public: bool Lock(); virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); + virtual bool AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector &vchCryptedSecretH); + bool AddKey(const CKey& key); + bool AddMalleableKey(const CMalleableKeyView& keyView, const CSecret &vchSecretH); bool HaveKey(const CKeyID &address) const { { @@ -297,6 +301,73 @@ public: } } + bool GetMalleableKey(const CMalleableKeyView &keyView, CMalleableKey &mKey) const; + + bool CheckOwnership(const CPubKey &pubKeyVariant, const CPubKey &R) const + { + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::CheckOwnership(pubKeyVariant, R); + for (CryptedMalleableKeyMap::const_iterator mi = mapCryptedMalleableKeys.begin(); mi != mapCryptedMalleableKeys.end(); mi++) + { + if (mi->first.CheckKeyVariant(R, pubKeyVariant)) + return true; + } + } + return false; + } + + bool CheckOwnership(const CPubKey &pubKeyVariant, const CPubKey &R, CMalleableKeyView &view) const + { + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::CheckOwnership(pubKeyVariant, R, view); + for (CryptedMalleableKeyMap::const_iterator mi = mapCryptedMalleableKeys.begin(); mi != mapCryptedMalleableKeys.end(); mi++) + { + if (mi->first.CheckKeyVariant(R, pubKeyVariant)) + { + view = mi->first; + return true; + } + } + } + return false; + } + + bool CreatePrivKey(const CPubKey &pubKeyVariant, const CPubKey &R, CKey &privKey) const; + + void ListMalleableViews(std::list &malleableViewList) const + { + malleableViewList.clear(); + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::ListMalleableViews(malleableViewList); + for (CryptedMalleableKeyMap::const_iterator mi = mapCryptedMalleableKeys.begin(); mi != mapCryptedMalleableKeys.end(); mi++) + malleableViewList.push_back(CMalleableKeyView(mi->first)); + } + } + + bool GetMalleableView(const CMalleablePubKey &mpk, CMalleableKeyView &view) + { + const CKeyID &mpkID = mpk.GetID(); + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::GetMalleableView(mpk, view); + for (CryptedMalleableKeyMap::const_iterator mi = mapCryptedMalleableKeys.begin(); mi != mapCryptedMalleableKeys.end(); mi++) + if (mi->first.GetID() == mpkID) + { + view = CMalleableKeyView(mi->first); + return true; + } + } + + return false; + } + /* Wallet status (encrypted, locked) changed. * Note: Called without locks held. */ diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index b0693ed..6a83604 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -39,6 +39,8 @@ Value importprivkey(const Array& params, bool fHelp) "importprivkey [label] [rescan=true]\n" "Adds a private key (as returned by dumpprivkey) to your wallet."); + EnsureWalletIsUnlocked(); + string strSecret = params[0].get_str(); string strLabel = ""; if (params.size() > 1) @@ -247,6 +249,8 @@ Value dumpmalleablekey(const Array& params, bool fHelp) "dumpmalleablekey \n" "Dump the private and public key pairs, which correspond to provided key view.\n"); + EnsureWalletIsUnlocked(); + CMalleableKey mKey; CMalleableKeyView keyView; keyView.SetString(params[0].get_str()); @@ -268,6 +272,9 @@ Value importmalleablekey(const Array& params, bool fHelp) "importmalleablekey \n" "Imports the private key pair into your wallet.\n"); + + EnsureWalletIsUnlocked(); + CMalleableKey mKey; bool fSuccess = mKey.SetString(params[0].get_str()); diff --git a/src/wallet.cpp b/src/wallet.cpp index 780c7f4..c720615 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -94,12 +94,32 @@ bool CWallet::AddKey(const CKey& key) bool CWallet::AddMalleableKey(const CMalleableKey& mKey) { CMalleableKeyView keyView = CMalleableKeyView(mKey); - if (!CCryptoKeyStore::AddMalleableKey(mKey)) + CSecret vchSecretH = mKey.GetSecretH(); + if (!CCryptoKeyStore::AddMalleableKey(keyView, vchSecretH)) return false; if (!fFileBacked) return true; if (!IsCrypted()) - return CWalletDB(strWalletFile).WriteMalleableKey(keyView, mKey, mapMalleableKeyMetadata[keyView]); + return CWalletDB(strWalletFile).WriteMalleableKey(keyView, vchSecretH, mapMalleableKeyMetadata[keyView]); + return true; +} + +bool CWallet::AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector &vchCryptedSecretH) +{ + if (!CCryptoKeyStore::AddCryptedMalleableKey(keyView, vchCryptedSecretH)) + return false; + + if (!fFileBacked) + return true; + + { + LOCK(cs_wallet); + if (pwalletdbEncryption) + return pwalletdbEncryption->WriteCryptedMalleableKey(keyView, vchCryptedSecretH, mapMalleableKeyMetadata[keyView]); + else + return CWalletDB(strWalletFile).WriteCryptedMalleableKey(keyView, vchCryptedSecretH, mapMalleableKeyMetadata[keyView]); + } + return true; } @@ -460,6 +480,16 @@ bool CWallet::DecryptWallet(const SecureString& strWalletPassphrase) mi++; } + MalleableKeyMap::const_iterator mi2 = mapMalleableKeys.begin(); + while (mi2 != mapMalleableKeys.end()) + { + const CSecret &vchSecretH = mi2->second; + const CMalleableKeyView &keyView = mi2->first; + pwalletdbDecryption->EraseCryptedMalleableKey(keyView); + pwalletdbDecryption->WriteMalleableKey(keyView, vchSecretH, mapMalleableKeyMetadata[keyView]); + mi2++; + } + // Erase master keys MasterKeyMap::const_iterator mk = mapMasterKeys.begin(); while (mk != mapMasterKeys.end()) diff --git a/src/wallet.h b/src/wallet.h index 12d8af5..d07aa7c 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -161,12 +161,14 @@ public: bool LoadMalleableKeyMetadata(const CMalleableKeyView &keyView, const CKeyMetadata &metadata); // Load malleable key without saving it to disk (used by LoadWallet) - bool LoadMalleableKey(const CMalleableKey &mKey) { return CCryptoKeyStore::AddMalleableKey(mKey); } + bool LoadMalleableKey(const CMalleableKeyView &keyView, const CSecret &vchSecretH) { return CCryptoKeyStore::AddMalleableKey(keyView, vchSecretH); } + bool LoadCryptedMalleableKey(const CMalleableKeyView &keyView, const std::vector &vchCryptedSecretH) { return CCryptoKeyStore::AddCryptedMalleableKey(keyView, vchCryptedSecretH); } bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } // Adds an encrypted key to the store, and saves it to disk. bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); + bool AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector &vchCryptedSecretH); // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { SetMinVersion(FEATURE_WALLETCRYPT); return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); } bool AddCScript(const CScript& redeemScript); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 2fe59ce..a072f18 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -304,31 +304,31 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "malpair") { - string strKey, strKeyView; + string strKeyView; CSecret vchSecret; - CMalleableKeyView keyView; - ssKey >> strKeyView; - keyView.SetString(strKeyView); ssValue >> vchSecret; - CMalleableKey mKey = keyView.GetMalleableKey(vchSecret); - - if (mKey.IsNull()) - { - strErr = "Error reading wallet database: CMalleableKey is corrupt"; - return false; - } - if (mKey.GetID() != keyView.GetID()) + CMalleableKeyView keyView(strKeyView); + if (!pwallet->LoadMalleableKey(keyView, vchSecret)) { - strErr = "Error reading wallet database: CMalleableKey view inconsistency"; + strErr = "Error reading wallet database: LoadMalleableKey failed"; return false; } + } + else if (strType == "malcpair") + { + string strKeyView; - if (!pwallet->LoadMalleableKey(mKey)) + std::vector vchCryptedSecret; + ssKey >> strKeyView; + ssValue >> vchCryptedSecret; + + CMalleableKeyView keyView(strKeyView); + if (!pwallet->LoadCryptedMalleableKey(keyView, vchCryptedSecret)) { - strErr = "Error reading wallet database: LoadMalleableKey failed"; + strErr = "Error reading wallet database: LoadCryptedMalleableKey failed"; return false; } } @@ -497,7 +497,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, static bool IsKeyType(string strType) { return (strType== "key" || strType == "wkey" || - strType == "mkey" || strType == "ckey" || strType == "malpair"); + strType == "mkey" || strType == "ckey" || strType == "malpair" || strType == "malcpair"); } DBErrors CWalletDB::LoadWallet(CWallet* pwallet) diff --git a/src/walletdb.h b/src/walletdb.h index 64a2d9f..94b355f 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -95,18 +95,32 @@ public: return true; } - bool WriteMalleableKey(const CMalleableKeyView& keyView, const CMalleableKey& malleableKey, const CKeyMetadata &keyMeta) + bool WriteMalleableKey(const CMalleableKeyView& keyView, const CSecret& vchSecretH, const CKeyMetadata &keyMeta) { nWalletDBUpdated++; if(!Write(std::make_pair(std::string("malmeta"), keyView.ToString()), keyMeta)) return false; - if(!Write(std::make_pair(std::string("malpair"), keyView.ToString()), malleableKey.GetSecretH(), false)) + if(!Write(std::make_pair(std::string("malpair"), keyView.ToString()), vchSecretH, false)) return false; return true; } + bool WriteCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector& vchCryptedSecretH, const CKeyMetadata &keyMeta) + { + nWalletDBUpdated++; + if(!Write(std::make_pair(std::string("malmeta"), keyView.ToString()), keyMeta)) + return false; + + if(!Write(std::make_pair(std::string("malcpair"), keyView.ToString()), vchCryptedSecretH, false)) + return false; + + Erase(std::make_pair(std::string("malpair"), keyView.ToString())); + + return true; + } + bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector& vchCryptedSecret, const CKeyMetadata &keyMeta) { @@ -143,6 +157,11 @@ public: return Erase(std::make_pair(std::string("ckey"), vchPubKey.Raw())); } + bool EraseCryptedMalleableKey(const CMalleableKeyView& keyView) + { + return Erase(std::make_pair(std::string("malcpair"), keyView.ToString())); + } + bool WriteCScript(const uint160& hash, const CScript& redeemScript) { nWalletDBUpdated++; -- 1.7.1