Prepare codebase for Encrypted Keys.
This commit is contained in:
parent
e94010b239
commit
acd6501610
9 changed files with 274 additions and 29 deletions
18
src/db.cpp
18
src/db.cpp
|
@ -685,7 +685,7 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
|
|||
|
||||
//// todo: shouldn't we catch exceptions and try to recover and continue?
|
||||
CRITICAL_BLOCK(pwallet->cs_mapWallet)
|
||||
CRITICAL_BLOCK(pwallet->cs_mapKeys)
|
||||
CRITICAL_BLOCK(pwallet->cs_KeyStore)
|
||||
{
|
||||
// Get cursor
|
||||
Dbc* pcursor = GetCursor();
|
||||
|
@ -765,14 +765,20 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
|
|||
{
|
||||
vector<unsigned char> vchPubKey;
|
||||
ssKey >> vchPubKey;
|
||||
CWalletKey wkey;
|
||||
CKey key;
|
||||
if (strType == "key")
|
||||
ssValue >> wkey.vchPrivKey;
|
||||
{
|
||||
CPrivKey pkey;
|
||||
ssValue >> pkey;
|
||||
key.SetPrivKey(pkey);
|
||||
}
|
||||
else
|
||||
{
|
||||
CWalletKey wkey;
|
||||
ssValue >> wkey;
|
||||
|
||||
pwallet->mapKeys[vchPubKey] = wkey.vchPrivKey;
|
||||
mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
|
||||
key.SetPrivKey(wkey.vchPrivKey);
|
||||
}
|
||||
pwallet->LoadKey(key);
|
||||
}
|
||||
else if (strType == "defaultkey")
|
||||
{
|
||||
|
|
|
@ -416,7 +416,6 @@ bool AppInit2(int argc, char* argv[])
|
|||
//// debug print
|
||||
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
|
||||
printf("nBestHeight = %d\n", nBestHeight);
|
||||
printf("mapKeys.size() = %d\n", pwalletMain->mapKeys.size());
|
||||
printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
|
||||
printf("mapPubKeys.size() = %d\n", mapPubKeys.size());
|
||||
printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());
|
||||
|
|
70
src/key.h
70
src/key.h
|
@ -31,6 +31,41 @@
|
|||
// see www.keylength.com
|
||||
// script supports up to 75 for single byte push
|
||||
|
||||
int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
|
||||
{
|
||||
int ok = 0;
|
||||
BN_CTX *ctx = NULL;
|
||||
EC_POINT *pub_key = NULL;
|
||||
|
||||
if (!eckey) return 0;
|
||||
|
||||
const EC_GROUP *group = EC_KEY_get0_group(eckey);
|
||||
|
||||
if ((ctx = BN_CTX_new()) == NULL)
|
||||
goto err;
|
||||
|
||||
pub_key = EC_POINT_new(group);
|
||||
|
||||
if (pub_key == NULL)
|
||||
goto err;
|
||||
|
||||
if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
|
||||
goto err;
|
||||
|
||||
EC_KEY_set_private_key(eckey,priv_key);
|
||||
EC_KEY_set_public_key(eckey,pub_key);
|
||||
|
||||
ok = 1;
|
||||
|
||||
err:
|
||||
|
||||
if (pub_key)
|
||||
EC_POINT_free(pub_key);
|
||||
if (ctx != NULL)
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
return(ok);
|
||||
}
|
||||
|
||||
|
||||
class key_error : public std::runtime_error
|
||||
|
@ -42,8 +77,7 @@ public:
|
|||
|
||||
// secure_allocator is defined in serialize.h
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
|
||||
|
||||
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
|
||||
|
||||
class CKey
|
||||
{
|
||||
|
@ -102,6 +136,38 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SetSecret(const CSecret& vchSecret)
|
||||
{
|
||||
EC_KEY_free(pkey);
|
||||
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
if (pkey == NULL)
|
||||
throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
|
||||
if (vchSecret.size() != 32)
|
||||
throw key_error("CKey::SetSecret() : secret must be 32 bytes");
|
||||
BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
|
||||
if (bn == NULL)
|
||||
throw key_error("CKey::SetSecret() : BN_bin2bn failed");
|
||||
if (!EC_KEY_regenerate_key(pkey,bn))
|
||||
throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
|
||||
BN_clear_free(bn);
|
||||
fSet = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
CSecret GetSecret() const
|
||||
{
|
||||
CSecret vchRet;
|
||||
vchRet.resize(32);
|
||||
const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
|
||||
int nBytes = BN_num_bytes(bn);
|
||||
if (bn == NULL)
|
||||
throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
|
||||
int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
|
||||
if (n != nBytes)
|
||||
throw key_error("CKey::GetSecret(): BN_bn2bin failed");
|
||||
return vchRet;
|
||||
}
|
||||
|
||||
CPrivKey GetPrivKey() const
|
||||
{
|
||||
unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);
|
||||
|
|
107
src/keystore.cpp
107
src/keystore.cpp
|
@ -5,29 +5,116 @@
|
|||
#include "headers.h"
|
||||
#include "db.h"
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// mapKeys
|
||||
//
|
||||
|
||||
std::vector<unsigned char> CKeyStore::GenerateNewKey()
|
||||
{
|
||||
RandAddSeedPerfmon();
|
||||
CKey key;
|
||||
key.MakeNewKey();
|
||||
if (!AddKey(key))
|
||||
throw std::runtime_error("GenerateNewKey() : AddKey failed");
|
||||
throw std::runtime_error("CKeyStore::GenerateNewKey() : AddKey failed");
|
||||
return key.GetPubKey();
|
||||
}
|
||||
|
||||
bool CKeyStore::AddKey(const CKey& key)
|
||||
bool CBasicKeyStore::AddKey(const CKey& key)
|
||||
{
|
||||
CRITICAL_BLOCK(cs_mapKeys)
|
||||
CRITICAL_BLOCK(cs_KeyStore)
|
||||
{
|
||||
mapKeys[key.GetPubKey()] = key.GetPrivKey();
|
||||
mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::Unlock(const CMasterKey& vMasterKeyIn)
|
||||
{
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
|
||||
std::map<std::vector<unsigned char>, std::vector<unsigned char> >::const_iterator mi = mapCryptedKeys.begin();
|
||||
for (; mi != mapCryptedKeys.end(); ++mi)
|
||||
{
|
||||
const std::vector<unsigned char> &vchPubKey = (*mi).first;
|
||||
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second;
|
||||
CSecret vchSecret;
|
||||
// decrypt vchCryptedSecret using vMasterKeyIn, into vchSecret
|
||||
CKey key;
|
||||
key.SetSecret(vchSecret);
|
||||
if (key.GetPubKey() == vchPubKey)
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
vMasterKey = vMasterKeyIn;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::AddKey(const CKey& key)
|
||||
{
|
||||
CRITICAL_BLOCK(cs_KeyStore)
|
||||
{
|
||||
if (!IsCrypted())
|
||||
return CBasicKeyStore::AddKey(key);
|
||||
|
||||
if (IsLocked())
|
||||
return false;
|
||||
|
||||
CSecret vchSecret = key.GetSecret();
|
||||
|
||||
std::vector<unsigned char> vchCryptedSecret;
|
||||
// encrypt vchSecret using vMasterKey, into vchCryptedSecret
|
||||
|
||||
AddCryptedKey(key.GetPubKey(), vchCryptedSecret);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
|
||||
{
|
||||
CRITICAL_BLOCK(cs_KeyStore)
|
||||
{
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
|
||||
mapCryptedKeys[vchPubKey] = vchCryptedSecret;
|
||||
mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::GetPrivKey(const std::vector<unsigned char> &vchPubKey, CPrivKey& keyOut) const
|
||||
{
|
||||
if (!IsCrypted())
|
||||
return CBasicKeyStore::GetPrivKey(vchPubKey, keyOut);
|
||||
|
||||
std::map<std::vector<unsigned char>, std::vector<unsigned char> >::const_iterator mi = mapCryptedKeys.find(vchPubKey);
|
||||
if (mi != mapCryptedKeys.end())
|
||||
{
|
||||
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second;
|
||||
CSecret vchSecret;
|
||||
// decrypt vchCryptedSecret using vMasterKey into vchSecret;
|
||||
CKey key;
|
||||
key.SetSecret(vchSecret);
|
||||
keyOut = key.GetPrivKey();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::GenerateMasterKey()
|
||||
{
|
||||
if (!mapCryptedKeys.empty())
|
||||
return false;
|
||||
|
||||
RandAddSeedPerfmon();
|
||||
|
||||
vMasterKey.resize(32);
|
||||
RAND_bytes(&vMasterKey[0], 32);
|
||||
|
||||
if (!IsCrypted())
|
||||
{
|
||||
// upgrade wallet
|
||||
fUseCrypto = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -4,12 +4,26 @@
|
|||
#ifndef BITCOIN_KEYSTORE_H
|
||||
#define BITCOIN_KEYSTORE_H
|
||||
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CMasterKey;
|
||||
|
||||
class CKeyStore
|
||||
{
|
||||
public:
|
||||
mutable CCriticalSection cs_KeyStore;
|
||||
|
||||
virtual bool AddKey(const CKey& key) =0;
|
||||
virtual bool HaveKey(const std::vector<unsigned char> &vchPubKey) const =0;
|
||||
virtual bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CPrivKey& keyOut) const =0;
|
||||
virtual std::vector<unsigned char> GenerateNewKey();
|
||||
};
|
||||
|
||||
class CBasicKeyStore : public CKeyStore
|
||||
{
|
||||
protected:
|
||||
std::map<std::vector<unsigned char>, CPrivKey> mapKeys;
|
||||
mutable CCriticalSection cs_mapKeys;
|
||||
virtual bool AddKey(const CKey& key);
|
||||
|
||||
public:
|
||||
bool AddKey(const CKey& key);
|
||||
bool HaveKey(const std::vector<unsigned char> &vchPubKey) const
|
||||
{
|
||||
return (mapKeys.count(vchPubKey) > 0);
|
||||
|
@ -24,7 +38,76 @@ public:
|
|||
}
|
||||
return false;
|
||||
}
|
||||
std::vector<unsigned char> GenerateNewKey();
|
||||
};
|
||||
|
||||
class CCryptoKeyStore : public CBasicKeyStore
|
||||
{
|
||||
private:
|
||||
std::map<std::vector<unsigned char>, std::vector<unsigned char> > mapCryptedKeys;
|
||||
|
||||
CMasterKey vMasterKey;
|
||||
|
||||
// if fUseCrypto is true, mapKeys must be empty
|
||||
// if fUseCrypto is false, vMasterKey must be empty
|
||||
bool fUseCrypto;
|
||||
|
||||
protected:
|
||||
bool IsCrypted() const
|
||||
{
|
||||
return fUseCrypto;
|
||||
}
|
||||
|
||||
bool SetCrypted()
|
||||
{
|
||||
if (fUseCrypto)
|
||||
return true;
|
||||
if (!mapKeys.empty())
|
||||
return false;
|
||||
fUseCrypto = true;
|
||||
}
|
||||
|
||||
// will encrypt previously unencrypted keys
|
||||
bool GenerateMasterKey();
|
||||
|
||||
bool GetMasterKey(CMasterKey &vMasterKeyOut) const
|
||||
{
|
||||
if (!IsCrypted())
|
||||
return false;
|
||||
if (IsLocked())
|
||||
return false;
|
||||
vMasterKeyOut = vMasterKey;
|
||||
return true;
|
||||
}
|
||||
bool Unlock(const CMasterKey& vMasterKeyIn);
|
||||
|
||||
public:
|
||||
CCryptoKeyStore() : fUseCrypto(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsLocked() const
|
||||
{
|
||||
if (!IsCrypted())
|
||||
return false;
|
||||
return vMasterKey.empty();
|
||||
}
|
||||
|
||||
bool Lock()
|
||||
{
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
vMasterKey.clear();
|
||||
}
|
||||
|
||||
virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool AddKey(const CKey& key);
|
||||
bool HaveKey(const std::vector<unsigned char> &vchPubKey) const
|
||||
{
|
||||
if (!IsCrypted())
|
||||
return CBasicKeyStore::HaveKey(vchPubKey);
|
||||
return mapCryptedKeys.count(vchPubKey) > 0;
|
||||
}
|
||||
bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CPrivKey& keyOut) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1030,7 +1030,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
|
|||
return false;
|
||||
|
||||
// Compile solution
|
||||
CRITICAL_BLOCK(keystore.cs_mapKeys)
|
||||
CRITICAL_BLOCK(keystore.cs_KeyStore)
|
||||
{
|
||||
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
|
||||
{
|
||||
|
|
|
@ -2382,7 +2382,7 @@ CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInit
|
|||
m_listCtrlReceiving->SetFocus();
|
||||
|
||||
// Fill listctrl with address book data
|
||||
CRITICAL_BLOCK(pwalletMain->cs_mapKeys)
|
||||
CRITICAL_BLOCK(pwalletMain->cs_KeyStore)
|
||||
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
|
||||
{
|
||||
string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
|
||||
|
|
|
@ -17,7 +17,8 @@ using namespace std;
|
|||
|
||||
bool CWallet::AddKey(const CKey& key)
|
||||
{
|
||||
this->CKeyStore::AddKey(key);
|
||||
if (!CBasicKeyStore::AddKey(key))
|
||||
return false;
|
||||
if (!fFileBacked)
|
||||
return true;
|
||||
return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
|
||||
|
@ -783,7 +784,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW
|
|||
|
||||
// Reserve a new key pair from key pool
|
||||
vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
|
||||
assert(mapKeys.count(vchPubKey));
|
||||
// assert(mapKeys.count(vchPubKey));
|
||||
|
||||
// Fill a vout to ourself, using same address type as the payment
|
||||
CScript scriptChange;
|
||||
|
@ -957,7 +958,7 @@ bool CWallet::LoadWallet(bool& fFirstRunRet)
|
|||
|
||||
if (!mapKeys.count(vchDefaultKey))
|
||||
{
|
||||
// Create new default key
|
||||
// Create new keyUser and set as default key
|
||||
RandAddSeedPerfmon();
|
||||
|
||||
SetDefaultKey(GetKeyFromKeyPool());
|
||||
|
@ -1062,7 +1063,7 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
|
|||
setKeyPool.erase(setKeyPool.begin());
|
||||
if (!walletdb.ReadPool(nIndex, keypool))
|
||||
throw runtime_error("ReserveKeyFromKeyPool() : read failed");
|
||||
if (!mapKeys.count(keypool.vchPubKey))
|
||||
if (!HaveKey(keypool.vchPubKey))
|
||||
throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
|
||||
assert(!keypool.vchPubKey.empty());
|
||||
printf("keypool reserve %"PRI64d"\n", nIndex);
|
||||
|
|
|
@ -12,7 +12,7 @@ class CWalletTx;
|
|||
class CReserveKey;
|
||||
class CWalletDB;
|
||||
|
||||
class CWallet : public CKeyStore
|
||||
class CWallet : public CCryptoKeyStore
|
||||
{
|
||||
private:
|
||||
bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
|
||||
|
@ -48,7 +48,10 @@ public:
|
|||
|
||||
std::vector<unsigned char> vchDefaultKey;
|
||||
|
||||
// keystore implementation
|
||||
bool AddKey(const CKey& key);
|
||||
bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
|
||||
|
||||
bool AddToWallet(const CWalletTx& wtxIn);
|
||||
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false);
|
||||
bool EraseFromWallet(uint256 hash);
|
||||
|
|
Loading…
Reference in a new issue