From 31f56e2f5d2a134e8f4798f7f1928d651979c703 Mon Sep 17 00:00:00 2001 From: Chethan Krishna Date: Thu, 30 Jun 2016 18:00:50 -0400 Subject: [PATCH 1/3] wallet-utility: extract addresses and private keys usage: ./wallet-utility -datadir= help: ./wallet-utility -h --- .gitignore | 1 + Makefile.am | 5 + configure.ac | 4 +- src/Makefile.am | 15 ++ src/Makefile.test.include | 3 +- src/test/data/wallet.dat | Bin 0 -> 16384 bytes src/test/test_bitcoin.h | 11 ++ src/test/walletutil_tests.cpp | 73 ++++++++ src/wallet-utility.cpp | 339 ++++++++++++++++++++++++++++++++++ 9 files changed, 448 insertions(+), 3 deletions(-) create mode 100644 src/test/data/wallet.dat create mode 100644 src/test/walletutil_tests.cpp create mode 100644 src/wallet-utility.cpp diff --git a/.gitignore b/.gitignore index a8722aa593ac..d9f334a0eb6e 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,4 @@ share/BitcoindComparisonTool.jar /doc/doxygen/ libbitcoinconsensus.pc +wallet-utility diff --git a/Makefile.am b/Makefile.am index 0a3b00bcc706..3d81263e9797 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,6 +12,7 @@ endif BITCOIND_BIN=$(top_builddir)/src/bitcoind$(EXEEXT) BITCOIN_QT_BIN=$(top_builddir)/src/qt/bitcoin-qt$(EXEEXT) BITCOIN_CLI_BIN=$(top_builddir)/src/bitcoin-cli$(EXEEXT) +WALLET_UTILITY_BIN=$(top_builddir)/src/wallet-utility$(EXEEXT) BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) OSX_APP=Bitcoin-Qt.app @@ -63,6 +64,7 @@ $(BITCOIN_WIN_INSTALLER): all-recursive STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIND_BIN) $(top_builddir)/release STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_QT_BIN) $(top_builddir)/release STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_CLI_BIN) $(top_builddir)/release + STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(WALLET_UTILITY_BIN) $(top_builddir)/release @test -f $(MAKENSIS) && $(MAKENSIS) -V2 $(top_builddir)/share/setup.nsi || \ echo error: could not build $@ @echo built $@ @@ -145,6 +147,9 @@ $(BITCOIND_BIN): FORCE $(BITCOIN_CLI_BIN): FORCE $(MAKE) -C src $(@F) +$(WALLET_UTILITY_BIN): FORCE + $(MAKE) -C src $(@F) + if USE_LCOV baseline.info: diff --git a/configure.ac b/configure.ac index e2056ee7539f..0e9e64fb3d01 100644 --- a/configure.ac +++ b/configure.ac @@ -191,7 +191,7 @@ CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" AC_ARG_WITH([utils], [AS_HELP_STRING([--with-utils], - [build bitcoin-cli bitcoin-tx (default=yes)])], + [build bitcoin-cli bitcoin-tx wallet-utility (default=yes)])], [build_bitcoin_utils=$withval], [build_bitcoin_utils=yes]) @@ -766,7 +766,7 @@ AC_MSG_CHECKING([whether to build bitcoind]) AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes]) AC_MSG_RESULT($build_bitcoind) -AC_MSG_CHECKING([whether to build utils (bitcoin-cli bitcoin-tx)]) +AC_MSG_CHECKING([whether to build utils (bitcoin-cli bitcoin-tx wallet-utility)]) AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes]) AC_MSG_RESULT($build_bitcoin_utils) diff --git a/src/Makefile.am b/src/Makefile.am index c52371bea91c..efe7e028d616 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -74,6 +74,9 @@ endif if BUILD_BITCOIN_UTILS bin_PROGRAMS += bitcoin-cli bitcoin-tx +if ENABLE_WALLET + bin_PROGRAMS += wallet-utility +endif endif .PHONY: FORCE check-symbols check-security @@ -367,6 +370,14 @@ bitcoin_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) bitcoin_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +# wallet-utility binary # +if ENABLE_WALLET +wallet_utility_SOURCES = wallet-utility.cpp +wallet_utility_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAG) +wallet_utility_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +wallet_utility_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +endif + if TARGET_WINDOWS bitcoin_cli_SOURCES += bitcoin-cli-res.rc endif @@ -377,6 +388,10 @@ bitcoin_cli_LDADD = \ $(LIBBITCOIN_UTIL) bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS) +if ENABLE_WALLET +wallet_utility_LDADD = libbitcoin_wallet.a $(LIBBITCOIN_COMMON) $(LIBBITCOIN_CRYPTO) $(LIBSECP256K1) $(LIBBITCOIN_UTIL) $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS) +endif + # # bitcoin-tx binary # diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 4ea09116c2d1..6813f85c007c 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -92,7 +92,8 @@ if ENABLE_WALLET BITCOIN_TESTS += \ test/accounting_tests.cpp \ wallet/test/wallet_tests.cpp \ - test/rpc_wallet_tests.cpp + test/rpc_wallet_tests.cpp \ + test/walletutil_tests.cpp endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) diff --git a/src/test/data/wallet.dat b/src/test/data/wallet.dat new file mode 100644 index 0000000000000000000000000000000000000000..d1352c06731a3b74b642eeef2dc5acaaa8a7b025 GIT binary patch literal 16384 zcmeI&cT5vu6aet=JFb+{CAi}%N(@23Dg=q*s0=}kiA+&Zsi~oYR4ZsCYOEq6;;5wo z!~p^SaDfwKh%-@3z&!{xYDE+2 zg%0Ti7UIx@e$>)AK*)-I&Il1TPLyv%1ht#pVU=J+{Eru@ZJi;a9?dzwZ-GY;009sH z0T2KI5C8!X009sH0T2Lz-WH&Hb!NX#Afpho+J#2p&)ezq6j2NG|Fi@I2!H?xfB*=9 z00@8p2!H?xfB*>eT>-MQ(pW4q_owIX|1|$^p3^sfA`vy{PXGVweFNtG zVGRNx00JNY0w4eaAOHd&00JNY0wB;k0(Ae+?AHgNTO7=C;=0(*5c&!{_+C5@!3(|< z?;&@%?JZ6cH=cV?m?qrE-@^YOd`I0Q009CZ00JNY0w4eaAn^YM<{|9(2&0D6$>H?D zC8S-%`hg+j^Rv0{vR$QGt6W{#be1yr>3Pr5>+OQ4b$70n30%KB?)mS3kE6a9%9Z|4sSlk(d z&%`HLlJ{eVmWJI3+!;3cWsYjQShbaUtJuYw?VKD?Jr!fZ0h#_DUrnZt@nUNdBNDSo z2Vz6Tip`(&WhX;(q}u8oTsD#2QR`amR1?vvS~RGAaOUsXzLpl~>k9*Nrd+fs|;VPi&VZ36z`ezSbySvTFs7Byy6(ifw zBd$Dz=}YdnUEdX&jWC~L6 zcE-=mpf)^D*014|HQf_1YQa*fZn$>U!ka(VLJ#Ecss(d?2{|CZ`hr8~>}7-8jKk;H zD_s&QPDQmSy<(#09KYt)UvAtz?#jin!AU3h&Z)6;7i1W)oxbT@VSgS!k26HO@@WdA z7U&|TgINpgu&kzM+h%_D{PIC3$QbLLp7K=F$ZB=4ZXKCibU0*T->L;m7?B6Zg}cVK zor|u>`@~UBsW>)2KW3ZEeb=R`OM5#i7rbTEf~8d5aQ$a3^gw=U&Y%8|KsMCx%{rNK Jty~d@z5y4K>5BjW literal 0 HcmV?d00001 diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 37bcb9b57c86..ce3aa3283d5e 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -33,6 +33,17 @@ struct TestingSetup: public BasicTestingSetup { ~TestingSetup(); }; +/** Wallet setup that configures a complete environment. + * Included are data directory, coins database, script check threads + * and wallet with 5 unused keys. + */ +struct WalletSetup: public BasicTestingSetup { + boost::filesystem::path pathTemp; + + WalletSetup(const std::string& chainName = CBaseChainParams::MAIN); + ~WalletSetup(); +}; + class CBlock; struct CMutableTransaction; class CScript; diff --git a/src/test/walletutil_tests.cpp b/src/test/walletutil_tests.cpp new file mode 100644 index 000000000000..f0d14cafb018 --- /dev/null +++ b/src/test/walletutil_tests.cpp @@ -0,0 +1,73 @@ +#include "main.h" +#include "test/test_bitcoin.h" +#include +#include + +#ifdef ENABLE_WALLET +#include "wallet/db.h" +#include "wallet/wallet.h" +#endif + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(walletutil_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(walletutil_test) +{ + /* + * addresses and private keys in test/data/wallet.dat + */ + string expected_addr = "[ \"13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av\", \"1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8\", \"13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F\" ]\n"; + string expected_addr_pkeys = "[ {\"addr\" : \"13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av\", \"pkey\" : \"5Jz5BWE2WQxp1hGqDZeisQFV1mRFR2AVBAgiXCbNcZyXNjD9aUd\"}, {\"addr\" : \"1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8\", \"pkey\" : \"5HsX2b3v2GjngYQ5ZM4mLp2b2apw6aMNVaPELV1YmpiYR1S4jzc\"}, {\"addr\" : \"13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F\", \"pkey\" : \"5KCWAs1wX2ESiL4PfDR8XYVSSETHFd2jaRGxt1QdanBFTit4XcH\"} ]\n"; + +#ifdef WIN32 + string strCmd = "wallet-utility -datadir=test/data/ > test/data/op.txt"; +#else + string strCmd = "./wallet-utility -datadir=test/data/ > test/data/op.txt"; +#endif + int ret = system(strCmd.c_str()); + BOOST_CHECK(ret == 0); + + boost::filesystem::path opPath = "test/data/op.txt"; + boost::filesystem::ifstream fIn; + fIn.open(opPath, std::ios::in); + + if (!fIn) + { + std::cerr << "Could not open the output file" << std::endl; + } + + stringstream ss_addr; + ss_addr << fIn.rdbuf(); + fIn.close(); + boost::filesystem::remove(opPath); + + string obtained = ss_addr.str(); + BOOST_CHECK_EQUAL(obtained, expected_addr); + +#ifdef WIN32 + strCmd = "wallet-utility -datadir=test/data/ -dumppass > test/data/op.txt"; +#else + strCmd = "./wallet-utility -datadir=test/data/ -dumppass > test/data/op.txt"; +#endif + + ret = system(strCmd.c_str()); + BOOST_CHECK(ret == 0); + + fIn.open(opPath, std::ios::in); + + if (!fIn) + { + std::cerr << "Could not open the output file" << std::endl; + } + + stringstream ss_addr_pkeys; + ss_addr_pkeys << fIn.rdbuf(); + fIn.close(); + boost::filesystem::remove(opPath); + + obtained = ss_addr_pkeys.str(); + BOOST_CHECK_EQUAL(obtained, expected_addr_pkeys); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet-utility.cpp b/src/wallet-utility.cpp new file mode 100644 index 000000000000..9eef52c3b711 --- /dev/null +++ b/src/wallet-utility.cpp @@ -0,0 +1,339 @@ +#include +#include + +// Include local headers +#include "wallet/walletdb.h" +#include "util.h" +#include "base58.h" +#include "wallet/crypter.h" +#include + + +void show_help() +{ + std::cout << + "This program outputs Bitcoin addresses and private keys from a wallet.dat file" << std::endl + << std::endl + << "Usage and options: " + << std::endl + << " -datadir= to tell the program where your wallet is" + << std::endl + << " -wallet= (Optional) if your wallet is not named wallet.dat" + << std::endl + << " -regtest or -testnet (Optional) dumps addresses from regtest/testnet" + << std::endl + << " -dumppass (Optional)if you want to extract private keys associated with addresses" + << std::endl + << " -pass= if you have encrypted private keys stored in your wallet" + << std::endl; +} + + +class WalletUtilityDB : public CDB +{ + private: + typedef std::map MasterKeyMap; + MasterKeyMap mapMasterKeys; + unsigned int nMasterKeyMaxID; + SecureString mPass; + std::vector vMKeys; + + public: + WalletUtilityDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose) + { + nMasterKeyMaxID = 0; + mPass.reserve(100); + } + + std::string getAddress(CDataStream ssKey); + std::string getKey(CDataStream ssKey, CDataStream ssValue); + std::string getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass); + bool updateMasterKeys(CDataStream ssKey, CDataStream ssValue); + bool parseKeys(bool dumppriv, std::string masterPass); + + bool DecryptSecret(const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext); + bool Unlock(); + bool DecryptKey(const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key); +}; + + +/* + * Address from a public key in base58 + */ +std::string WalletUtilityDB::getAddress(CDataStream ssKey) +{ + CPubKey vchPubKey; + ssKey >> vchPubKey; + CKeyID id = vchPubKey.GetID(); + std::string strAddr = CBitcoinAddress(id).ToString(); + + return strAddr; +} + + +/* + * Non encrypted private key in WIF + */ +std::string WalletUtilityDB::getKey(CDataStream ssKey, CDataStream ssValue) +{ + std::string strKey; + CPubKey vchPubKey; + ssKey >> vchPubKey; + CPrivKey pkey; + CKey key; + + ssValue >> pkey; + if (key.Load(pkey, vchPubKey, true)) + strKey = CBitcoinSecret(key).ToString(); + + return strKey; +} + + +bool WalletUtilityDB::DecryptSecret(const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext) +{ + CCrypter cKeyCrypter; + std::vector chIV(WALLET_CRYPTO_KEY_SIZE); + memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); + + BOOST_FOREACH(const CKeyingMaterial vMKey, vMKeys) + { + if(!cKeyCrypter.SetKey(vMKey, chIV)) + continue; + if (cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext))) + return true; + } + return false; +} + + +bool WalletUtilityDB::Unlock() +{ + CCrypter crypter; + CKeyingMaterial vMasterKey; + + BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) + { + if(!crypter.SetKeyFromPassphrase(mPass, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) + return false; + if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) + continue; // try another master key + vMKeys.push_back(vMasterKey); + } + return true; +} + + +bool WalletUtilityDB::DecryptKey(const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key) +{ + CKeyingMaterial vchSecret; + if(!DecryptSecret(vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) + return false; + + if (vchSecret.size() != 32) + return false; + + key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); + return true; +} + + +/* + * Encrypted private key in WIF format + */ +std::string WalletUtilityDB::getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass) +{ + mPass = masterPass.c_str(); + CPubKey vchPubKey; + ssKey >> vchPubKey; + CKey key; + + std::vector vKey; + ssValue >> vKey; + + if (!Unlock()) + return ""; + + if(!DecryptKey(vKey, vchPubKey, key)) + return ""; + + std::string strKey = CBitcoinSecret(key).ToString(); + return strKey; +} + + +/* + * Master key derivation + */ +bool WalletUtilityDB::updateMasterKeys(CDataStream ssKey, CDataStream ssValue) +{ + unsigned int nID; + ssKey >> nID; + CMasterKey kMasterKey; + ssValue >> kMasterKey; + if (mapMasterKeys.count(nID) != 0) + { + std::cout << "Error reading wallet database: duplicate CMasterKey id " << nID << std::endl; + return false; + } + mapMasterKeys[nID] = kMasterKey; + + if (nMasterKeyMaxID < nID) + nMasterKeyMaxID = nID; + + return true; +} + + +/* + * Look at all the records and parse keys for addresses and private keys + */ +bool WalletUtilityDB::parseKeys(bool dumppriv, std::string masterPass) +{ + DBErrors result = DB_LOAD_OK; + std::string strType; + bool first = true; + + try { + Dbc* pcursor = GetCursor(); + if (!pcursor) + { + LogPrintf("Error getting wallet database cursor\n"); + result = DB_CORRUPT; + } + + if (dumppriv) + { + while (result == DB_LOAD_OK && true) + { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int result = ReadAtCursor(pcursor, ssKey, ssValue); + + if (result == DB_NOTFOUND) { + break; + } + else if (result != 0) + { + LogPrintf("Error reading next record from wallet database\n"); + result = DB_CORRUPT; + break; + } + + ssKey >> strType; + if (strType == "mkey") + { + updateMasterKeys(ssKey, ssValue); + } + } + pcursor->close(); + pcursor = GetCursor(); + } + + while (result == DB_LOAD_OK && true) + { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = ReadAtCursor(pcursor, ssKey, ssValue); + + if (ret == DB_NOTFOUND) + { + std::cout << " ]" << std::endl; + first = true; + break; + } + else if (ret != DB_LOAD_OK) + { + LogPrintf("Error reading next record from wallet database\n"); + result = DB_CORRUPT; + break; + } + + ssKey >> strType; + + if (strType == "key" || strType == "ckey") + { + std::string strAddr = getAddress(ssKey); + std::string strKey = ""; + + + if (dumppriv && strType == "key") + strKey = getKey(ssKey, ssValue); + if (dumppriv && strType == "ckey") + { + if (masterPass == "") + { + std::cout << "Encrypted wallet, please provide a password. See help below" << std::endl; + show_help(); + result = DB_LOAD_FAIL; + break; + } + strKey = getCryptedKey(ssKey, ssValue, masterPass); + } + + if (strAddr != "") + { + if (first) + std::cout << "[ "; + else + std::cout << ", "; + } + + if (dumppriv) + { + std::cout << "{\"addr\" : \"" + strAddr + "\", " + << "\"pkey\" : \"" + strKey + "\"}" + << std::flush; + } + else + { + std::cout << "\"" + strAddr + "\""; + } + + first = false; + } + } + + pcursor->close(); + } catch (DbException &e) { + std::cout << "DBException caught " << e.get_errno() << std::endl; + } catch (std::exception &e) { + std::cout << "Exception caught " << std::endl; + } + + if (result == DB_LOAD_OK) + return true; + else + return false; +} + + +int main(int argc, char* argv[]) +{ + ParseParameters(argc, argv); + std::string walletFile = GetArg("-wallet", "wallet.dat"); + std::string masterPass = GetArg("-pass", ""); + bool fDumpPass = GetBoolArg("-dumppass", false); + bool help = GetBoolArg("-h", false); + bool result = false; + + if (help) + { + show_help(); + return 0; + } + + try { + SelectParams(ChainNameFromCommandLine()); + result = WalletUtilityDB(walletFile, "r").parseKeys(fDumpPass, masterPass); + } + catch (const std::exception& e) { + std::cout << "Error opening wallet file " << walletFile << std::endl; + std::cout << e.what() << std::endl; + } + + if (result) + return 0; + else + return -1; +} From efb0d557a55ffe6a5bae0378ffb03dac7ed0da14 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 18 Jul 2016 18:03:01 -0400 Subject: [PATCH 2/3] test: wallet utility python test --- src/Makefile.test.include | 2 ++ src/test/wallet-utility.py | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100755 src/test/wallet-utility.py diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 6813f85c007c..dc84dc831476 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -131,6 +131,8 @@ bitcoin_test_clean : FORCE check-local: @echo "Running test/bitcoin-util-test.py..." $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/bitcoin-util-test.py + @echo "Running test/wallet-utility.py..." + $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/wallet-utility.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check diff --git a/src/test/wallet-utility.py b/src/test/wallet-utility.py new file mode 100755 index 000000000000..f583ace74aa7 --- /dev/null +++ b/src/test/wallet-utility.py @@ -0,0 +1,26 @@ +#!/usr/bin/python +# Copyright 2014 BitPay, Inc. +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from subprocess import check_output +import json + +import os + +def assert_equal(thing1, thing2): + if thing1 != thing2: + raise AssertionError("%s != %s"%(str(thing1),str(thing2))) + +if __name__ == '__main__': + datadir = os.environ["srcdir"] + "/test/data" + command = os.environ["srcdir"] + "/wallet-utility" + + output = json.loads(check_output([command, "-datadir=" + datadir])) + + assert_equal(output[0], "13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av"); + assert_equal(output[1], "1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8"); + assert_equal(output[2], "13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F"); + + + From 365802634b6f1a5ef11081e18c4ee624fc1e150a Mon Sep 17 00:00:00 2001 From: Chethan Krishna Date: Mon, 18 Jul 2016 18:31:21 -0400 Subject: [PATCH 3/3] Remove cpp test for wallet-utility --- src/Makefile.test.include | 9 +- src/test/test_bitcoin.h | 11 - src/test/wallet-utility.py | 61 ++++- src/test/walletutil_tests.cpp | 73 ----- src/wallet-utility.cpp | 502 +++++++++++++++++----------------- 5 files changed, 305 insertions(+), 351 deletions(-) delete mode 100644 src/test/walletutil_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index dc84dc831476..f030a5b353f0 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -17,7 +17,9 @@ EXTRA_DIST += \ test/data/txcreate2.hex \ test/data/txcreatedata1.hex \ test/data/txcreatedata2.hex \ - test/data/txcreatesign.hex + test/data/txcreatesign.hex \ + test/wallet-utility.py \ + test/data/wallet.dat JSON_TEST_FILES = \ test/data/script_valid.json \ @@ -92,8 +94,7 @@ if ENABLE_WALLET BITCOIN_TESTS += \ test/accounting_tests.cpp \ wallet/test/wallet_tests.cpp \ - test/rpc_wallet_tests.cpp \ - test/walletutil_tests.cpp + test/rpc_wallet_tests.cpp endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) @@ -131,8 +132,10 @@ bitcoin_test_clean : FORCE check-local: @echo "Running test/bitcoin-util-test.py..." $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/bitcoin-util-test.py +if ENABLE_WALLET @echo "Running test/wallet-utility.py..." $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/wallet-utility.py +endif $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index ce3aa3283d5e..37bcb9b57c86 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -33,17 +33,6 @@ struct TestingSetup: public BasicTestingSetup { ~TestingSetup(); }; -/** Wallet setup that configures a complete environment. - * Included are data directory, coins database, script check threads - * and wallet with 5 unused keys. - */ -struct WalletSetup: public BasicTestingSetup { - boost::filesystem::path pathTemp; - - WalletSetup(const std::string& chainName = CBaseChainParams::MAIN); - ~WalletSetup(); -}; - class CBlock; struct CMutableTransaction; class CScript; diff --git a/src/test/wallet-utility.py b/src/test/wallet-utility.py index f583ace74aa7..b853a227e984 100755 --- a/src/test/wallet-utility.py +++ b/src/test/wallet-utility.py @@ -3,10 +3,12 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from subprocess import check_output -import json - +import subprocess import os +import json +import sys +import buildenv +import shutil def assert_equal(thing1, thing2): if thing1 != thing2: @@ -14,13 +16,46 @@ def assert_equal(thing1, thing2): if __name__ == '__main__': datadir = os.environ["srcdir"] + "/test/data" - command = os.environ["srcdir"] + "/wallet-utility" - - output = json.loads(check_output([command, "-datadir=" + datadir])) - - assert_equal(output[0], "13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av"); - assert_equal(output[1], "1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8"); - assert_equal(output[2], "13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F"); - - - + execprog = './wallet-utility' + buildenv.exeext + execargs = '-datadir=' + datadir + execrun = execprog + ' ' + execargs + + proc = subprocess.Popen(execrun, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) + try: + outs = proc.communicate() + except OSError: + print("OSError, Failed to execute " + execprog) + sys.exit(1) + + output = json.loads(outs[0]) + + assert_equal(output[0], "13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av") + assert_equal(output[1], "1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8") + assert_equal(output[2], "13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F") + + execargs = '-datadir=' + datadir + ' -dumppass' + execrun = execprog + ' ' + execargs + + proc = subprocess.Popen(execrun, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) + try: + outs = proc.communicate() + except OSError: + print("OSError, Failed to execute " + execprog) + sys.exit(1) + + output = json.loads(outs[0]) + + assert_equal(output[0]['addr'], "13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av") + assert_equal(output[0]['pkey'], "5Jz5BWE2WQxp1hGqDZeisQFV1mRFR2AVBAgiXCbNcZyXNjD9aUd") + assert_equal(output[1]['addr'], "1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8") + assert_equal(output[1]['pkey'], "5HsX2b3v2GjngYQ5ZM4mLp2b2apw6aMNVaPELV1YmpiYR1S4jzc") + assert_equal(output[2]['addr'], "13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F") + assert_equal(output[2]['pkey'], "5KCWAs1wX2ESiL4PfDR8XYVSSETHFd2jaRGxt1QdanBFTit4XcH") + + if os.path.exists(datadir + '/database'): + if os.path.isdir(datadir + '/database'): + shutil.rmtree(datadir + '/database') + + if os.path.exists(datadir + '/db.log'): + os.remove(datadir + '/db.log') + sys.exit(0) diff --git a/src/test/walletutil_tests.cpp b/src/test/walletutil_tests.cpp deleted file mode 100644 index f0d14cafb018..000000000000 --- a/src/test/walletutil_tests.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "main.h" -#include "test/test_bitcoin.h" -#include -#include - -#ifdef ENABLE_WALLET -#include "wallet/db.h" -#include "wallet/wallet.h" -#endif - -using namespace std; - -BOOST_FIXTURE_TEST_SUITE(walletutil_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(walletutil_test) -{ - /* - * addresses and private keys in test/data/wallet.dat - */ - string expected_addr = "[ \"13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av\", \"1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8\", \"13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F\" ]\n"; - string expected_addr_pkeys = "[ {\"addr\" : \"13EngsxkRi7SJPPqCyJsKf34U8FoX9E9Av\", \"pkey\" : \"5Jz5BWE2WQxp1hGqDZeisQFV1mRFR2AVBAgiXCbNcZyXNjD9aUd\"}, {\"addr\" : \"1FKCLGTpPeYBUqfNxktck8k5nqxB8sjim8\", \"pkey\" : \"5HsX2b3v2GjngYQ5ZM4mLp2b2apw6aMNVaPELV1YmpiYR1S4jzc\"}, {\"addr\" : \"13cdtE9tnNeXCZJ8KQ5WELgEmLSBLnr48F\", \"pkey\" : \"5KCWAs1wX2ESiL4PfDR8XYVSSETHFd2jaRGxt1QdanBFTit4XcH\"} ]\n"; - -#ifdef WIN32 - string strCmd = "wallet-utility -datadir=test/data/ > test/data/op.txt"; -#else - string strCmd = "./wallet-utility -datadir=test/data/ > test/data/op.txt"; -#endif - int ret = system(strCmd.c_str()); - BOOST_CHECK(ret == 0); - - boost::filesystem::path opPath = "test/data/op.txt"; - boost::filesystem::ifstream fIn; - fIn.open(opPath, std::ios::in); - - if (!fIn) - { - std::cerr << "Could not open the output file" << std::endl; - } - - stringstream ss_addr; - ss_addr << fIn.rdbuf(); - fIn.close(); - boost::filesystem::remove(opPath); - - string obtained = ss_addr.str(); - BOOST_CHECK_EQUAL(obtained, expected_addr); - -#ifdef WIN32 - strCmd = "wallet-utility -datadir=test/data/ -dumppass > test/data/op.txt"; -#else - strCmd = "./wallet-utility -datadir=test/data/ -dumppass > test/data/op.txt"; -#endif - - ret = system(strCmd.c_str()); - BOOST_CHECK(ret == 0); - - fIn.open(opPath, std::ios::in); - - if (!fIn) - { - std::cerr << "Could not open the output file" << std::endl; - } - - stringstream ss_addr_pkeys; - ss_addr_pkeys << fIn.rdbuf(); - fIn.close(); - boost::filesystem::remove(opPath); - - obtained = ss_addr_pkeys.str(); - BOOST_CHECK_EQUAL(obtained, expected_addr_pkeys); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet-utility.cpp b/src/wallet-utility.cpp index 9eef52c3b711..b52e6634d257 100644 --- a/src/wallet-utility.cpp +++ b/src/wallet-utility.cpp @@ -11,49 +11,49 @@ void show_help() { - std::cout << - "This program outputs Bitcoin addresses and private keys from a wallet.dat file" << std::endl - << std::endl - << "Usage and options: " - << std::endl - << " -datadir= to tell the program where your wallet is" - << std::endl - << " -wallet= (Optional) if your wallet is not named wallet.dat" - << std::endl - << " -regtest or -testnet (Optional) dumps addresses from regtest/testnet" - << std::endl - << " -dumppass (Optional)if you want to extract private keys associated with addresses" - << std::endl - << " -pass= if you have encrypted private keys stored in your wallet" - << std::endl; + std::cout << + "This program outputs Bitcoin addresses and private keys from a wallet.dat file" << std::endl + << std::endl + << "Usage and options: " + << std::endl + << " -datadir= to tell the program where your wallet is" + << std::endl + << " -wallet= (Optional) if your wallet is not named wallet.dat" + << std::endl + << " -regtest or -testnet (Optional) dumps addresses from regtest/testnet" + << std::endl + << " -dumppass (Optional)if you want to extract private keys associated with addresses" + << std::endl + << " -pass= if you have encrypted private keys stored in your wallet" + << std::endl; } class WalletUtilityDB : public CDB { - private: - typedef std::map MasterKeyMap; - MasterKeyMap mapMasterKeys; - unsigned int nMasterKeyMaxID; - SecureString mPass; - std::vector vMKeys; - - public: - WalletUtilityDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose) - { - nMasterKeyMaxID = 0; - mPass.reserve(100); - } - - std::string getAddress(CDataStream ssKey); - std::string getKey(CDataStream ssKey, CDataStream ssValue); - std::string getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass); - bool updateMasterKeys(CDataStream ssKey, CDataStream ssValue); - bool parseKeys(bool dumppriv, std::string masterPass); - - bool DecryptSecret(const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext); - bool Unlock(); - bool DecryptKey(const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key); + private: + typedef std::map MasterKeyMap; + MasterKeyMap mapMasterKeys; + unsigned int nMasterKeyMaxID; + SecureString mPass; + std::vector vMKeys; + + public: + WalletUtilityDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose) + { + nMasterKeyMaxID = 0; + mPass.reserve(100); + } + + std::string getAddress(CDataStream ssKey); + std::string getKey(CDataStream ssKey, CDataStream ssValue); + std::string getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass); + bool updateMasterKeys(CDataStream ssKey, CDataStream ssValue); + bool parseKeys(bool dumppriv, std::string masterPass); + + bool DecryptSecret(const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext); + bool Unlock(); + bool DecryptKey(const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key); }; @@ -62,12 +62,12 @@ class WalletUtilityDB : public CDB */ std::string WalletUtilityDB::getAddress(CDataStream ssKey) { - CPubKey vchPubKey; - ssKey >> vchPubKey; - CKeyID id = vchPubKey.GetID(); - std::string strAddr = CBitcoinAddress(id).ToString(); + CPubKey vchPubKey; + ssKey >> vchPubKey; + CKeyID id = vchPubKey.GetID(); + std::string strAddr = CBitcoinAddress(id).ToString(); - return strAddr; + return strAddr; } @@ -76,65 +76,65 @@ std::string WalletUtilityDB::getAddress(CDataStream ssKey) */ std::string WalletUtilityDB::getKey(CDataStream ssKey, CDataStream ssValue) { - std::string strKey; - CPubKey vchPubKey; - ssKey >> vchPubKey; - CPrivKey pkey; - CKey key; + std::string strKey; + CPubKey vchPubKey; + ssKey >> vchPubKey; + CPrivKey pkey; + CKey key; - ssValue >> pkey; - if (key.Load(pkey, vchPubKey, true)) - strKey = CBitcoinSecret(key).ToString(); + ssValue >> pkey; + if (key.Load(pkey, vchPubKey, true)) + strKey = CBitcoinSecret(key).ToString(); - return strKey; + return strKey; } bool WalletUtilityDB::DecryptSecret(const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext) { - CCrypter cKeyCrypter; - std::vector chIV(WALLET_CRYPTO_KEY_SIZE); - memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); - - BOOST_FOREACH(const CKeyingMaterial vMKey, vMKeys) - { - if(!cKeyCrypter.SetKey(vMKey, chIV)) - continue; - if (cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext))) - return true; - } - return false; + CCrypter cKeyCrypter; + std::vector chIV(WALLET_CRYPTO_KEY_SIZE); + memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); + + BOOST_FOREACH(const CKeyingMaterial vMKey, vMKeys) + { + if(!cKeyCrypter.SetKey(vMKey, chIV)) + continue; + if (cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext))) + return true; + } + return false; } bool WalletUtilityDB::Unlock() { - CCrypter crypter; - CKeyingMaterial vMasterKey; - - BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) - { - if(!crypter.SetKeyFromPassphrase(mPass, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) - return false; - if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) - continue; // try another master key - vMKeys.push_back(vMasterKey); - } - return true; + CCrypter crypter; + CKeyingMaterial vMasterKey; + + BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) + { + if(!crypter.SetKeyFromPassphrase(mPass, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) + return false; + if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) + continue; // try another master key + vMKeys.push_back(vMasterKey); + } + return true; } bool WalletUtilityDB::DecryptKey(const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key) { - CKeyingMaterial vchSecret; - if(!DecryptSecret(vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) - return false; + CKeyingMaterial vchSecret; + if(!DecryptSecret(vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) + return false; - if (vchSecret.size() != 32) - return false; + if (vchSecret.size() != 32) + return false; - key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); - return true; + key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); + return true; } @@ -143,22 +143,22 @@ bool WalletUtilityDB::DecryptKey(const std::vector& vchCryptedSec */ std::string WalletUtilityDB::getCryptedKey(CDataStream ssKey, CDataStream ssValue, std::string masterPass) { - mPass = masterPass.c_str(); - CPubKey vchPubKey; - ssKey >> vchPubKey; - CKey key; + mPass = masterPass.c_str(); + CPubKey vchPubKey; + ssKey >> vchPubKey; + CKey key; - std::vector vKey; - ssValue >> vKey; + std::vector vKey; + ssValue >> vKey; - if (!Unlock()) - return ""; + if (!Unlock()) + return ""; - if(!DecryptKey(vKey, vchPubKey, key)) - return ""; + if(!DecryptKey(vKey, vchPubKey, key)) + return ""; - std::string strKey = CBitcoinSecret(key).ToString(); - return strKey; + std::string strKey = CBitcoinSecret(key).ToString(); + return strKey; } @@ -167,21 +167,21 @@ std::string WalletUtilityDB::getCryptedKey(CDataStream ssKey, CDataStream ssValu */ bool WalletUtilityDB::updateMasterKeys(CDataStream ssKey, CDataStream ssValue) { - unsigned int nID; - ssKey >> nID; - CMasterKey kMasterKey; - ssValue >> kMasterKey; - if (mapMasterKeys.count(nID) != 0) - { - std::cout << "Error reading wallet database: duplicate CMasterKey id " << nID << std::endl; - return false; - } - mapMasterKeys[nID] = kMasterKey; - - if (nMasterKeyMaxID < nID) - nMasterKeyMaxID = nID; - - return true; + unsigned int nID; + ssKey >> nID; + CMasterKey kMasterKey; + ssValue >> kMasterKey; + if (mapMasterKeys.count(nID) != 0) + { + std::cout << "Error reading wallet database: duplicate CMasterKey id " << nID << std::endl; + return false; + } + mapMasterKeys[nID] = kMasterKey; + + if (nMasterKeyMaxID < nID) + nMasterKeyMaxID = nID; + + return true; } @@ -190,150 +190,150 @@ bool WalletUtilityDB::updateMasterKeys(CDataStream ssKey, CDataStream ssValue) */ bool WalletUtilityDB::parseKeys(bool dumppriv, std::string masterPass) { - DBErrors result = DB_LOAD_OK; - std::string strType; - bool first = true; - - try { - Dbc* pcursor = GetCursor(); - if (!pcursor) - { - LogPrintf("Error getting wallet database cursor\n"); - result = DB_CORRUPT; - } - - if (dumppriv) - { - while (result == DB_LOAD_OK && true) - { - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int result = ReadAtCursor(pcursor, ssKey, ssValue); - - if (result == DB_NOTFOUND) { - break; - } - else if (result != 0) - { - LogPrintf("Error reading next record from wallet database\n"); - result = DB_CORRUPT; - break; - } - - ssKey >> strType; - if (strType == "mkey") - { - updateMasterKeys(ssKey, ssValue); - } - } - pcursor->close(); - pcursor = GetCursor(); - } - - while (result == DB_LOAD_OK && true) - { - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue); - - if (ret == DB_NOTFOUND) - { - std::cout << " ]" << std::endl; - first = true; - break; - } - else if (ret != DB_LOAD_OK) - { - LogPrintf("Error reading next record from wallet database\n"); - result = DB_CORRUPT; - break; - } - - ssKey >> strType; - - if (strType == "key" || strType == "ckey") - { - std::string strAddr = getAddress(ssKey); - std::string strKey = ""; - - - if (dumppriv && strType == "key") - strKey = getKey(ssKey, ssValue); - if (dumppriv && strType == "ckey") - { - if (masterPass == "") - { - std::cout << "Encrypted wallet, please provide a password. See help below" << std::endl; - show_help(); - result = DB_LOAD_FAIL; - break; - } - strKey = getCryptedKey(ssKey, ssValue, masterPass); - } - - if (strAddr != "") - { - if (first) - std::cout << "[ "; - else - std::cout << ", "; - } - - if (dumppriv) - { - std::cout << "{\"addr\" : \"" + strAddr + "\", " - << "\"pkey\" : \"" + strKey + "\"}" - << std::flush; - } - else - { - std::cout << "\"" + strAddr + "\""; - } - - first = false; - } - } - - pcursor->close(); - } catch (DbException &e) { - std::cout << "DBException caught " << e.get_errno() << std::endl; - } catch (std::exception &e) { - std::cout << "Exception caught " << std::endl; - } - - if (result == DB_LOAD_OK) - return true; - else - return false; + DBErrors result = DB_LOAD_OK; + std::string strType; + bool first = true; + + try { + Dbc* pcursor = GetCursor(); + if (!pcursor) + { + LogPrintf("Error getting wallet database cursor\n"); + result = DB_CORRUPT; + } + + if (dumppriv) + { + while (result == DB_LOAD_OK && true) + { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int result = ReadAtCursor(pcursor, ssKey, ssValue); + + if (result == DB_NOTFOUND) { + break; + } + else if (result != 0) + { + LogPrintf("Error reading next record from wallet database\n"); + result = DB_CORRUPT; + break; + } + + ssKey >> strType; + if (strType == "mkey") + { + updateMasterKeys(ssKey, ssValue); + } + } + pcursor->close(); + pcursor = GetCursor(); + } + + while (result == DB_LOAD_OK && true) + { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = ReadAtCursor(pcursor, ssKey, ssValue); + + if (ret == DB_NOTFOUND) + { + std::cout << " ]" << std::endl; + first = true; + break; + } + else if (ret != DB_LOAD_OK) + { + LogPrintf("Error reading next record from wallet database\n"); + result = DB_CORRUPT; + break; + } + + ssKey >> strType; + + if (strType == "key" || strType == "ckey") + { + std::string strAddr = getAddress(ssKey); + std::string strKey = ""; + + + if (dumppriv && strType == "key") + strKey = getKey(ssKey, ssValue); + if (dumppriv && strType == "ckey") + { + if (masterPass == "") + { + std::cout << "Encrypted wallet, please provide a password. See help below" << std::endl; + show_help(); + result = DB_LOAD_FAIL; + break; + } + strKey = getCryptedKey(ssKey, ssValue, masterPass); + } + + if (strAddr != "") + { + if (first) + std::cout << "[ "; + else + std::cout << ", "; + } + + if (dumppriv) + { + std::cout << "{\"addr\" : \"" + strAddr + "\", " + << "\"pkey\" : \"" + strKey + "\"}" + << std::flush; + } + else + { + std::cout << "\"" + strAddr + "\""; + } + + first = false; + } + } + + pcursor->close(); + } catch (DbException &e) { + std::cout << "DBException caught " << e.get_errno() << std::endl; + } catch (std::exception &e) { + std::cout << "Exception caught " << std::endl; + } + + if (result == DB_LOAD_OK) + return true; + else + return false; } int main(int argc, char* argv[]) { - ParseParameters(argc, argv); - std::string walletFile = GetArg("-wallet", "wallet.dat"); - std::string masterPass = GetArg("-pass", ""); - bool fDumpPass = GetBoolArg("-dumppass", false); - bool help = GetBoolArg("-h", false); - bool result = false; - - if (help) - { - show_help(); - return 0; - } - - try { - SelectParams(ChainNameFromCommandLine()); - result = WalletUtilityDB(walletFile, "r").parseKeys(fDumpPass, masterPass); - } - catch (const std::exception& e) { - std::cout << "Error opening wallet file " << walletFile << std::endl; - std::cout << e.what() << std::endl; - } - - if (result) - return 0; - else - return -1; + ParseParameters(argc, argv); + std::string walletFile = GetArg("-wallet", "wallet.dat"); + std::string masterPass = GetArg("-pass", ""); + bool fDumpPass = GetBoolArg("-dumppass", false); + bool help = GetBoolArg("-h", false); + bool result = false; + + if (help) + { + show_help(); + return 0; + } + + try { + SelectParams(ChainNameFromCommandLine()); + result = WalletUtilityDB(walletFile, "r").parseKeys(fDumpPass, masterPass); + } + catch (const std::exception& e) { + std::cout << "Error opening wallet file " << walletFile << std::endl; + std::cout << e.what() << std::endl; + } + + if (result) + return 0; + else + return -1; }