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