commit e9707e8ec7ef058c0ff08b6b454f0393843c5ff0 Author: Jeff Garzik Date: Sat Mar 26 16:50:30 2011 -0400 Add wallet privkey encryption, and use it for all new keys diff --git a/crypter.h b/crypter.h new file mode 100644 index 0000000..c119dc9 --- /dev/null +++ b/crypter.h @@ -0,0 +1,64 @@ +#ifndef __CRYPTER_H__ +#define __CRYPTER_H__ + +class CCrypter +{ +protected: + EVP_CIPHER_CTX e_ctx; + EVP_CIPHER_CTX d_ctx; + +public: + bool SetKey(const unsigned char *keyData, int keyData_len, + const unsigned char *salt) + { + int nrounds = 1000; + unsigned char key[32], iv[32]; + + int i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha256(), salt, + keyData, keyData_len, nrounds, key, iv); + if (i != 32) + return false; + + EVP_CIPHER_CTX_init(&e_ctx); + EVP_EncryptInit_ex(&e_ctx, EVP_aes_256_cbc(), NULL, key, iv); + EVP_CIPHER_CTX_init(&d_ctx); + EVP_DecryptInit_ex(&d_ctx, EVP_aes_256_cbc(), NULL, key, iv); + + return true; + } + + vector Encrypt(vector vchPlaintext) + { + // max ciphertext len for a n bytes of plaintext is + // n + AES_BLOCK_SIZE - 1 bytes + int len = vchPlaintext.size(); + int c_len = len + AES_BLOCK_SIZE, f_len = 0; + vector vchCiphertext(c_len); + + EVP_EncryptInit_ex(&e_ctx, NULL, NULL, NULL, NULL); + EVP_EncryptUpdate(&e_ctx, &vchCiphertext[0], &c_len, + &vchPlaintext[0], len); + EVP_EncryptFinal_ex(&e_ctx, (&vchCiphertext[0])+c_len, &f_len); + + vchCiphertext.resize(c_len + f_len); + return vchCiphertext; + } + + vector Decrypt(vector vchCiphertext) + { + // plaintext will always be equal to or lesser than length of ciphertext + int len = vchCiphertext.size(); + int p_len = len, f_len = 0; + vector vchPlaintext(p_len); + + EVP_DecryptInit_ex(&d_ctx, NULL, NULL, NULL, NULL); + EVP_DecryptUpdate(&d_ctx, &vchPlaintext[0], &p_len, + &vchCiphertext[0], len); + EVP_DecryptFinal_ex(&d_ctx, (&vchPlaintext[0])+p_len, &f_len); + + vchPlaintext.resize(p_len + f_len); + return vchPlaintext; + } +}; + +#endif /* __CRYPTER_H__ */ diff --git a/db.cpp b/db.cpp index aaa997b..6e5c31a 100644 --- a/db.cpp +++ b/db.cpp @@ -744,6 +744,25 @@ bool CWalletDB::LoadWallet() if (nNumber > nAccountingEntryNumber) nAccountingEntryNumber = nNumber; } + else if (strType == "ekey") + { + vector vchPubKey; + ssKey >> vchPubKey; + + vector vchCiphertext; + ssKey >> vchCiphertext; + + vector vchPlaintext; + vchPlaintext = cWalletCrypter.Decrypt(vchCiphertext); + + CWalletKey wkey; + wkey.vchPrivKey.resize(vchPlaintext.size()); + memcpy(&wkey.vchPrivKey[0], &vchPlaintext[0], + vchPlaintext.size()); + + mapKeys[vchPubKey] = wkey.vchPrivKey; + mapPubKeys[Hash160(vchPubKey)] = vchPubKey; + } else if (strType == "key" || strType == "wkey") { vector vchPubKey; diff --git a/db.h b/db.h index c9c40d5..9d8ba80 100644 --- a/db.h +++ b/db.h @@ -399,10 +399,11 @@ public: return Read(make_pair(string("key"), vchPubKey), vchPrivKey); } - bool WriteKey(const vector& vchPubKey, const CPrivKey& vchPrivKey) + bool WriteKey(const vector& vchPubKey, + const vector& vchCiphertext) { nWalletDBUpdated++; - return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false); + return Write(make_pair(string("ekey"), vchPubKey), vchCiphertext,false); } bool ReadDefaultKey(vector& vchPubKey) diff --git a/headers.h b/headers.h index 6a08cb7..964fa14 100644 --- a/headers.h +++ b/headers.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -117,6 +118,7 @@ using namespace boost; #include "uint256.h" #include "util.h" #include "key.h" +#include "crypter.h" #include "bignum.h" #include "base58.h" #include "script.h" diff --git a/init.cpp b/init.cpp index 8c70ba2..0647d8f 100644 --- a/init.cpp +++ b/init.cpp @@ -326,6 +326,36 @@ bool AppInit2(int argc, char* argv[]) } } + // obtain wallet encrypt/decrypt key, from passphrase + string strWalletPass = getenv("WALLET_PASSPHRASE"); + +#ifdef GUI + if (!strWalletPass.size()) { + strWalletPass = wxGetPasswordFromUser( + _("Input passphrase to decrypt wallet"), _("Password")); + } +#endif + if (!strWalletPass.size()) { +#ifdef GUI + wxMessageBox(_("Wallet decryption password not supplied"), "Bitcoin"); +#else + fprintf(stderr, "Wallet decryption password not supplied\n"); +#endif + return false; + } + + string strSalt = "bitcoin is fun!"; + if (!cWalletCrypter.SetKey((const unsigned char *)strWalletPass.c_str(), + strWalletPass.size(), + (const unsigned char *)strSalt.c_str())) { +#ifdef GUI + wxMessageBox(_("Wallet decryption setup failed"), "Bitcoin"); +#else + fprintf(stderr, "Wallet decryption setup failed\n"); +#endif + return false; + } + // // Load data files // diff --git a/main.cpp b/main.cpp index bfc45af..f43fe9c 100644 --- a/main.cpp +++ b/main.cpp @@ -41,6 +41,7 @@ map mapWallet; vector vWalletUpdated; CCriticalSection cs_mapWallet; +CCrypter cWalletCrypter; map, CPrivKey> mapKeys; map > mapPubKeys; CCriticalSection cs_mapKeys; @@ -83,7 +84,14 @@ bool AddKey(const CKey& key) mapKeys[key.GetPubKey()] = key.GetPrivKey(); mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey(); } - return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey()); + + CPrivKey privKey = key.GetPrivKey(); + vector vchPlaintext(privKey.size()); + memcpy(&vchPlaintext[0], &privKey[0], privKey.size()); + + vector vchCiphertext; + vchCiphertext = cWalletCrypter.Encrypt(vchPlaintext); + return CWalletDB().WriteKey(key.GetPubKey(), vchCiphertext); } vector GenerateNewKey() diff --git a/main.h b/main.h index e9d0c00..f104d93 100644 --- a/main.h +++ b/main.h @@ -46,6 +46,7 @@ extern CCriticalSection cs_mapAddressBook; extern vector vchDefaultKey; extern double dHashesPerSec; extern int64 nHPSTimerStart; +extern CCrypter cWalletCrypter; // Settings extern int fGenerateBitcoins;