Encryption/decryption support for malleable keys.
authorCryptoManiac <balthazar@yandex.ru>
Fri, 4 Mar 2016 22:24:45 +0000 (01:24 +0300)
committerCryptoManiac <balthazar@yandex.ru>
Fri, 4 Mar 2016 22:24:45 +0000 (01:24 +0300)
src/key.cpp
src/key.h
src/keystore.cpp
src/keystore.h
src/rpcdump.cpp
src/wallet.cpp
src/wallet.h
src/walletdb.cpp
src/walletdb.h

index c11da92..6c0a57d 100644 (file)
@@ -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)
index 67c414e..3f9d8f1 100644 (file)
--- 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);
index 451f7ea..215590e 100644 (file)
@@ -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<unsigned char> 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<unsigned char> &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<unsigned char>  &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<unsigned char> 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;
index d4ac615..438752f 100644 (file)
@@ -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<CMalleableKeyView> &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<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
+typedef std::map<CMalleableKeyView, std::vector<unsigned char> > 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<unsigned char> &vchCryptedSecret);
+    virtual bool AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector<unsigned char>  &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<CMalleableKeyView> &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.
      */
index b0693ed..6a83604 100644 (file)
@@ -39,6 +39,8 @@ Value importprivkey(const Array& params, bool fHelp)
             "importprivkey <novacoinprivkey> [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 <Key view>\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 <Key data>\n"
             "Imports the private key pair into your wallet.\n");
 
+
+    EnsureWalletIsUnlocked();
+
     CMalleableKey mKey;
     bool fSuccess = mKey.SetString(params[0].get_str());
 
index 780c7f4..c720615 100644 (file)
@@ -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<unsigned char> &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())
index 12d8af5..d07aa7c 100644 (file)
@@ -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<unsigned char> &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<unsigned char> &vchCryptedSecret);
+    bool AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector<unsigned char> &vchCryptedSecretH);
     // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
     bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { SetMinVersion(FEATURE_WALLETCRYPT); return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
     bool AddCScript(const CScript& redeemScript);
index 2fe59ce..a072f18 100644 (file)
@@ -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<unsigned char> 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)
index 64a2d9f..94b355f 100644 (file)
@@ -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<unsigned char>& 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<unsigned char>& 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++;