1 // Copyright (c) 2009-2018 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. 4 5 #ifndef BITCOIN_WALLET_CRYPTER_H 6 #define BITCOIN_WALLET_CRYPTER_H 7 8 #include <keystore.h> 9 #include <serialize.h> 10 #include <support/allocators/secure.h> 11 12 #include <atomic> 13 14 const unsigned int WALLET_CRYPTO_KEY_SIZE = 32; 15 const unsigned int WALLET_CRYPTO_SALT_SIZE = 8; 16 const unsigned int WALLET_CRYPTO_IV_SIZE = 16; 17 18 /** 19 * Private key encryption is done based on a CMasterKey, 20 * which holds a salt and random encryption key. 21 * 22 * CMasterKeys are encrypted using AES-256-CBC using a key 23 * derived using derivation method nDerivationMethod 24 * (0 == EVP_sha512()) and derivation iterations nDeriveIterations. 25 * vchOtherDerivationParameters is provided for alternative algorithms 26 * which may require more parameters (such as scrypt). 27 * 28 * Wallet Private Keys are then encrypted using AES-256-CBC 29 * with the double-sha256 of the public key as the IV, and the 30 * master key's key as the encryption key (see keystore.[ch]). 31 */ 32 33 /** Master key for wallet encryption */ 34 class CMasterKey 35 { 36 public: 37 std::vector<unsigned char> vchCryptedKey; 38 std::vector<unsigned char> vchSalt; 39 //! 0 = EVP_sha512() 40 //! 1 = scrypt() 41 unsigned int nDerivationMethod; 42 unsigned int nDeriveIterations; 43 //! Use this for more parameters to key derivation, 44 //! such as the various parameters to scrypt 45 std::vector<unsigned char> vchOtherDerivationParameters; 46 47 ADD_SERIALIZE_METHODS; 48 49 template <typename Stream, typename Operation> SerializationOp(Stream & s,Operation ser_action)50 inline void SerializationOp(Stream& s, Operation ser_action) { 51 READWRITE(vchCryptedKey); 52 READWRITE(vchSalt); 53 READWRITE(nDerivationMethod); 54 READWRITE(nDeriveIterations); 55 READWRITE(vchOtherDerivationParameters); 56 } 57 CMasterKey()58 CMasterKey() 59 { 60 // 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M 61 // ie slightly lower than the lowest hardware we need bother supporting 62 nDeriveIterations = 25000; 63 nDerivationMethod = 0; 64 vchOtherDerivationParameters = std::vector<unsigned char>(0); 65 } 66 }; 67 68 typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial; 69 70 namespace wallet_crypto_tests 71 { 72 class TestCrypter; 73 } 74 75 /** Encryption/decryption context with key information */ 76 class CCrypter 77 { 78 friend class wallet_crypto_tests::TestCrypter; // for test access to chKey/chIV 79 private: 80 std::vector<unsigned char, secure_allocator<unsigned char>> vchKey; 81 std::vector<unsigned char, secure_allocator<unsigned char>> vchIV; 82 bool fKeySet; 83 84 int BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const; 85 86 public: 87 bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod); 88 bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const; 89 bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const; 90 bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV); 91 CleanKey()92 void CleanKey() 93 { 94 memory_cleanse(vchKey.data(), vchKey.size()); 95 memory_cleanse(vchIV.data(), vchIV.size()); 96 fKeySet = false; 97 } 98 CCrypter()99 CCrypter() 100 { 101 fKeySet = false; 102 vchKey.resize(WALLET_CRYPTO_KEY_SIZE); 103 vchIV.resize(WALLET_CRYPTO_IV_SIZE); 104 } 105 ~CCrypter()106 ~CCrypter() 107 { 108 CleanKey(); 109 } 110 }; 111 112 /** Keystore which keeps the private keys encrypted. 113 * It derives from the basic key store, which is used if no encryption is active. 114 */ 115 class CCryptoKeyStore : public CBasicKeyStore 116 { 117 private: 118 119 CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore); 120 121 //! if fUseCrypto is true, mapKeys must be empty 122 //! if fUseCrypto is false, vMasterKey must be empty 123 std::atomic<bool> fUseCrypto; 124 125 //! keeps track of whether Unlock has run a thorough check before 126 bool fDecryptionThoroughlyChecked; 127 128 protected: 129 using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>; 130 131 bool SetCrypted(); 132 133 //! will encrypt previously unencrypted keys 134 bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); 135 136 bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false); 137 CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore); 138 139 public: CCryptoKeyStore()140 CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false) 141 { 142 } 143 IsCrypted()144 bool IsCrypted() const { return fUseCrypto; } 145 bool IsLocked() const; 146 bool Lock(); 147 148 virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); 149 bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override; 150 bool HaveKey(const CKeyID &address) const override; 151 bool GetKey(const CKeyID &address, CKey& keyOut) const override; 152 bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; 153 std::set<CKeyID> GetKeys() const override; 154 155 /** 156 * Wallet status (encrypted, locked) changed. 157 * Note: Called without locks held. 158 */ 159 boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged; 160 }; 161 162 #endif // BITCOIN_WALLET_CRYPTER_H 163