]> Git Repo - VerusCoin.git/blame - src/wallet-utility.cpp
Bitcore port
[VerusCoin.git] / src / wallet-utility.cpp
CommitLineData
8b78a819
T
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
12void 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
32class 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 */
63std::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 */
77std::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
93bool 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
110bool 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
127bool 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 */
144std::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 */
168bool 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 */
191bool 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
311int 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.056545 seconds and 4 git commands to generate.