mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-28 12:07:32 -03:00
e93fff1463
c626dcb50
Make fUseCrypto atomic (MeshCollider)731065b11
Consistent parameter names in txdb.h (MeshCollider)35aeabec6
Make fReindex atomic to avoid race (MeshCollider)58d91af59
Fix race for mapBlockIndex in AppInitMain (MeshCollider) Pull request description: Fixes https://github.com/bitcoin/bitcoin/issues/11106 Also makes fReindex atomic as suggested in @TheBlueMatt comment below, and makes fUseCrypto atomic as suggested in 10916d291e7635b
just renames the parameters in the txdb header file to make them consistent with those used in the cpp file, noticed it when looking for uses of fReindex Tree-SHA512: b378aa7289fd505b76565cd4d48dcdc04ac5540283ea1c80442170b0f13cb6df771b1a94dd54b7fec3478a7b4668c224ec9d795f16937782724c5d020edd3a42
196 lines
5.9 KiB
C++
196 lines
5.9 KiB
C++
// Copyright (c) 2009-2016 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#ifndef BITCOIN_WALLET_CRYPTER_H
|
|
#define BITCOIN_WALLET_CRYPTER_H
|
|
|
|
#include "keystore.h"
|
|
#include "serialize.h"
|
|
#include "support/allocators/secure.h"
|
|
|
|
#include <atomic>
|
|
|
|
const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
|
|
const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
|
|
const unsigned int WALLET_CRYPTO_IV_SIZE = 16;
|
|
|
|
/**
|
|
* Private key encryption is done based on a CMasterKey,
|
|
* which holds a salt and random encryption key.
|
|
*
|
|
* CMasterKeys are 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 public key as the IV, and the
|
|
* master key's key as the encryption key (see keystore.[ch]).
|
|
*/
|
|
|
|
/** Master key for wallet encryption */
|
|
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;
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
template <typename Stream, typename Operation>
|
|
inline void SerializationOp(Stream& s, Operation ser_action) {
|
|
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;
|
|
|
|
namespace wallet_crypto
|
|
{
|
|
class TestCrypter;
|
|
}
|
|
|
|
/** Encryption/decryption context with key information */
|
|
class CCrypter
|
|
{
|
|
friend class wallet_crypto::TestCrypter; // for test access to chKey/chIV
|
|
private:
|
|
std::vector<unsigned char, secure_allocator<unsigned char>> vchKey;
|
|
std::vector<unsigned char, secure_allocator<unsigned char>> vchIV;
|
|
bool fKeySet;
|
|
|
|
int BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const;
|
|
|
|
public:
|
|
bool SetKeyFromPassphrase(const SecureString &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) const;
|
|
bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const;
|
|
bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV);
|
|
|
|
void CleanKey()
|
|
{
|
|
memory_cleanse(vchKey.data(), vchKey.size());
|
|
memory_cleanse(vchIV.data(), vchIV.size());
|
|
fKeySet = false;
|
|
}
|
|
|
|
CCrypter()
|
|
{
|
|
fKeySet = false;
|
|
vchKey.resize(WALLET_CRYPTO_KEY_SIZE);
|
|
vchIV.resize(WALLET_CRYPTO_IV_SIZE);
|
|
}
|
|
|
|
~CCrypter()
|
|
{
|
|
CleanKey();
|
|
}
|
|
};
|
|
|
|
/** Keystore which keeps the private keys encrypted.
|
|
* It derives from the basic key store, which is used if no encryption is active.
|
|
*/
|
|
class CCryptoKeyStore : public CBasicKeyStore
|
|
{
|
|
private:
|
|
|
|
CKeyingMaterial vMasterKey;
|
|
|
|
//! if fUseCrypto is true, mapKeys must be empty
|
|
//! if fUseCrypto is false, vMasterKey must be empty
|
|
std::atomic<bool> fUseCrypto;
|
|
|
|
//! keeps track of whether Unlock has run a thorough check before
|
|
bool fDecryptionThoroughlyChecked;
|
|
|
|
protected:
|
|
bool SetCrypted();
|
|
|
|
//! will encrypt previously unencrypted keys
|
|
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
|
|
|
|
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
|
|
CryptedKeyMap mapCryptedKeys;
|
|
|
|
public:
|
|
CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)
|
|
{
|
|
}
|
|
|
|
bool IsCrypted() const
|
|
{
|
|
return fUseCrypto;
|
|
}
|
|
|
|
bool IsLocked() const
|
|
{
|
|
if (!IsCrypted())
|
|
return false;
|
|
bool result;
|
|
{
|
|
LOCK(cs_KeyStore);
|
|
result = vMasterKey.empty();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool Lock();
|
|
|
|
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
|
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
|
|
bool HaveKey(const CKeyID &address) const override
|
|
{
|
|
{
|
|
LOCK(cs_KeyStore);
|
|
if (!IsCrypted()) {
|
|
return CBasicKeyStore::HaveKey(address);
|
|
}
|
|
return mapCryptedKeys.count(address) > 0;
|
|
}
|
|
return false;
|
|
}
|
|
bool GetKey(const CKeyID &address, CKey& keyOut) const override;
|
|
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
|
|
std::set<CKeyID> GetKeys() const override
|
|
{
|
|
LOCK(cs_KeyStore);
|
|
if (!IsCrypted()) {
|
|
return CBasicKeyStore::GetKeys();
|
|
}
|
|
std::set<CKeyID> set_address;
|
|
for (const auto& mi : mapCryptedKeys) {
|
|
set_address.insert(mi.first);
|
|
}
|
|
return set_address;
|
|
}
|
|
|
|
/**
|
|
* Wallet status (encrypted, locked) changed.
|
|
* Note: Called without locks held.
|
|
*/
|
|
boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
|
|
};
|
|
|
|
#endif // BITCOIN_WALLET_CRYPTER_H
|