RPC: Add new methods suitable for malleable key pairs management;
[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::AddMalleableKey(const CMalleableKey& mKey)
33 {
34     {
35         LOCK(cs_KeyStore);
36         mapMalleableKeys[CMalleableKeyView(mKey)] = mKey;
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         ScriptMap::const_iterator 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         CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
150         for (; mi != mapCryptedKeys.end(); ++mi)
151         {
152             const CPubKey &vchPubKey = (*mi).second.first;
153             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
154             CSecret vchSecret;
155             if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
156                 return false;
157             if (vchSecret.size() != 32)
158                 return false;
159             CKey key;
160             key.SetPubKey(vchPubKey);
161             key.SetSecret(vchSecret);
162             if (key.GetPubKey() == vchPubKey)
163                 break;
164             return false;
165         }
166
167         vMasterKey = vMasterKeyIn;
168     }
169     NotifyStatusChanged(this);
170     return true;
171 }
172
173 bool CCryptoKeyStore::AddKey(const CKey& key)
174 {
175     {
176         LOCK(cs_KeyStore);
177
178         CScript script;
179         script.SetDestination(key.GetPubKey().GetID());
180
181         if (HaveWatchOnly(script))
182             return false;
183
184         if (!IsCrypted())
185             return CBasicKeyStore::AddKey(key);
186
187         if (IsLocked())
188             return false;
189
190         std::vector<unsigned char> vchCryptedSecret;
191         CPubKey vchPubKey = key.GetPubKey();
192         bool fCompressed;
193         if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
194             return false;
195
196         if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
197             return false;
198     }
199     return true;
200 }
201
202
203 bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
204 {
205     {
206         LOCK(cs_KeyStore);
207         if (!SetCrypted())
208             return false;
209
210         mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
211     }
212     return true;
213 }
214
215 bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
216 {
217     {
218         LOCK(cs_KeyStore);
219         if (!IsCrypted())
220             return CBasicKeyStore::GetKey(address, keyOut);
221
222         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
223         if (mi != mapCryptedKeys.end())
224         {
225             const CPubKey &vchPubKey = (*mi).second.first;
226             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
227             CSecret vchSecret;
228             if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
229                 return false;
230             if (vchSecret.size() != 32)
231                 return false;
232             keyOut.SetPubKey(vchPubKey);
233             keyOut.SetSecret(vchSecret);
234             return true;
235         }
236     }
237     return false;
238 }
239
240 bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
241 {
242     {
243         LOCK(cs_KeyStore);
244         if (!IsCrypted())
245             return CKeyStore::GetPubKey(address, vchPubKeyOut);
246
247         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
248         if (mi != mapCryptedKeys.end())
249         {
250             vchPubKeyOut = (*mi).second.first;
251             return true;
252         }
253     }
254     return false;
255 }
256
257 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
258 {
259     {
260         LOCK(cs_KeyStore);
261         if (!mapCryptedKeys.empty() || IsCrypted())
262             return false;
263
264         fUseCrypto = true;
265         BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
266         {
267             CKey key;
268             if (!key.SetSecret(mKey.second.first, mKey.second.second))
269                 return false;
270             const CPubKey vchPubKey = key.GetPubKey();
271             std::vector<unsigned char> vchCryptedSecret;
272             bool fCompressed;
273             if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
274                 return false;
275             if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
276                 return false;
277         }
278         mapKeys.clear();
279     }
280     return true;
281 }
282
283 bool CCryptoKeyStore::DecryptKeys(const CKeyingMaterial& vMasterKeyIn)
284 {
285     {
286         LOCK(cs_KeyStore);
287         if (!IsCrypted())
288             return false;
289
290         CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
291         for (; mi != mapCryptedKeys.end(); ++mi)
292         {
293             const CPubKey &vchPubKey = (*mi).second.first;
294             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
295             CSecret vchSecret;
296             if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
297                 return false;
298             if (vchSecret.size() != 32)
299                 return false;
300             CKey key;
301             key.SetPubKey(vchPubKey);
302             key.SetSecret(vchSecret);
303             if (!CBasicKeyStore::AddKey(key))
304                 return false;
305         }
306
307         mapCryptedKeys.clear();
308     }
309
310     return true;
311 }