Line data Source code
1 : // Copyright (c) 2009-2013 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 : #include "crypter.h"
6 :
7 : #include "script/script.h"
8 : #include "script/standard.h"
9 : #include "util.h"
10 :
11 : #include <string>
12 : #include <vector>
13 : #include <boost/foreach.hpp>
14 : #include <openssl/aes.h>
15 : #include <openssl/evp.h>
16 :
17 5 : bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
18 : {
19 10 : if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
20 : return false;
21 :
22 5 : int i = 0;
23 5 : if (nDerivationMethod == 0)
24 5 : i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
25 15 : (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
26 :
27 5 : if (i != (int)WALLET_CRYPTO_KEY_SIZE)
28 : {
29 0 : memory_cleanse(chKey, sizeof(chKey));
30 0 : memory_cleanse(chIV, sizeof(chIV));
31 0 : return false;
32 : }
33 :
34 5 : fKeySet = true;
35 5 : return true;
36 : }
37 :
38 258 : bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
39 : {
40 774 : if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
41 : return false;
42 :
43 258 : memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
44 258 : memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
45 :
46 258 : fKeySet = true;
47 258 : return true;
48 : }
49 :
50 66 : bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext)
51 : {
52 66 : if (!fKeySet)
53 : return false;
54 :
55 : // max ciphertext len for a n bytes of plaintext is
56 : // n + AES_BLOCK_SIZE - 1 bytes
57 132 : int nLen = vchPlaintext.size();
58 66 : int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
59 198 : vchCiphertext = std::vector<unsigned char> (nCLen);
60 :
61 : EVP_CIPHER_CTX ctx;
62 :
63 66 : bool fOk = true;
64 :
65 66 : EVP_CIPHER_CTX_init(&ctx);
66 66 : if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
67 66 : if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
68 66 : if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
69 66 : EVP_CIPHER_CTX_cleanup(&ctx);
70 :
71 66 : if (!fOk) return false;
72 :
73 66 : vchCiphertext.resize(nCLen + nFLen);
74 : return true;
75 : }
76 :
77 195 : bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext)
78 : {
79 195 : if (!fKeySet)
80 : return false;
81 :
82 : // plaintext will always be equal to or lesser than length of ciphertext
83 390 : int nLen = vchCiphertext.size();
84 195 : int nPLen = nLen, nFLen = 0;
85 :
86 585 : vchPlaintext = CKeyingMaterial(nPLen);
87 :
88 : EVP_CIPHER_CTX ctx;
89 :
90 195 : bool fOk = true;
91 :
92 195 : EVP_CIPHER_CTX_init(&ctx);
93 195 : if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
94 195 : if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
95 195 : if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
96 195 : EVP_CIPHER_CTX_cleanup(&ctx);
97 :
98 195 : if (!fOk) return false;
99 :
100 195 : vchPlaintext.resize(nPLen + nFLen);
101 : return true;
102 : }
103 :
104 :
105 65 : static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
106 : {
107 65 : CCrypter cKeyCrypter;
108 130 : std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
109 65 : memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
110 65 : if(!cKeyCrypter.SetKey(vMasterKey, chIV))
111 : return false;
112 130 : return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
113 : }
114 :
115 193 : static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
116 : {
117 193 : CCrypter cKeyCrypter;
118 386 : std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
119 193 : memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
120 193 : if(!cKeyCrypter.SetKey(vMasterKey, chIV))
121 : return false;
122 386 : return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
123 : }
124 :
125 193 : static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
126 : {
127 : CKeyingMaterial vchSecret;
128 193 : if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
129 : return false;
130 :
131 386 : if (vchSecret.size() != 32)
132 : return false;
133 :
134 386 : key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
135 193 : return key.VerifyPubKey(vchPubKey);
136 : }
137 :
138 91 : bool CCryptoKeyStore::SetCrypted()
139 : {
140 91 : LOCK(cs_KeyStore);
141 91 : if (fUseCrypto)
142 : return true;
143 2 : if (!mapKeys.empty())
144 : return false;
145 1 : fUseCrypto = true;
146 1 : return true;
147 : }
148 :
149 2 : bool CCryptoKeyStore::Lock()
150 : {
151 2 : if (!SetCrypted())
152 : return false;
153 :
154 : {
155 2 : LOCK(cs_KeyStore);
156 2 : vMasterKey.clear();
157 : }
158 :
159 2 : NotifyStatusChanged(this);
160 2 : return true;
161 : }
162 :
163 2 : bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
164 : {
165 : {
166 2 : LOCK(cs_KeyStore);
167 2 : if (!SetCrypted())
168 : return false;
169 :
170 2 : bool keyPass = false;
171 2 : bool keyFail = false;
172 4 : CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
173 92 : for (; mi != mapCryptedKeys.end(); ++mi)
174 : {
175 43 : const CPubKey &vchPubKey = (*mi).second.first;
176 43 : const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
177 : CKey key;
178 43 : if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
179 : {
180 : keyFail = true;
181 : break;
182 : }
183 43 : keyPass = true;
184 43 : if (fDecryptionThoroughlyChecked)
185 : break;
186 : }
187 2 : if (keyPass && keyFail)
188 : {
189 0 : LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
190 0 : assert(false);
191 : }
192 2 : if (keyFail || !keyPass)
193 : return false;
194 2 : vMasterKey = vMasterKeyIn;
195 2 : fDecryptionThoroughlyChecked = true;
196 : }
197 2 : NotifyStatusChanged(this);
198 2 : return true;
199 : }
200 :
201 3991 : bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
202 : {
203 : {
204 3991 : LOCK(cs_KeyStore);
205 3991 : if (!IsCrypted())
206 3947 : return CBasicKeyStore::AddKeyPubKey(key, pubkey);
207 :
208 44 : if (IsLocked())
209 : return false;
210 :
211 : std::vector<unsigned char> vchCryptedSecret;
212 132 : CKeyingMaterial vchSecret(key.begin(), key.end());
213 44 : if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
214 : return false;
215 :
216 44 : if (!AddCryptedKey(pubkey, vchCryptedSecret))
217 : return false;
218 : }
219 44 : return true;
220 : }
221 :
222 :
223 87 : bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
224 : {
225 : {
226 87 : LOCK(cs_KeyStore);
227 87 : if (!SetCrypted())
228 0 : return false;
229 :
230 348 : mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
231 : }
232 87 : return true;
233 : }
234 :
235 1278 : bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
236 : {
237 : {
238 1278 : LOCK(cs_KeyStore);
239 1278 : if (!IsCrypted())
240 1128 : return CBasicKeyStore::GetKey(address, keyOut);
241 :
242 300 : CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
243 300 : if (mi != mapCryptedKeys.end())
244 : {
245 150 : const CPubKey &vchPubKey = (*mi).second.first;
246 150 : const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
247 150 : return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
248 : }
249 : }
250 0 : return false;
251 : }
252 :
253 543 : bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
254 : {
255 : {
256 543 : LOCK(cs_KeyStore);
257 543 : if (!IsCrypted())
258 284 : return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
259 :
260 518 : CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
261 518 : if (mi != mapCryptedKeys.end())
262 : {
263 259 : vchPubKeyOut = (*mi).second.first;
264 259 : return true;
265 : }
266 : // Check for watch-only pubkeys
267 0 : return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
268 : }
269 : return false;
270 : }
271 :
272 1 : bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
273 : {
274 : {
275 1 : LOCK(cs_KeyStore);
276 2 : if (!mapCryptedKeys.empty() || IsCrypted())
277 : return false;
278 :
279 1 : fUseCrypto = true;
280 111 : BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
281 : {
282 21 : const CKey &key = mKey.second;
283 21 : CPubKey vchPubKey = key.GetPubKey();
284 63 : CKeyingMaterial vchSecret(key.begin(), key.end());
285 : std::vector<unsigned char> vchCryptedSecret;
286 21 : if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
287 : return false;
288 21 : if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
289 : return false;
290 : }
291 1 : mapKeys.clear();
292 : }
293 1 : return true;
294 288 : }
|