]> Git Repo - VerusCoin.git/blob - src/wallet-utility.cpp
f36785df3459cf7d40d2ddfbdc1c7ce4ee68f745
[VerusCoin.git] / src / wallet-utility.cpp
1 #include <iostream>
2 #include <string>
3
4 // Include local headers
5 #include "wallet/walletdb.h"
6 #include "util.h"
7 #include "base58.h"
8 #include "wallet/crypter.h"
9 #include <boost/foreach.hpp>
10
11
12 void show_help()
13 {
14     std::cout <<
15         "This program outputs Bitcoin addresses and private keys from a wallet.dat file" << std::endl
16         << std::endl
17         << "Usage and options: "
18         << std::endl
19         << " -datadir=<directory> to tell the program where your wallet is"
20         << std::endl
21         << " -wallet=<name> (Optional) if your wallet is not named wallet.dat"
22         << std::endl
23         << " -regtest or -testnet (Optional) dumps addresses from regtest/testnet"
24         << std::endl
25         << " -dumppass (Optional)if you want to extract private keys associated with addresses"
26         << std::endl
27         << "    -pass=<walletpassphrase> if you have encrypted private keys stored in your wallet"
28         << std::endl;
29 }
30
31
32 class WalletUtilityDB : public CDB
33 {
34     private:
35         typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
36         MasterKeyMap mapMasterKeys;
37         unsigned int nMasterKeyMaxID;
38         SecureString mPass;
39         std::vector<CKeyingMaterial> vMKeys;
40
41     public:
42         WalletUtilityDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose)
43     {
44         nMasterKeyMaxID = 0;
45         mPass.reserve(100);
46     }
47
48         std::string getAddress(CDataStream ssKey);
49         std::string getKey(CDataStream ssKey, CDataStream ssValue);
50         std::string getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass);
51         bool updateMasterKeys(CDataStream ssKey, CDataStream ssValue);
52         bool parseKeys(bool dumppriv, std::string masterPass);
53
54         bool DecryptSecret(const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
55         bool Unlock();
56         bool DecryptKey(const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key);
57 };
58
59
60 /*
61  * Address from a public key in base58
62  */
63 std::string WalletUtilityDB::getAddress(CDataStream ssKey)
64 {
65     CPubKey vchPubKey;
66     ssKey >> vchPubKey;
67     CKeyID id = vchPubKey.GetID();
68     std::string strAddr = CBitcoinAddress(id).ToString();
69
70     return strAddr;
71 }
72
73
74 /*
75  * Non encrypted private key in WIF
76  */
77 std::string WalletUtilityDB::getKey(CDataStream ssKey, CDataStream ssValue)
78 {
79     std::string strKey;
80     CPubKey vchPubKey;
81     ssKey >> vchPubKey;
82     CPrivKey pkey;
83     CKey key;
84
85     ssValue >> pkey;
86     if (key.Load(pkey, vchPubKey, true))
87         strKey = CBitcoinSecret(key).ToString();
88
89     return strKey;
90 }
91
92
93 bool WalletUtilityDB::DecryptSecret(const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
94 {
95     CCrypter cKeyCrypter;
96     std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
97     memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
98
99     BOOST_FOREACH(const CKeyingMaterial vMKey, vMKeys)
100     {
101         if(!cKeyCrypter.SetKey(vMKey, chIV))
102             continue;
103         if (cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext)))
104             return true;
105     }
106     return false;
107 }
108
109
110 bool WalletUtilityDB::Unlock()
111 {
112     CCrypter crypter;
113     CKeyingMaterial vMasterKey;
114
115     BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
116     {
117         if(!crypter.SetKeyFromPassphrase(mPass, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
118             return false;
119         if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
120             continue; // try another master key
121         vMKeys.push_back(vMasterKey);
122     }
123     return true;
124 }
125
126
127 bool WalletUtilityDB::DecryptKey(const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
128 {
129     CKeyingMaterial vchSecret;
130     if(!DecryptSecret(vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
131         return false;
132
133     if (vchSecret.size() != 32)
134         return false;
135
136     key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
137     return true;
138 }
139
140
141 /*
142  * Encrypted private key in WIF format
143  */
144 std::string WalletUtilityDB::getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass)
145 {
146     mPass = masterPass.c_str();
147     CPubKey vchPubKey;
148     ssKey >> vchPubKey;
149     CKey key;
150
151     std::vector<unsigned char> vKey;
152     ssValue >> vKey;
153
154     if (!Unlock())
155         return "";
156
157     if(!DecryptKey(vKey, vchPubKey, key))
158         return "";
159
160     std::string strKey = CBitcoinSecret(key).ToString();
161     return strKey;
162 }
163
164
165 /*
166  * Master key derivation
167  */
168 bool WalletUtilityDB::updateMasterKeys(CDataStream ssKey, CDataStream ssValue)
169 {
170     unsigned int nID;
171     ssKey >> nID;
172     CMasterKey kMasterKey;
173     ssValue >> kMasterKey;
174     if (mapMasterKeys.count(nID) != 0)
175     {
176         std::cout << "Error reading wallet database: duplicate CMasterKey id " << nID << std::endl;
177         return false;
178     }
179     mapMasterKeys[nID] = kMasterKey;
180
181     if (nMasterKeyMaxID < nID)
182         nMasterKeyMaxID = nID;
183
184     return true;
185 }
186
187
188 /*
189  * Look at all the records and parse keys for addresses and private keys
190  */
191 bool WalletUtilityDB::parseKeys(bool dumppriv, std::string masterPass)
192 {
193     DBErrors result = DB_LOAD_OK;
194     std::string strType;
195     bool first = true;
196
197     try {
198         Dbc* pcursor = GetCursor();
199         if (!pcursor)
200         {
201             LogPrintf("Error getting wallet database cursor\n");
202             result = DB_CORRUPT;
203         }
204
205         if (dumppriv)
206         {
207             while (result == DB_LOAD_OK && true)
208             {
209                 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
210                 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
211                 int result = ReadAtCursor(pcursor, ssKey, ssValue);
212
213                 if (result == DB_NOTFOUND) {
214                     break;
215                 }
216                 else if (result != 0)
217                 {
218                     LogPrintf("Error reading next record from wallet database\n");
219                     result = DB_CORRUPT;
220                     break;
221                 }
222
223                 ssKey >> strType;
224                 if (strType == "mkey")
225                 {
226                     updateMasterKeys(ssKey, ssValue);
227                 }
228             }
229             pcursor->close();
230             pcursor = GetCursor();
231         }
232
233         while (result == DB_LOAD_OK && true)
234         {
235             CDataStream ssKey(SER_DISK, CLIENT_VERSION);
236             CDataStream ssValue(SER_DISK, CLIENT_VERSION);
237             int ret = ReadAtCursor(pcursor, ssKey, ssValue);
238
239             if (ret == DB_NOTFOUND)
240             {
241                 std::cout << " ]" << std::endl;
242                 first = true;
243                 break;
244             }
245             else if (ret != DB_LOAD_OK)
246             {
247                 LogPrintf("Error reading next record from wallet database\n");
248                 result = DB_CORRUPT;
249                 break;
250             }
251
252             ssKey >> strType;
253
254             if (strType == "key" || strType == "ckey")
255             {
256                 std::string strAddr = getAddress(ssKey);
257                 std::string strKey = "";
258
259
260                 if (dumppriv && strType == "key")
261                     strKey = getKey(ssKey, ssValue);
262                 if (dumppriv && strType == "ckey")
263                 {
264                     if (masterPass == "")
265                     {
266                         std::cout << "Encrypted wallet, please provide a password. See help below" << std::endl;
267                         show_help();
268                         result = DB_LOAD_FAIL;
269                         break;
270                     }
271                     strKey = getCryptedKey(ssKey, ssValue, masterPass);
272                 }
273
274                 if (strAddr != "")
275                 {
276                     if (first)
277                         std::cout << "[ ";
278                     else
279                         std::cout << ", ";
280                 }
281
282                 if (dumppriv)
283                 {
284                     std::cout << "{\"addr\" : \"" + strAddr + "\", "
285                         << "\"pkey\" : \"" + strKey + "\"}"
286                         << std::flush;
287                 }
288                 else
289                 {
290                     std::cout << "\"" + strAddr + "\"";
291                 }
292
293                 first = false;
294             }
295         }
296
297         pcursor->close();
298     } catch (DbException &e) {
299         std::cout << "DBException caught " << e.get_errno() << std::endl;
300     } catch (std::exception &e) {
301         std::cout << "Exception caught " << std::endl;
302     }
303
304     if (result == DB_LOAD_OK)
305         return true;
306     else
307         return false;
308 }
309
310
311 int main(int argc, char* argv[])
312 {
313     ParseParameters(argc, argv);
314     std::string walletFile = GetArg("-wallet", "wallet.dat");
315     std::string masterPass = GetArg("-pass", "");
316     bool fDumpPass = GetBoolArg("-dumppass", false);
317     bool help = GetBoolArg("-h", false);
318     bool result = false;
319
320     if (help)
321     {
322         show_help();
323         return 0;
324     }
325
326     try {
327         SelectParamsFromCommandLine();
328         result = WalletUtilityDB(walletFile, "r").parseKeys(fDumpPass, masterPass);
329     }
330     catch (const std::exception& e) {
331         std::cout << "Error opening wallet file " << walletFile << std::endl;
332         std::cout << e.what() << std::endl;
333     }
334
335     if (result)
336         return 0;
337     else
338         return -1;
339 }
This page took 0.03393 seconds and 2 git commands to generate.