Skip to content

Commit

Permalink
Prepare codebase for Encrypted Keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa authored and Matt Corallo committed Jul 8, 2011
1 parent e94010b commit acd6501
Show file tree
Hide file tree
Showing 9 changed files with 274 additions and 29 deletions.
18 changes: 12 additions & 6 deletions src/db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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")
{
Expand Down
1 change: 0 additions & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
70 changes: 68 additions & 2 deletions src/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -42,8 +77,7 @@ class key_error : public std::runtime_error

// 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
{
Expand Down Expand Up @@ -102,6 +136,38 @@ class CKey
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);
Expand Down
107 changes: 97 additions & 10 deletions src/keystore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
89 changes: 86 additions & 3 deletions src/keystore.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -24,7 +38,76 @@ class CKeyStore
}
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
2 changes: 1 addition & 1 deletion src/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
2 changes: 1 addition & 1 deletion src/ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading

0 comments on commit acd6501

Please sign in to comment.