Browse Source

Prepare codebase for Encrypted Keys.

0.8
Pieter Wuille 14 years ago committed by Matt Corallo
parent
commit
acd6501610
  1. 18
      src/db.cpp
  2. 1
      src/init.cpp
  3. 70
      src/key.h
  4. 107
      src/keystore.cpp
  5. 89
      src/keystore.h
  6. 2
      src/script.cpp
  7. 2
      src/ui.cpp
  8. 9
      src/wallet.cpp
  9. 5
      src/wallet.h

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? //// todo: shouldn't we catch exceptions and try to recover and continue?
CRITICAL_BLOCK(pwallet->cs_mapWallet) CRITICAL_BLOCK(pwallet->cs_mapWallet)
CRITICAL_BLOCK(pwallet->cs_mapKeys) CRITICAL_BLOCK(pwallet->cs_KeyStore)
{ {
// Get cursor // Get cursor
Dbc* pcursor = GetCursor(); Dbc* pcursor = GetCursor();
@ -765,14 +765,20 @@ bool CWalletDB::LoadWallet(CWallet* pwallet)
{ {
vector<unsigned char> vchPubKey; vector<unsigned char> vchPubKey;
ssKey >> vchPubKey; ssKey >> vchPubKey;
CWalletKey wkey; CKey key;
if (strType == "key") if (strType == "key")
ssValue >> wkey.vchPrivKey; {
CPrivKey pkey;
ssValue >> pkey;
key.SetPrivKey(pkey);
}
else else
{
CWalletKey wkey;
ssValue >> wkey; ssValue >> wkey;
key.SetPrivKey(wkey.vchPrivKey);
pwallet->mapKeys[vchPubKey] = wkey.vchPrivKey; }
mapPubKeys[Hash160(vchPubKey)] = vchPubKey; pwallet->LoadKey(key);
} }
else if (strType == "defaultkey") else if (strType == "defaultkey")
{ {

1
src/init.cpp

@ -416,7 +416,6 @@ bool AppInit2(int argc, char* argv[])
//// debug print //// debug print
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size()); printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
printf("nBestHeight = %d\n", nBestHeight); printf("nBestHeight = %d\n", nBestHeight);
printf("mapKeys.size() = %d\n", pwalletMain->mapKeys.size());
printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size()); printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
printf("mapPubKeys.size() = %d\n", mapPubKeys.size()); printf("mapPubKeys.size() = %d\n", mapPubKeys.size());
printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size()); printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());

70
src/key.h

@ -31,6 +31,41 @@
// see www.keylength.com // see www.keylength.com
// script supports up to 75 for single byte push // 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 class key_error : public std::runtime_error
@ -42,8 +77,7 @@ public:
// secure_allocator is defined in serialize.h // 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> > CPrivKey;
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
class CKey class CKey
{ {
@ -102,6 +136,38 @@ public:
return true; 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 CPrivKey GetPrivKey() const
{ {
unsigned int nSize = i2d_ECPrivateKey(pkey, NULL); unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);

107
src/keystore.cpp

@ -5,29 +5,116 @@
#include "headers.h" #include "headers.h"
#include "db.h" #include "db.h"
//////////////////////////////////////////////////////////////////////////////
//
// mapKeys
//
std::vector<unsigned char> CKeyStore::GenerateNewKey() std::vector<unsigned char> CKeyStore::GenerateNewKey()
{ {
RandAddSeedPerfmon(); RandAddSeedPerfmon();
CKey key; CKey key;
key.MakeNewKey(); key.MakeNewKey();
if (!AddKey(key)) if (!AddKey(key))
throw std::runtime_error("GenerateNewKey() : AddKey failed"); throw std::runtime_error("CKeyStore::GenerateNewKey() : AddKey failed");
return key.GetPubKey(); 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(); mapKeys[key.GetPubKey()] = key.GetPrivKey();
mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey(); 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;
}

89
src/keystore.h

@ -4,12 +4,26 @@
#ifndef BITCOIN_KEYSTORE_H #ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H #define BITCOIN_KEYSTORE_H
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CMasterKey;
class CKeyStore class CKeyStore
{ {
public: 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; 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 bool HaveKey(const std::vector<unsigned char> &vchPubKey) const
{ {
return (mapKeys.count(vchPubKey) > 0); return (mapKeys.count(vchPubKey) > 0);
@ -24,7 +38,76 @@ public:
} }
return false; 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 #endif

2
src/script.cpp

@ -1030,7 +1030,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
return false; return false;
// Compile solution // Compile solution
CRITICAL_BLOCK(keystore.cs_mapKeys) CRITICAL_BLOCK(keystore.cs_KeyStore)
{ {
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{ {

2
src/ui.cpp

@ -2382,7 +2382,7 @@ CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInit
m_listCtrlReceiving->SetFocus(); m_listCtrlReceiving->SetFocus();
// Fill listctrl with address book data // Fill listctrl with address book data
CRITICAL_BLOCK(pwalletMain->cs_mapKeys) CRITICAL_BLOCK(pwalletMain->cs_KeyStore)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{ {
string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue(); string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();

9
src/wallet.cpp

@ -17,7 +17,8 @@ using namespace std;
bool CWallet::AddKey(const CKey& key) bool CWallet::AddKey(const CKey& key)
{ {
this->CKeyStore::AddKey(key); if (!CBasicKeyStore::AddKey(key))
return false;
if (!fFileBacked) if (!fFileBacked)
return true; return true;
return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey()); 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 // Reserve a new key pair from key pool
vector<unsigned char> vchPubKey = reservekey.GetReservedKey(); 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 // Fill a vout to ourself, using same address type as the payment
CScript scriptChange; CScript scriptChange;
@ -957,7 +958,7 @@ bool CWallet::LoadWallet(bool& fFirstRunRet)
if (!mapKeys.count(vchDefaultKey)) if (!mapKeys.count(vchDefaultKey))
{ {
// Create new default key // Create new keyUser and set as default key
RandAddSeedPerfmon(); RandAddSeedPerfmon();
SetDefaultKey(GetKeyFromKeyPool()); SetDefaultKey(GetKeyFromKeyPool());
@ -1062,7 +1063,7 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
setKeyPool.erase(setKeyPool.begin()); setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool)) if (!walletdb.ReadPool(nIndex, keypool))
throw runtime_error("ReserveKeyFromKeyPool() : read failed"); throw runtime_error("ReserveKeyFromKeyPool() : read failed");
if (!mapKeys.count(keypool.vchPubKey)) if (!HaveKey(keypool.vchPubKey))
throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
assert(!keypool.vchPubKey.empty()); assert(!keypool.vchPubKey.empty());
printf("keypool reserve %"PRI64d"\n", nIndex); printf("keypool reserve %"PRI64d"\n", nIndex);

5
src/wallet.h

@ -12,7 +12,7 @@ class CWalletTx;
class CReserveKey; class CReserveKey;
class CWalletDB; class CWalletDB;
class CWallet : public CKeyStore class CWallet : public CCryptoKeyStore
{ {
private: private:
bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; 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; std::vector<unsigned char> vchDefaultKey;
// keystore implementation
bool AddKey(const CKey& key); bool AddKey(const CKey& key);
bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
bool AddToWallet(const CWalletTx& wtxIn); bool AddToWallet(const CWalletTx& wtxIn);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false);
bool EraseFromWallet(uint256 hash); bool EraseFromWallet(uint256 hash);

Loading…
Cancel
Save