1 // Copyright (c) 2009-2014 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #ifndef BITCOIN_WALLET_CRYPTER_H
6 #define BITCOIN_WALLET_CRYPTER_H
11 #include "support/allocators/secure.h"
12 #include "zcash/Address.hpp"
16 const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
17 const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
20 * Private key encryption is done based on a CMasterKey,
21 * which holds a salt and random encryption key.
23 * CMasterKeys are encrypted using AES-256-CBC using a key
24 * derived using derivation method nDerivationMethod
25 * (0 == EVP_sha512()) and derivation iterations nDeriveIterations.
26 * vchOtherDerivationParameters is provided for alternative algorithms
27 * which may require more parameters (such as scrypt).
29 * Wallet Private Keys are then encrypted using AES-256-CBC
30 * with the double-sha256 of the public key as the IV, and the
31 * master key's key as the encryption key (see keystore.[ch]).
34 /** Master key for wallet encryption */
38 std::vector<unsigned char> vchCryptedKey;
39 std::vector<unsigned char> vchSalt;
42 unsigned int nDerivationMethod;
43 unsigned int nDeriveIterations;
44 //! Use this for more parameters to key derivation,
45 //! such as the various parameters to scrypt
46 std::vector<unsigned char> vchOtherDerivationParameters;
48 ADD_SERIALIZE_METHODS;
50 template <typename Stream, typename Operation>
51 inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
52 READWRITE(vchCryptedKey);
54 READWRITE(nDerivationMethod);
55 READWRITE(nDeriveIterations);
56 READWRITE(vchOtherDerivationParameters);
61 // 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M
62 // ie slightly lower than the lowest hardware we need bother supporting
63 nDeriveIterations = 25000;
64 nDerivationMethod = 0;
65 vchOtherDerivationParameters = std::vector<unsigned char>(0);
69 typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
71 class CSecureDataStream : public CBaseDataStream<CKeyingMaterial>
74 explicit CSecureDataStream(int nTypeIn, int nVersionIn) : CBaseDataStream(nTypeIn, nVersionIn) { }
76 CSecureDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) :
77 CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
79 CSecureDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) :
80 CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
83 /** Encryption/decryption context with key information */
87 unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
88 unsigned char chIV[WALLET_CRYPTO_KEY_SIZE];
92 bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod);
93 bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext);
94 bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext);
95 bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV);
99 memory_cleanse(chKey, sizeof(chKey));
100 memory_cleanse(chIV, sizeof(chIV));
108 // Try to keep the key data out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap)
109 // Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
110 // 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.
111 LockedPageManager::Instance().LockRange(&chKey[0], sizeof chKey);
112 LockedPageManager::Instance().LockRange(&chIV[0], sizeof chIV);
119 LockedPageManager::Instance().UnlockRange(&chKey[0], sizeof chKey);
120 LockedPageManager::Instance().UnlockRange(&chIV[0], sizeof chIV);
124 /** Keystore which keeps the private keys encrypted.
125 * It derives from the basic key store, which is used if no encryption is active.
127 class CCryptoKeyStore : public CBasicKeyStore
130 CryptedKeyMap mapCryptedKeys;
131 CryptedSpendingKeyMap mapCryptedSpendingKeys;
133 CKeyingMaterial vMasterKey;
135 //! if fUseCrypto is true, mapKeys and mapSpendingKeys must be empty
136 //! if fUseCrypto is false, vMasterKey must be empty
139 //! keeps track of whether Unlock has run a thorough check before
140 bool fDecryptionThoroughlyChecked;
145 //! will encrypt previously unencrypted keys
146 bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
148 bool Unlock(const CKeyingMaterial& vMasterKeyIn);
151 CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)
155 bool IsCrypted() const
160 bool IsLocked() const
167 result = vMasterKey.empty();
174 virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
175 bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
176 bool HaveKey(const CKeyID &address) const
181 return CBasicKeyStore::HaveKey(address);
182 return mapCryptedKeys.count(address) > 0;
186 bool GetKey(const CKeyID &address, CKey& keyOut) const;
187 bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
188 void GetKeys(std::set<CKeyID> &setAddress) const
192 CBasicKeyStore::GetKeys(setAddress);
196 CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
197 while (mi != mapCryptedKeys.end())
199 setAddress.insert((*mi).first);
203 virtual bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address,
204 const libzcash::ViewingKey &vk,
205 const std::vector<unsigned char> &vchCryptedSecret);
206 bool AddSpendingKey(const libzcash::SpendingKey &sk);
207 bool HaveSpendingKey(const libzcash::PaymentAddress &address) const
212 return CBasicKeyStore::HaveSpendingKey(address);
213 return mapCryptedSpendingKeys.count(address) > 0;
217 bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const;
218 void GetPaymentAddresses(std::set<libzcash::PaymentAddress> &setAddress) const
222 CBasicKeyStore::GetPaymentAddresses(setAddress);
226 CryptedSpendingKeyMap::const_iterator mi = mapCryptedSpendingKeys.begin();
227 while (mi != mapCryptedSpendingKeys.end())
229 setAddress.insert((*mi).first);
235 * Wallet status (encrypted, locked) changed.
236 * Note: Called without locks held.
238 boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
241 #endif // BITCOIN_WALLET_CRYPTER_H