aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2011-06-25 14:57:32 +0200
committerMatt Corallo <matt@bluematt.me>2011-07-08 15:46:47 +0200
commitacd6501610817eee0bd1c8ea9c591f043affbaec (patch)
treee2b05a5d0bc1a0b890b2b1d6a16713967143ff95
parente94010b2395694d56dd62a2cb956a40ef801a191 (diff)
Prepare codebase for Encrypted Keys.
-rw-r--r--src/db.cpp18
-rw-r--r--src/init.cpp1
-rw-r--r--src/key.h70
-rw-r--r--src/keystore.cpp107
-rw-r--r--src/keystore.h89
-rw-r--r--src/script.cpp2
-rw-r--r--src/ui.cpp2
-rw-r--r--src/wallet.cpp9
-rw-r--r--src/wallet.h5
9 files changed, 274 insertions, 29 deletions
diff --git a/src/db.cpp b/src/db.cpp
index f044355a35..c479a452cd 100644
--- a/src/db.cpp
+++ b/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")
{
diff --git a/src/init.cpp b/src/init.cpp
index 635799ccf9..21b40d5193 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -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());
diff --git a/src/key.h b/src/key.h
index c973d6eb82..c0fce18bf3 100644
--- a/src/key.h
+++ b/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);
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 7dd045fe5f..765144a9b7 100644
--- a/src/keystore.cpp
+++ b/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;
+}
diff --git a/src/keystore.h b/src/keystore.h
index 6080d7d7f5..4095535493 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -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
diff --git a/src/script.cpp b/src/script.cpp
index bd1b5b3c5f..c17525034a 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -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)
{
diff --git a/src/ui.cpp b/src/ui.cpp
index 9b84fb9e6b..db02cb5831 100644
--- a/src/ui.cpp
+++ b/src/ui.cpp
@@ -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();
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 6ef75ef27f..a179876dcf 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -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);
diff --git a/src/wallet.h b/src/wallet.h
index 7d9db97267..8fb29a4892 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -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);