fdba2915fec0145e5efd497bbd9ddb4084e99e1d
[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     CSecret secret = key.GetSecret(fCompressed);
25     {
26         LOCK(cs_KeyStore);
27         mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed);
28     }
29     return true;
30 }
31
32 bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
33 {
34     if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
35         return error("CBasicKeyStore::AddCScript() : redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
36
37     {
38         LOCK(cs_KeyStore);
39         mapScripts[redeemScript.GetID()] = redeemScript;
40     }
41     return true;
42 }
43
44 bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
45 {
46     bool result;
47     {
48         LOCK(cs_KeyStore);
49         result = (mapScripts.count(hash) > 0);
50     }
51     return result;
52 }
53
54
55 bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
56 {
57     {
58         LOCK(cs_KeyStore);
59         ScriptMap::const_iterator mi = mapScripts.find(hash);
60         if (mi != mapScripts.end())
61         {
62             redeemScriptOut = (*mi).second;
63             return true;
64         }
65     }
66     return false;
67 }
68
69 bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
70 {
71     LOCK(cs_KeyStore);
72
73     CTxDestination address;
74     if (ExtractDestination(dest, address)) {
75         CKeyID keyID;
76         CBitcoinAddress(address).GetKeyID(keyID);
77         if (HaveKey(keyID))
78             return false;
79     }
80
81     setWatchOnly.insert(dest);
82     return true;
83 }
84
85
86 bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest)
87 {
88     LOCK(cs_KeyStore);
89     setWatchOnly.erase(dest);
90     return true;
91 }
92
93 bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
94 {
95     LOCK(cs_KeyStore);
96     return setWatchOnly.count(dest) > 0;
97 }
98
99 bool CBasicKeyStore::HaveWatchOnly() const
100 {
101     LOCK(cs_KeyStore);
102     return (!setWatchOnly.empty());
103 }
104
105 CCryptoKeyStore::CCryptoKeyStore() : fUseCrypto(false)
106 {
107     std::string strMalleableKey = GetArg("-masterkey", "");
108     CMalleableKey malleableKey;
109     if (strMalleableKey != "")
110         malleableKey.SetString(strMalleableKey);
111     else
112         malleableKey.MakeNewKeys();
113
114     const CMalleableKeyView& keyView(malleableKey);
115     mapMalleableKeys[keyView] = malleableKey;
116 }
117
118 bool CCryptoKeyStore::SetCrypted()
119 {
120     {
121         LOCK(cs_KeyStore);
122         if (fUseCrypto)
123             return true;
124         if (!mapKeys.empty())
125             return false;
126         fUseCrypto = true;
127     }
128     return true;
129 }
130
131 bool CCryptoKeyStore::Lock()
132 {
133     if (!SetCrypted())
134         return false;
135
136     {
137         LOCK(cs_KeyStore);
138         vMasterKey.clear();
139         fWalletUnlockMintOnly = false;
140     }
141
142     NotifyStatusChanged(this);
143     return true;
144 }
145
146 bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
147 {
148     {
149         LOCK(cs_KeyStore);
150         if (!SetCrypted())
151             return false;
152
153         CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
154         for (; mi != mapCryptedKeys.end(); ++mi)
155         {
156             const CPubKey &vchPubKey = (*mi).second.first;
157             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
158             CSecret vchSecret;
159             if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
160                 return false;
161             if (vchSecret.size() != 32)
162                 return false;
163             CKey key;
164             key.SetPubKey(vchPubKey);
165             key.SetSecret(vchSecret);
166             if (key.GetPubKey() == vchPubKey)
167                 break;
168             return false;
169         }
170
171         vMasterKey = vMasterKeyIn;
172     }
173     NotifyStatusChanged(this);
174     return true;
175 }
176
177 bool CCryptoKeyStore::AddKey(const CKey& key)
178 {
179     {
180         LOCK(cs_KeyStore);
181
182         CScript script;
183         script.SetDestination(key.GetPubKey().GetID());
184
185         if (HaveWatchOnly(script))
186             return false;
187
188         if (!IsCrypted())
189             return CBasicKeyStore::AddKey(key);
190
191         if (IsLocked())
192             return false;
193
194         std::vector<unsigned char> vchCryptedSecret;
195         CPubKey vchPubKey = key.GetPubKey();
196         bool fCompressed;
197         if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
198             return false;
199
200         if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
201             return false;
202     }
203     return true;
204 }
205
206
207 bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
208 {
209     {
210         LOCK(cs_KeyStore);
211         if (!SetCrypted())
212             return false;
213
214         mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
215     }
216     return true;
217 }
218
219 bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
220 {
221     {
222         LOCK(cs_KeyStore);
223         if (!IsCrypted())
224             return CBasicKeyStore::GetKey(address, keyOut);
225
226         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
227         if (mi != mapCryptedKeys.end())
228         {
229             const CPubKey &vchPubKey = (*mi).second.first;
230             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
231             CSecret vchSecret;
232             if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
233                 return false;
234             if (vchSecret.size() != 32)
235                 return false;
236             keyOut.SetPubKey(vchPubKey);
237             keyOut.SetSecret(vchSecret);
238             return true;
239         }
240     }
241     return false;
242 }
243
244 bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
245 {
246     {
247         LOCK(cs_KeyStore);
248         if (!IsCrypted())
249             return CKeyStore::GetPubKey(address, vchPubKeyOut);
250
251         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
252         if (mi != mapCryptedKeys.end())
253         {
254             vchPubKeyOut = (*mi).second.first;
255             return true;
256         }
257     }
258     return false;
259 }
260
261 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
262 {
263     {
264         LOCK(cs_KeyStore);
265         if (!mapCryptedKeys.empty() || IsCrypted())
266             return false;
267
268         fUseCrypto = true;
269         BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
270         {
271             CKey key;
272             if (!key.SetSecret(mKey.second.first, mKey.second.second))
273                 return false;
274             const CPubKey vchPubKey = key.GetPubKey();
275             std::vector<unsigned char> vchCryptedSecret;
276             bool fCompressed;
277             if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
278                 return false;
279             if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
280                 return false;
281         }
282         mapKeys.clear();
283     }
284     return true;
285 }
286
287 bool CCryptoKeyStore::DecryptKeys(const CKeyingMaterial& vMasterKeyIn)
288 {
289     {
290         LOCK(cs_KeyStore);
291         if (!IsCrypted())
292             return false;
293
294         CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
295         for (; mi != mapCryptedKeys.end(); ++mi)
296         {
297             const CPubKey &vchPubKey = (*mi).second.first;
298             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
299             CSecret vchSecret;
300             if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
301                 return false;
302             if (vchSecret.size() != 32)
303                 return false;
304             CKey key;
305             key.SetPubKey(vchPubKey);
306             key.SetSecret(vchSecret);
307             if (!CBasicKeyStore::AddKey(key))
308                 return false;
309         }
310
311         mapCryptedKeys.clear();
312     }
313
314     return true;
315 }