Line data Source code
1 : // Copyright (c) 2009-2013 The Bitcoin developers
2 : // Copyright (c) 2017-2021 The PIVX Core developers
3 : // Distributed under the MIT/X11 software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #include "crypter.h"
7 :
8 : #include "crypto/aes.h"
9 : #include "crypto/sha512.h"
10 : #include "script/script.h"
11 : #include "script/standard.h"
12 : #include "uint256.h"
13 :
14 122 : int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char* key, unsigned char* iv) const
15 : {
16 : // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc
17 : // cipher and sha512 message digest. Because sha512's output size (64b) is
18 : // greater than the aes256 block size (16b) + aes256 key size (32b),
19 : // there's no need to process more than once (D_0).
20 :
21 122 : if (!count || !key || !iv)
22 : return 0;
23 :
24 122 : unsigned char buf[CSHA512::OUTPUT_SIZE];
25 122 : CSHA512 di;
26 :
27 122 : di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size());
28 122 : di.Write(chSalt.data(), chSalt.size());
29 122 : di.Finalize(buf);
30 :
31 8326520 : for (int i = 0; i != count - 1; i++)
32 8326400 : di.Reset().Write(buf, sizeof(buf)).Finalize(buf);
33 :
34 122 : memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
35 122 : memcpy(iv, buf + WALLET_CRYPTO_KEY_SIZE, WALLET_CRYPTO_IV_SIZE);
36 122 : memory_cleanse(buf, sizeof(buf));
37 : return WALLET_CRYPTO_KEY_SIZE;
38 : }
39 :
40 122 : bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
41 : {
42 122 : if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
43 : return false;
44 :
45 122 : int i = 0;
46 122 : if (nDerivationMethod == 0)
47 122 : i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());
48 :
49 122 : if (i != (int)WALLET_CRYPTO_KEY_SIZE) {
50 0 : memory_cleanse(vchKey.data(), vchKey.size());
51 0 : memory_cleanse(vchIV.data(), vchIV.size());
52 0 : return false;
53 : }
54 :
55 122 : fKeySet = true;
56 122 : return true;
57 : }
58 :
59 4997 : bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
60 : {
61 4997 : if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_SIZE)
62 : return false;
63 :
64 4995 : memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
65 4995 : memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());
66 :
67 4995 : fKeySet = true;
68 4995 : return true;
69 : }
70 :
71 5191 : bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char>& vchCiphertext) const
72 : {
73 5191 : if (!fKeySet)
74 : return false;
75 :
76 : // max ciphertext len for a n bytes of plaintext is
77 : // n + AES_BLOCKSIZE bytes
78 5191 : vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
79 :
80 10382 : AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
81 5191 : size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), vchCiphertext.data());
82 5191 : if (nLen < vchPlaintext.size())
83 : return false;
84 5191 : vchCiphertext.resize(nLen);
85 : return true;
86 : }
87 :
88 6610 : bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
89 : {
90 6610 : if (!fKeySet)
91 : return false;
92 :
93 : // plaintext will always be equal to or lesser than length of ciphertext
94 6610 : int nLen = vchCiphertext.size();
95 6610 : vchPlaintext.resize(nLen);
96 13220 : AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
97 6610 : nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), &vchPlaintext[0]);
98 6610 : if (nLen == 0)
99 : return false;
100 6502 : vchPlaintext.resize(nLen);
101 : return true;
102 : }
103 :
104 1850 : bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial& vchPlaintext, const uint256& nIV, std::vector<unsigned char>& vchCiphertext)
105 : {
106 1850 : CCrypter cKeyCrypter;
107 3700 : std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
108 1850 : memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
109 1850 : if (!cKeyCrypter.SetKey(vMasterKey, chIV))
110 : return false;
111 1850 : return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
112 : }
113 :
114 3147 : bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
115 : {
116 3147 : CCrypter cKeyCrypter;
117 6294 : std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
118 3147 : memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
119 3147 : if (!cKeyCrypter.SetKey(vMasterKey, chIV))
120 : return false;
121 3145 : return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
122 : }
123 :
124 3035 : bool CCryptoKeyStore::DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
125 : {
126 6070 : CKeyingMaterial vchSecret;
127 3035 : if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
128 : return false;
129 :
130 3034 : if (vchSecret.size() != 32)
131 : return false;
132 :
133 3034 : key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
134 3034 : return key.VerifyPubKey(vchPubKey);
135 : }
136 :
137 2501 : bool CCryptoKeyStore::SetCrypted()
138 : {
139 2501 : LOCK(cs_KeyStore);
140 2501 : if (fUseCrypto)
141 : return true;
142 1 : if (!mapKeys.empty() && !mapSaplingSpendingKeys.empty())
143 : return false;
144 1 : fUseCrypto = true;
145 1 : return true;
146 : }
147 :
148 131709 : bool CCryptoKeyStore::IsLocked() const
149 : {
150 131709 : if (!IsCrypted()) {
151 : return false;
152 : }
153 2344 : return WITH_LOCK(cs_KeyStore, return vMasterKey.empty());
154 : }
155 :
156 19658 : bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey& pubkey)
157 : {
158 39316 : LOCK(cs_KeyStore);
159 19658 : if (!IsCrypted()) {
160 19651 : return CBasicKeyStore::AddKeyPubKey(key, pubkey);
161 : }
162 :
163 7 : if (IsLocked()) {
164 : return false;
165 : }
166 :
167 19665 : std::vector<unsigned char> vchCryptedSecret;
168 21 : CKeyingMaterial vchSecret(key.begin(), key.end());
169 7 : if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
170 : return false;
171 : }
172 :
173 7 : if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
174 0 : return false;
175 : }
176 : return true;
177 : }
178 :
179 6969341 : bool CCryptoKeyStore::HaveKey(const CKeyID& address) const
180 : {
181 13938662 : LOCK(cs_KeyStore);
182 6969341 : if (!IsCrypted()) {
183 6966568 : return CBasicKeyStore::HaveKey(address);
184 : }
185 5548 : return mapCryptedKeys.count(address) > 0;
186 : }
187 :
188 2348 : bool CCryptoKeyStore::AddCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret)
189 : {
190 4696 : LOCK(cs_KeyStore);
191 2348 : if (!SetCrypted()) {
192 : return false;
193 : }
194 :
195 4696 : mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
196 2348 : return true;
197 : }
198 :
199 3757999 : bool CCryptoKeyStore::GetKey(const CKeyID& address, CKey& keyOut) const
200 : {
201 7515998 : LOCK(cs_KeyStore);
202 3757999 : if (!IsCrypted()) {
203 3756357 : return CBasicKeyStore::GetKey(address, keyOut);
204 : }
205 :
206 1639 : CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
207 1639 : if (mi != mapCryptedKeys.end()) {
208 1639 : const CPubKey& vchPubKey = (*mi).second.first;
209 1639 : const std::vector<unsigned char>& vchCryptedSecret = (*mi).second.second;
210 1639 : return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
211 : }
212 : return false;
213 : }
214 :
215 3532913 : bool CCryptoKeyStore::GetPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const
216 : {
217 7065826 : LOCK(cs_KeyStore);
218 3532913 : if (!IsCrypted()) {
219 3532383 : return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
220 : }
221 :
222 532 : CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
223 532 : if (mi != mapCryptedKeys.end()) {
224 532 : vchPubKeyOut = (*mi).second.first;
225 532 : return true;
226 : }
227 : // Check for watch-only pubkeys
228 0 : return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
229 : }
230 :
231 8 : std::set<CKeyID> CCryptoKeyStore::GetKeys() const
232 : {
233 16 : LOCK(cs_KeyStore);
234 8 : if (!IsCrypted()) {
235 7 : return CBasicKeyStore::GetKeys();
236 : }
237 9 : std::set<CKeyID> set_address;
238 613 : for (const auto& mi : mapCryptedKeys) {
239 612 : set_address.insert(mi.first);
240 : }
241 2 : return set_address;
242 : }
243 :
244 7 : bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
245 : {
246 14 : LOCK(cs_KeyStore);
247 7 : if (!mapCryptedKeys.empty() || IsCrypted())
248 0 : return false;
249 :
250 7 : fUseCrypto = true;
251 785 : for (KeyMap::value_type& mKey : mapKeys) {
252 778 : const CKey& key = mKey.second;
253 778 : CPubKey vchPubKey = key.GetPubKey();
254 2334 : CKeyingMaterial vchSecret(key.begin(), key.end());
255 1556 : std::vector<unsigned char> vchCryptedSecret;
256 778 : if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
257 0 : return false;
258 778 : if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
259 : return false;
260 : }
261 7 : mapKeys.clear();
262 7 : return true;
263 : }
|