Add support for encrypting spending keys

This commit is contained in:
Jack Grigg
2016-08-10 17:47:13 +12:00
parent 80259d4b4f
commit 16d140f4a2
6 changed files with 203 additions and 2 deletions

View File

@@ -6,6 +6,7 @@
#include "script/script.h"
#include "script/standard.h"
#include "streams.h"
#include "util.h"
#include <string>
@@ -135,12 +136,31 @@ static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsi
return key.VerifyPubKey(vchPubKey);
}
static bool DecryptSpendingKey(const CKeyingMaterial& vMasterKey,
const std::vector<unsigned char>& vchCryptedSecret,
const libzcash::PaymentAddress& address,
libzcash::SpendingKey& sk)
{
CKeyingMaterial vchSecret;
if(!DecryptSecret(vMasterKey, vchCryptedSecret, address.GetHash(), vchSecret))
return false;
if (vchSecret.size() != 32)
return false;
// TODO does this undo the benefits of using CKeyingMaterial?
std::vector<unsigned char> serialized(vchSecret.begin(), vchSecret.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
ss >> sk;
return sk.address() == address;
}
bool CCryptoKeyStore::SetCrypted()
{
LOCK(cs_KeyStore);
if (fUseCrypto)
return true;
if (!mapKeys.empty())
if (!(mapKeys.empty() && mapSpendingKeys.empty()))
return false;
fUseCrypto = true;
return true;
@@ -184,6 +204,21 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
if (fDecryptionThoroughlyChecked)
break;
}
CryptedSpendingKeyMap::const_iterator skmi = mapCryptedSpendingKeys.begin();
for (; skmi != mapCryptedSpendingKeys.end(); ++skmi)
{
const libzcash::PaymentAddress &address = (*skmi).first;
const std::vector<unsigned char> &vchCryptedSecret = (*skmi).second;
libzcash::SpendingKey sk;
if (!DecryptSpendingKey(vMasterKeyIn, vchCryptedSecret, address, sk))
{
keyFail = true;
break;
}
keyPass = true;
if (fDecryptionThoroughlyChecked)
break;
}
if (keyPass && keyFail)
{
LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
@@ -267,6 +302,59 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) co
return false;
}
bool CCryptoKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk)
{
{
LOCK(cs_KeyStore);
if (!IsCrypted())
return CBasicKeyStore::AddSpendingKey(sk);
if (IsLocked())
return false;
std::vector<unsigned char> vchCryptedSecret;
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << sk;
CKeyingMaterial vchSecret(ss.begin(), ss.end());
auto address = sk.address();
if (!EncryptSecret(vMasterKey, vchSecret, address.GetHash(), vchCryptedSecret))
return false;
if (!AddCryptedSpendingKey(address, vchCryptedSecret))
return false;
}
return true;
}
bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::PaymentAddress &address, const std::vector<unsigned char> &vchCryptedSecret)
{
{
LOCK(cs_KeyStore);
if (!SetCrypted())
return false;
mapCryptedSpendingKeys[address] = vchCryptedSecret;
}
return true;
}
bool CCryptoKeyStore::GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const
{
{
LOCK(cs_KeyStore);
if (!IsCrypted())
return CBasicKeyStore::GetSpendingKey(address, skOut);
CryptedSpendingKeyMap::const_iterator mi = mapCryptedSpendingKeys.find(address);
if (mi != mapCryptedSpendingKeys.end())
{
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second;
return DecryptSpendingKey(vMasterKey, vchCryptedSecret, address, skOut);
}
}
return false;
}
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
{
@@ -287,6 +375,20 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
return false;
}
mapKeys.clear();
BOOST_FOREACH(SpendingKeyMap::value_type& mSpendingKey, mapSpendingKeys)
{
const libzcash::SpendingKey &sk = mSpendingKey.second;
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << sk;
CKeyingMaterial vchSecret(ss.begin(), ss.end());
libzcash::PaymentAddress address = sk.address();
std::vector<unsigned char> vchCryptedSecret;
if (!EncryptSecret(vMasterKeyIn, vchSecret, address.GetHash(), vchCryptedSecret))
return false;
if (!AddCryptedSpendingKey(address, vchCryptedSecret))
return false;
}
mapSpendingKeys.clear();
}
return true;
}