Line data Source code
1 : // Copyright (c) 2009-2014 The Bitcoin developers
2 : // Copyright (c) 2017-2021 The PIVX Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #ifndef PIVX_CRYPTER_H
7 : #define PIVX_CRYPTER_H
8 :
9 : #include "keystore.h"
10 : #include "serialize.h"
11 : #include "streams.h"
12 : #include "support/allocators/zeroafterfree.h"
13 :
14 : class uint256;
15 :
16 : #include <atomic>
17 :
18 : const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
19 : const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
20 : const unsigned int WALLET_CRYPTO_IV_SIZE = 16;
21 :
22 : /**
23 : * Private key encryption is done based on a CMasterKey,
24 : * which holds a salt and random encryption key.
25 : *
26 : * CMasterKeys are encrypted using AES-256-CBC using a key
27 : * derived using derivation method nDerivationMethod
28 : * (0 == EVP_sha512()) and derivation iterations nDeriveIterations.
29 : * vchOtherDerivationParameters is provided for alternative algorithms
30 : * which may require more parameters (such as scrypt).
31 : *
32 : * Wallet Private Keys are then encrypted using AES-256-CBC
33 : * with the double-sha256 of the public key as the IV, and the
34 : * master key's key as the encryption key (see keystore.[ch]).
35 : */
36 :
37 : /** Master key for wallet encryption */
38 : class CMasterKey
39 : {
40 : public:
41 : std::vector<unsigned char> vchCryptedKey;
42 : std::vector<unsigned char> vchSalt;
43 : //! 0 = EVP_sha512()
44 : //! 1 = scrypt()
45 : unsigned int nDerivationMethod;
46 : unsigned int nDeriveIterations;
47 : //! Use this for more parameters to key derivation,
48 : //! such as the various parameters to scrypt
49 : std::vector<unsigned char> vchOtherDerivationParameters;
50 :
51 9 : SERIALIZE_METHODS(CMasterKey, obj) { READWRITE(obj.vchCryptedKey, obj.vchSalt, obj.nDerivationMethod, obj.nDeriveIterations, obj.vchOtherDerivationParameters); }
52 :
53 16 : CMasterKey()
54 16 : {
55 : // 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M
56 : // ie slightly lower than the lowest hardware we need bother supporting
57 16 : nDeriveIterations = 25000;
58 16 : nDerivationMethod = 0;
59 16 : vchOtherDerivationParameters = std::vector<unsigned char>(0);
60 16 : }
61 : };
62 :
63 : typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
64 :
65 : namespace wallet_crypto
66 : {
67 : class TestCrypter;
68 : }
69 :
70 430 : class CSecureDataStream : public CBaseDataStream<CKeyingMaterial>
71 : {
72 : public:
73 104 : explicit CSecureDataStream(int nTypeIn, int nVersionIn) : CBaseDataStream(nTypeIn, nVersionIn) { }
74 :
75 : CSecureDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) :
76 : CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
77 :
78 111 : CSecureDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) :
79 111 : CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
80 : };
81 :
82 : /** Encryption/decryption context with key information */
83 : class CCrypter
84 : {
85 : friend class wallet_crypto::TestCrypter; // for test access to chKey/chIV
86 : private:
87 : std::vector<unsigned char, secure_allocator<unsigned char>> vchKey;
88 : std::vector<unsigned char, secure_allocator<unsigned char>> vchIV;
89 : bool fKeySet;
90 :
91 : int BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const;
92 :
93 : public:
94 : bool SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod);
95 : bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char>& vchCiphertext) const;
96 : bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const;
97 : bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV);
98 :
99 5102 : void CleanKey()
100 : {
101 5102 : memory_cleanse(vchKey.data(), vchKey.size());
102 5102 : memory_cleanse(vchIV.data(), vchIV.size());
103 5102 : fKeySet = false;
104 5102 : }
105 :
106 5102 : CCrypter()
107 5102 : {
108 5102 : fKeySet = false;
109 5102 : vchKey.resize(WALLET_CRYPTO_KEY_SIZE);
110 5102 : vchIV.resize(WALLET_CRYPTO_IV_SIZE);
111 5102 : }
112 :
113 5102 : ~CCrypter()
114 10204 : {
115 5102 : CleanKey();
116 5102 : }
117 : };
118 :
119 : bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial& vchPlaintext, const uint256& nIV, std::vector<unsigned char>& vchCiphertext);
120 : bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
121 :
122 :
123 : /** Keystore which keeps the private keys encrypted.
124 : * It derives from the basic key store, which is used if no encryption is active.
125 : */
126 : class CCryptoKeyStore : public CBasicKeyStore
127 : {
128 : private:
129 : //! if fUseCrypto is true, mapKeys and mapSaplingSpendingKeys must be empty
130 : //! if fUseCrypto is false, vMasterKey must be empty
131 : std::atomic<bool> fUseCrypto;
132 :
133 : protected:
134 : // TODO: In the future, move this variable to the wallet class directly following upstream's structure.
135 : CKeyingMaterial vMasterKey;
136 : // Sapling
137 : CryptedSaplingSpendingKeyMap mapCryptedSaplingSpendingKeys;
138 :
139 : bool SetCrypted();
140 :
141 : //! will encrypt previously unencrypted keys
142 : bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
143 :
144 : CryptedKeyMap mapCryptedKeys;
145 :
146 : static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key);
147 :
148 : // Unlock Sapling keys
149 : bool UnlockSaplingKeys(const CKeyingMaterial& vMasterKeyIn, bool fDecryptionThoroughlyChecked);
150 :
151 : public:
152 505 : CCryptoKeyStore() : fUseCrypto(false) { }
153 :
154 14437523 : bool IsCrypted() const { return fUseCrypto; }
155 : bool IsLocked() const;
156 :
157 : virtual bool AddCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret);
158 : bool AddKeyPubKey(const CKey& key, const CPubKey& pubkey) override;
159 : bool HaveKey(const CKeyID& address) const override;
160 :
161 : bool GetKey(const CKeyID& address, CKey& keyOut) const override;
162 : bool GetPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const override;
163 : std::set<CKeyID> GetKeys() const override;
164 :
165 : //! Sapling
166 : virtual bool AddCryptedSaplingSpendingKey(const libzcash::SaplingExtendedFullViewingKey& extfvk,
167 : const std::vector<unsigned char>& vchCryptedSecret);
168 : bool HaveSaplingSpendingKey(const libzcash::SaplingExtendedFullViewingKey& extfvk) const override;
169 : bool GetSaplingSpendingKey(const libzcash::SaplingExtendedFullViewingKey& extfvk, libzcash::SaplingExtendedSpendingKey& skOut) const override;
170 :
171 : /**
172 : * Wallet status (encrypted, locked) changed.
173 : * Note: Called without locks held.
174 : */
175 : boost::signals2::signal<void(CCryptoKeyStore* wallet)> NotifyStatusChanged;
176 : };
177 :
178 : #endif // PIVX_CRYPTER_H
|