86a4cc3ac895c9d5141c744ca5c6b1f8b40ec64a
[novacoin.git] / src / keystore.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin 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 "keystore.h"
7 #include "script.h"
8 #include "base58.h"
9
10 extern bool fWalletUnlockMintOnly;
11
12 bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
13 {
14     CKey key;
15     if (!GetKey(address, key))
16         return false;
17     vchPubKeyOut = key.GetPubKey();
18     return true;
19 }
20
21 bool CBasicKeyStore::AddKey(const CKey& key)
22 {
23     bool fCompressed = false;
24     auto secret = key.GetSecret(fCompressed);
25     {
26         LOCK(cs_KeyStore);
27         mapKeys[key.GetPubKey().GetID()] = { secret, fCompressed };
28     }
29     return true;
30 }
31
32 bool CBasicKeyStore::AddMalleableKey(const CMalleableKeyView& keyView, const CSecret& vchSecretH)
33 {
34     {
35         LOCK(cs_KeyStore);
36         mapMalleableKeys[CMalleableKeyView(keyView)] = vchSecretH;
37     }
38     return true;
39 }
40
41 bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
42 {
43     if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
44         return error("CBasicKeyStore::AddCScript() : redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
45
46     {
47         LOCK(cs_KeyStore);
48         mapScripts[redeemScript.GetID()] = redeemScript;
49     }
50     return true;
51 }
52
53 bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
54 {
55     bool result;
56     {
57         LOCK(cs_KeyStore);
58         result = (mapScripts.count(hash) > 0);
59     }
60     return result;
61 }
62
63
64 bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
65 {
66     {
67         LOCK(cs_KeyStore);
68         auto mi = mapScripts.find(hash);
69         if (mi != mapScripts.end())
70         {
71             redeemScriptOut = (*mi).second;
72             return true;
73         }
74     }
75     return false;
76 }
77
78 bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
79 {
80     LOCK(cs_KeyStore);
81
82     CTxDestination address;
83     if (ExtractDestination(dest, address)) {
84         CKeyID keyID;
85         CBitcoinAddress(address).GetKeyID(keyID);
86         if (HaveKey(keyID))
87             return false;
88     }
89
90     setWatchOnly.insert(dest);
91     return true;
92 }
93
94
95 bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest)
96 {
97     LOCK(cs_KeyStore);
98     setWatchOnly.erase(dest);
99     return true;
100 }
101
102 bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
103 {
104     LOCK(cs_KeyStore);
105     return setWatchOnly.count(dest) > 0;
106 }
107
108 bool CBasicKeyStore::HaveWatchOnly() const
109 {
110     LOCK(cs_KeyStore);
111     return (!setWatchOnly.empty());
112 }
113
114 bool CCryptoKeyStore::SetCrypted()
115 {
116     {
117         LOCK(cs_KeyStore);
118         if (fUseCrypto)
119             return true;
120         if (!mapKeys.empty())
121             return false;
122         fUseCrypto = true;
123     }
124     return true;
125 }
126
127 bool CCryptoKeyStore::Lock()
128 {
129     if (!SetCrypted())
130         return false;
131
132     {
133         LOCK(cs_KeyStore);
134         vMasterKey.clear();
135         fWalletUnlockMintOnly = false;
136     }
137
138     NotifyStatusChanged(this);
139     return true;
140 }
141
142 bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
143 {
144     {
145         LOCK(cs_KeyStore);
146         if (!SetCrypted())
147             return false;
148
149         bool keyPass = false;
150         bool keyFail = false;
151
152         // Check regular key pairs
153         {
154             auto mi = mapCryptedKeys.begin();
155             for (; mi != mapCryptedKeys.end(); ++mi)
156             {
157                 const auto &vchPubKey = (*mi).second.first;
158                 const auto &vchCryptedSecret = (*mi).second.second;
159                 CSecret vchSecret;
160                 if (!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
161                 {
162                     keyFail = true;
163                     break;
164                 }
165                 if (vchSecret.size() != 32)
166                 {
167                     keyFail = true;
168                     break;
169                 }
170                 keyPass = true;
171                 if (fDecryptionThoroughlyChecked)
172                     break;
173             }
174         }
175
176         // Check malleable key pairs
177         {
178             if (keyPass && !keyFail)
179             {
180                 auto mi = mapCryptedMalleableKeys.begin();
181                 for(; mi != mapCryptedMalleableKeys.end(); ++mi)
182                 {
183                     const auto &H = mi->first.GetMalleablePubKey().GetH();
184                     CSecret vchSecretH;
185                     if (!DecryptSecret(vMasterKeyIn, mi->second, H.GetHash(), vchSecretH))
186                     {
187                         keyFail = true;
188                         break;
189                     }
190                     if (vchSecretH.size() != 32)
191                     {
192                         keyFail = true;
193                         break;
194                     }
195                     keyPass = true;
196                     if (fDecryptionThoroughlyChecked)
197                         break;
198                 }
199             }
200         }
201
202         if (keyPass && keyFail)
203         {
204             printf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
205             assert(false);
206         }
207         if (keyFail || !keyPass)
208             return false;
209         vMasterKey = vMasterKeyIn;
210         fDecryptionThoroughlyChecked = true;
211     }
212     NotifyStatusChanged(this);
213     return true;
214 }
215
216
217 bool CCryptoKeyStore::AddKey(const CKey& key)
218 {
219     {
220         LOCK(cs_KeyStore);
221
222         CScript script;
223         script.SetDestination(key.GetPubKey().GetID());
224
225         if (HaveWatchOnly(script))
226             return false;
227
228         if (!IsCrypted())
229             return CBasicKeyStore::AddKey(key);
230
231         if (IsLocked())
232             return false;
233
234         std::vector<unsigned char> vchCryptedSecret;
235         auto vchPubKey = key.GetPubKey();
236         bool fCompressed;
237         if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
238             return false;
239
240         if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
241             return false;
242     }
243     return true;
244 }
245
246 bool CCryptoKeyStore::AddMalleableKey(const CMalleableKeyView& keyView, const CSecret &vchSecretH)
247 {
248     {
249         LOCK(cs_KeyStore);
250         if (!SetCrypted())
251             return CBasicKeyStore::AddMalleableKey(keyView, vchSecretH);
252
253         if (IsLocked())
254             return false;
255
256         CKey keyH;
257         keyH.SetSecret(vchSecretH, true);
258
259         std::vector<unsigned char> vchCryptedSecretH;
260         if (!EncryptSecret(vMasterKey, vchSecretH, keyH.GetPubKey().GetHash(), vchCryptedSecretH))
261             return false;
262
263         if (!AddCryptedMalleableKey(keyView, vchCryptedSecretH))
264             return false;
265     }
266     return true;
267 }
268
269 bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
270 {
271     {
272         LOCK(cs_KeyStore);
273         if (!SetCrypted())
274             return false;
275
276         mapCryptedKeys[vchPubKey.GetID()] = { vchPubKey, vchCryptedSecret };
277     }
278     return true;
279 }
280
281 bool CCryptoKeyStore::AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector<unsigned char>  &vchCryptedSecretH)
282 {
283     {
284         LOCK(cs_KeyStore);
285         if (!SetCrypted())
286             return false;
287
288         mapCryptedMalleableKeys[CMalleableKeyView(keyView)] = vchCryptedSecretH;
289     }
290     return true;
291 }
292
293 bool CCryptoKeyStore::CreatePrivKey(const CPubKey &pubKeyVariant, const CPubKey &R, CKey &privKey) const
294 {
295     {
296         LOCK(cs_KeyStore);
297         if (!IsCrypted())
298             return CBasicKeyStore::CreatePrivKey(pubKeyVariant, R, privKey);
299
300         for (auto mi = mapCryptedMalleableKeys.begin(); mi != mapCryptedMalleableKeys.end(); mi++)
301         {
302             if (mi->first.CheckKeyVariant(R, pubKeyVariant))
303             {
304                 const CPubKey H = mi->first.GetMalleablePubKey().GetH();
305
306                 CSecret vchSecretH;
307                 if (!DecryptSecret(vMasterKey, mi->second, H.GetHash(), vchSecretH))
308                     return false;
309                 if (vchSecretH.size() != 32)
310                     return false;
311
312                 CMalleableKey mKey = mi->first.GetMalleableKey(vchSecretH);
313                 return mKey.CheckKeyVariant(R, pubKeyVariant, privKey);;
314             }
315         }
316
317     }
318     return true;
319 }
320
321 bool CCryptoKeyStore::GetMalleableKey(const CMalleableKeyView &keyView, CMalleableKey &mKey) const
322 {
323     {
324         LOCK(cs_KeyStore);
325         if (!IsCrypted())
326             return CBasicKeyStore::GetMalleableKey(keyView, mKey);
327         auto mi = mapCryptedMalleableKeys.find(keyView);
328         if (mi != mapCryptedMalleableKeys.end())
329         {
330             const CPubKey H = keyView.GetMalleablePubKey().GetH();
331
332             CSecret vchSecretH;
333             if (!DecryptSecret(vMasterKey, mi->second, H.GetHash(), vchSecretH))
334                 return false;
335
336             if (vchSecretH.size() != 32)
337                 return false;
338             mKey = mi->first.GetMalleableKey(vchSecretH);
339
340             return true;
341         }
342     }
343     return false;
344 }
345
346 bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
347 {
348     {
349         LOCK(cs_KeyStore);
350         if (!IsCrypted())
351             return CBasicKeyStore::GetKey(address, keyOut);
352
353         auto mi = mapCryptedKeys.find(address);
354         if (mi != mapCryptedKeys.end())
355         {
356             const CPubKey &vchPubKey = (*mi).second.first;
357             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
358             CSecret vchSecret;
359             if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
360                 return false;
361             if (vchSecret.size() != 32)
362                 return false;
363             keyOut.SetSecret(vchSecret);
364             keyOut.SetCompressedPubKey(vchPubKey.IsCompressed());
365             return true;
366         }
367     }
368     return false;
369 }
370
371 bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
372 {
373     {
374         LOCK(cs_KeyStore);
375         if (!IsCrypted())
376             return CKeyStore::GetPubKey(address, vchPubKeyOut);
377
378         auto mi = mapCryptedKeys.find(address);
379         if (mi != mapCryptedKeys.end())
380         {
381             vchPubKeyOut = (*mi).second.first;
382             return true;
383         }
384     }
385     return false;
386 }
387
388 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
389 {
390     {
391         LOCK(cs_KeyStore);
392         if (!mapCryptedKeys.empty() || IsCrypted())
393             return false;
394
395         fUseCrypto = true;
396         for(auto& mKey : mapKeys)
397         {
398             CKey key;
399             if (!key.SetSecret(mKey.second.first, mKey.second.second))
400                 return false;
401             const auto vchPubKey = key.GetPubKey();
402             std::vector<unsigned char> vchCryptedSecret;
403             bool fCompressed;
404             if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
405                 return false;
406             if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
407                 return false;
408         }
409         mapKeys.clear();
410
411         for(auto& mKey : mapMalleableKeys)
412         {
413             const auto vchPubKeyH = mKey.first.GetMalleablePubKey().GetH();
414             std::vector<unsigned char> vchCryptedSecretH;
415             if (!EncryptSecret(vMasterKeyIn, mKey.second, vchPubKeyH.GetHash(), vchCryptedSecretH))
416                 return false;
417             if (!AddCryptedMalleableKey(mKey.first, vchCryptedSecretH))
418                 return false;
419         }
420         mapMalleableKeys.clear();
421     }
422     return true;
423 }
424
425 bool CCryptoKeyStore::DecryptKeys(const CKeyingMaterial& vMasterKeyIn)
426 {
427     {
428         LOCK(cs_KeyStore);
429         if (!IsCrypted())
430             return false;
431
432         auto mi = mapCryptedKeys.begin();
433         for (; mi != mapCryptedKeys.end(); ++mi)
434         {
435             const auto &vchPubKey = (*mi).second.first;
436             const auto &vchCryptedSecret = (*mi).second.second;
437             CSecret vchSecret;
438             if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
439                 return false;
440             if (vchSecret.size() != 32)
441                 return false;
442             CKey key;
443             key.SetSecret(vchSecret);
444             key.SetCompressedPubKey(vchPubKey.IsCompressed());
445             if (!CBasicKeyStore::AddKey(key))
446                 return false;
447         }
448
449         mapCryptedKeys.clear();
450
451         auto mi2 = mapCryptedMalleableKeys.begin();
452         for(; mi2 != mapCryptedMalleableKeys.end(); ++mi2)
453         {
454             const auto vchPubKeyH = mi2->first.GetMalleablePubKey().GetH();
455
456             CSecret vchSecretH;
457             if(!DecryptSecret(vMasterKeyIn, mi2->second, vchPubKeyH.GetHash(), vchSecretH))
458                 return false;
459             if (vchSecretH.size() != 32)
460                 return false;
461
462             if (!CBasicKeyStore::AddMalleableKey(mi2->first, vchSecretH))
463                 return false;
464         }
465         mapCryptedMalleableKeys.clear();
466     }
467
468     return true;
469 }