Auto merge of #1372 - str4d:1199-spending-key-wallet-encryption, r=str4d
Encrypt spending keys in the wallet This is a continuation of #1210.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "script/script.h"
|
||||
#include "script/standard.h"
|
||||
#include "streams.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <string>
|
||||
@@ -135,12 +136,29 @@ 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() != libzcash::SerializedSpendingKeySize)
|
||||
return false;
|
||||
|
||||
CSecureDataStream ss(vchSecret, 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 +202,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,10 +300,66 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) co
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk)
|
||||
{
|
||||
{
|
||||
LOCK(cs_SpendingKeyStore);
|
||||
if (!IsCrypted())
|
||||
return CBasicKeyStore::AddSpendingKey(sk);
|
||||
|
||||
if (IsLocked())
|
||||
return false;
|
||||
|
||||
std::vector<unsigned char> vchCryptedSecret;
|
||||
CSecureDataStream 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, sk.viewing_key(), vchCryptedSecret))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::PaymentAddress &address,
|
||||
const libzcash::ViewingKey &vk,
|
||||
const std::vector<unsigned char> &vchCryptedSecret)
|
||||
{
|
||||
{
|
||||
LOCK(cs_SpendingKeyStore);
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
|
||||
mapCryptedSpendingKeys[address] = vchCryptedSecret;
|
||||
mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(vk)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const
|
||||
{
|
||||
{
|
||||
LOCK(cs_SpendingKeyStore);
|
||||
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)
|
||||
{
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
LOCK2(cs_KeyStore, cs_SpendingKeyStore);
|
||||
if (!mapCryptedKeys.empty() || IsCrypted())
|
||||
return false;
|
||||
|
||||
@@ -287,6 +376,20 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
|
||||
return false;
|
||||
}
|
||||
mapKeys.clear();
|
||||
BOOST_FOREACH(SpendingKeyMap::value_type& mSpendingKey, mapSpendingKeys)
|
||||
{
|
||||
const libzcash::SpendingKey &sk = mSpendingKey.second;
|
||||
CSecureDataStream 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, sk.viewing_key(), vchCryptedSecret))
|
||||
return false;
|
||||
}
|
||||
mapSpendingKeys.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
|
||||
#include "keystore.h"
|
||||
#include "serialize.h"
|
||||
#include "streams.h"
|
||||
#include "support/allocators/secure.h"
|
||||
#include "zcash/Address.hpp"
|
||||
|
||||
class uint256;
|
||||
|
||||
@@ -66,6 +68,18 @@ public:
|
||||
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
|
||||
|
||||
class CSecureDataStream : public CBaseDataStream<CKeyingMaterial>
|
||||
{
|
||||
public:
|
||||
explicit CSecureDataStream(int nTypeIn, int nVersionIn) : CBaseDataStream(nTypeIn, nVersionIn) { }
|
||||
|
||||
CSecureDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) :
|
||||
CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
|
||||
|
||||
CSecureDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) :
|
||||
CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
|
||||
};
|
||||
|
||||
/** Encryption/decryption context with key information */
|
||||
class CCrypter
|
||||
{
|
||||
@@ -114,10 +128,11 @@ class CCryptoKeyStore : public CBasicKeyStore
|
||||
{
|
||||
private:
|
||||
CryptedKeyMap mapCryptedKeys;
|
||||
CryptedSpendingKeyMap mapCryptedSpendingKeys;
|
||||
|
||||
CKeyingMaterial vMasterKey;
|
||||
|
||||
//! if fUseCrypto is true, mapKeys must be empty
|
||||
//! if fUseCrypto is true, mapKeys and mapSpendingKeys must be empty
|
||||
//! if fUseCrypto is false, vMasterKey must be empty
|
||||
bool fUseCrypto;
|
||||
|
||||
@@ -185,6 +200,36 @@ public:
|
||||
mi++;
|
||||
}
|
||||
}
|
||||
virtual bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address,
|
||||
const libzcash::ViewingKey &vk,
|
||||
const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool AddSpendingKey(const libzcash::SpendingKey &sk);
|
||||
bool HaveSpendingKey(const libzcash::PaymentAddress &address) const
|
||||
{
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (!IsCrypted())
|
||||
return CBasicKeyStore::HaveSpendingKey(address);
|
||||
return mapCryptedSpendingKeys.count(address) > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const;
|
||||
void GetPaymentAddresses(std::set<libzcash::PaymentAddress> &setAddress) const
|
||||
{
|
||||
if (!IsCrypted())
|
||||
{
|
||||
CBasicKeyStore::GetPaymentAddresses(setAddress);
|
||||
return;
|
||||
}
|
||||
setAddress.clear();
|
||||
CryptedSpendingKeyMap::const_iterator mi = mapCryptedSpendingKeys.begin();
|
||||
while (mi != mapCryptedSpendingKeys.end())
|
||||
{
|
||||
setAddress.insert((*mi).first);
|
||||
mi++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wallet status (encrypted, locked) changed.
|
||||
|
||||
Reference in New Issue
Block a user