Jeff Garzik
14 years ago
24 changed files with 1588 additions and 160 deletions
@ -0,0 +1,132 @@
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2011 The Bitcoin Developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <openssl/aes.h> |
||||
#include <openssl/evp.h> |
||||
#include <vector> |
||||
#include <string> |
||||
#include "headers.h" |
||||
#ifdef __WXMSW__ |
||||
#include <windows.h> |
||||
#endif |
||||
|
||||
#include "crypter.h" |
||||
#include "main.h" |
||||
#include "util.h" |
||||
|
||||
bool CCrypter::SetKeyFromPassphrase(const std::string& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod) |
||||
{ |
||||
if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE) |
||||
return false; |
||||
|
||||
// Try to keep the keydata out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap)
|
||||
// Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
|
||||
// Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process.
|
||||
mlock(&chKey[0], sizeof chKey); |
||||
mlock(&chIV[0], sizeof chIV); |
||||
|
||||
int i = 0; |
||||
if (nDerivationMethod == 0) |
||||
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0], |
||||
(unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV); |
||||
|
||||
if (i != WALLET_CRYPTO_KEY_SIZE) |
||||
{ |
||||
memset(&chKey, 0, sizeof chKey); |
||||
memset(&chIV, 0, sizeof chIV); |
||||
return false; |
||||
} |
||||
|
||||
fKeySet = true; |
||||
return true; |
||||
} |
||||
|
||||
bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV) |
||||
{ |
||||
if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE) |
||||
return false; |
||||
|
||||
// Try to keep the keydata out of swap
|
||||
// Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
|
||||
// Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process.
|
||||
mlock(&chKey[0], sizeof chKey); |
||||
mlock(&chIV[0], sizeof chIV); |
||||
|
||||
memcpy(&chKey[0], &chNewKey[0], sizeof chKey); |
||||
memcpy(&chIV[0], &chNewIV[0], sizeof chIV); |
||||
|
||||
fKeySet = true; |
||||
return true; |
||||
} |
||||
|
||||
bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) |
||||
{ |
||||
if (!fKeySet) |
||||
return false; |
||||
|
||||
// max ciphertext len for a n bytes of plaintext is
|
||||
// n + AES_BLOCK_SIZE - 1 bytes
|
||||
int nLen = vchPlaintext.size(); |
||||
int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0; |
||||
vchCiphertext = std::vector<unsigned char> (nCLen); |
||||
|
||||
EVP_CIPHER_CTX ctx; |
||||
|
||||
EVP_CIPHER_CTX_init(&ctx); |
||||
EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV); |
||||
|
||||
EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen); |
||||
EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0])+nCLen, &nFLen); |
||||
|
||||
EVP_CIPHER_CTX_cleanup(&ctx); |
||||
|
||||
vchCiphertext.resize(nCLen + nFLen); |
||||
return true; |
||||
} |
||||
|
||||
bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) |
||||
{ |
||||
if (!fKeySet) |
||||
return false; |
||||
|
||||
// plaintext will always be equal to or lesser than length of ciphertext
|
||||
int nLen = vchCiphertext.size(); |
||||
int nPLen = nLen, nFLen = 0; |
||||
|
||||
vchPlaintext = CKeyingMaterial(nPLen); |
||||
|
||||
EVP_CIPHER_CTX ctx; |
||||
|
||||
EVP_CIPHER_CTX_init(&ctx); |
||||
EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV); |
||||
|
||||
EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen); |
||||
EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0])+nPLen, &nFLen); |
||||
|
||||
EVP_CIPHER_CTX_cleanup(&ctx); |
||||
|
||||
vchPlaintext.resize(nPLen + nFLen); |
||||
return true; |
||||
} |
||||
|
||||
|
||||
bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext) |
||||
{ |
||||
CCrypter cKeyCrypter; |
||||
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE); |
||||
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); |
||||
if(!cKeyCrypter.SetKey(vMasterKey, chIV)) |
||||
return false; |
||||
return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext); |
||||
} |
||||
|
||||
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext) |
||||
{ |
||||
CCrypter cKeyCrypter; |
||||
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE); |
||||
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); |
||||
if(!cKeyCrypter.SetKey(vMasterKey, chIV)) |
||||
return false; |
||||
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext)); |
||||
} |
@ -0,0 +1,96 @@
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2011 The Bitcoin Developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef __CRYPTER_H__ |
||||
#define __CRYPTER_H__ |
||||
|
||||
#include "key.h" |
||||
|
||||
const unsigned int WALLET_CRYPTO_KEY_SIZE = 32; |
||||
const unsigned int WALLET_CRYPTO_SALT_SIZE = 8; |
||||
|
||||
/*
|
||||
Private key encryption is done based on a CMasterKey, |
||||
which holds a salt and random encryption key. |
||||
|
||||
CMasterKeys is encrypted using AES-256-CBC using a key |
||||
derived using derivation method nDerivationMethod |
||||
(0 == EVP_sha512()) and derivation iterations nDeriveIterations. |
||||
vchOtherDerivationParameters is provided for alternative algorithms |
||||
which may require more parameters (such as scrypt). |
||||
|
||||
Wallet Private Keys are then encrypted using AES-256-CBC |
||||
with the double-sha256 of the private key as the IV, and the |
||||
master key's key as the encryption key. |
||||
*/ |
||||
|
||||
class CMasterKey |
||||
{ |
||||
public: |
||||
std::vector<unsigned char> vchCryptedKey; |
||||
std::vector<unsigned char> vchSalt; |
||||
// 0 = EVP_sha512()
|
||||
// 1 = scrypt()
|
||||
unsigned int nDerivationMethod; |
||||
unsigned int nDeriveIterations; |
||||
// Use this for more parameters to key derivation,
|
||||
// such as the various parameters to scrypt
|
||||
std::vector<unsigned char> vchOtherDerivationParameters; |
||||
|
||||
IMPLEMENT_SERIALIZE |
||||
( |
||||
READWRITE(vchCryptedKey); |
||||
READWRITE(vchSalt); |
||||
READWRITE(nDerivationMethod); |
||||
READWRITE(nDeriveIterations); |
||||
READWRITE(vchOtherDerivationParameters); |
||||
) |
||||
CMasterKey() |
||||
{ |
||||
// 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M
|
||||
// ie slightly lower than the lowest hardware we need bother supporting
|
||||
nDeriveIterations = 25000; |
||||
nDerivationMethod = 0; |
||||
vchOtherDerivationParameters = std::vector<unsigned char>(0); |
||||
} |
||||
}; |
||||
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial; |
||||
|
||||
class CCrypter |
||||
{ |
||||
private: |
||||
unsigned char chKey[WALLET_CRYPTO_KEY_SIZE]; |
||||
unsigned char chIV[WALLET_CRYPTO_KEY_SIZE]; |
||||
bool fKeySet; |
||||
|
||||
public: |
||||
bool SetKeyFromPassphrase(const std::string &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod); |
||||
bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext); |
||||
bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext); |
||||
bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV); |
||||
|
||||
void CleanKey() |
||||
{ |
||||
memset(&chKey, 0, sizeof chKey); |
||||
memset(&chIV, 0, sizeof chIV); |
||||
munlock(&chKey, sizeof chKey); |
||||
munlock(&chIV, sizeof chIV); |
||||
fKeySet = false; |
||||
} |
||||
|
||||
CCrypter() |
||||
{ |
||||
fKeySet = false; |
||||
} |
||||
|
||||
~CCrypter() |
||||
{ |
||||
CleanKey(); |
||||
} |
||||
}; |
||||
|
||||
bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext); |
||||
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char> &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext); |
||||
|
||||
#endif |
Loading…
Reference in new issue