Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add warning before dumpwallet is executed #291

Merged
merged 5 commits into from
Oct 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ BITCOIN_CORE_H = \
wallet/rpcwallet.h \
wallet/wallet.h \
wallet/walletdb.h \
wallet/authhelper.h \
definition.h \
zmq/zmqabstractnotifier.h \
zmq/zmqconfig.h\
Expand Down Expand Up @@ -281,6 +282,7 @@ libbitcoin_wallet_a_SOURCES = \
wallet/rpcwallet.cpp \
wallet/wallet.cpp \
wallet/walletdb.cpp \
wallet/authhelper.cpp \
policy/rbf.cpp \
$(BITCOIN_CORE_H)

Expand Down
2 changes: 1 addition & 1 deletion src/rpc/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ std::vector<std::string> CRPCTable::listCommands() const

std::string HelpExampleCli(const std::string& methodname, const std::string& args)
{
return "> bitcoin-cli " + methodname + " " + args + "\n";
return "> zcoin-cli " + methodname + " " + args + "\n";
}

std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
Expand Down
103 changes: 103 additions & 0 deletions src/wallet/authhelper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#include <random>
#include <string>
#include <map>

#include "base58.h"
#include "authhelper.h"
#include "wallet.h"
#include "main.h"

struct AuthorizationHelper::Impl
{
using rnd_type = size_t;
using code_type = std::string;
Impl()
: rnd_dist(std::numeric_limits<rnd_type>::min(), std::numeric_limits<rnd_type>::max())
{
LOCK2(cs_main, pwalletMain->cs_wallet);
generator.seed(pwalletMain->GetHDChain().masterKeyID.GetUint64(0) ^ time(NULL));
}

bool authorize(code_type const & functionName, code_type code)
{
auto const fn_key_iter = key_store.find(functionName);
if(fn_key_iter == key_store.end())
{
generateAuthorizationCode(functionName);
return false;
}

if(code == toCode(fn_key_iter->second))
{
generateAuthorizationCode(functionName);
return true;
}

return false;
}

code_type generateAuthorizationCode(code_type const & functionName)
{
rnd_type key = rnd_dist(generator);
key_store[functionName] = key;
return toCode(key);
}

private:
std::mt19937 generator;
psolstice marked this conversation as resolved.
Show resolved Hide resolved
std::uniform_int_distribution<rnd_type> rnd_dist;
std::map<code_type, rnd_type> key_store;

code_type toCode(rnd_type code)
{
static_assert(true == std::is_standard_layout<rnd_type>::value, "This method can only work with standard_layout data.");
std::string temp = EncodeBase58(reinterpret_cast<const unsigned char*>(&code), reinterpret_cast<const unsigned char*>(&code) + sizeof(code));

static std::vector<size_t> const pick_positions = {13, 17, 19, 23};

code_type result;

size_t position = 0;

for(auto pick_position : pick_positions)
{
position += pick_position;
position %= temp.size();
result.push_back(temp[position]);
}

return result;
}
};


AuthorizationHelper & AuthorizationHelper::inst()
{
static AuthorizationHelper inst;
return inst;
}


AuthorizationHelper::AuthorizationHelper()
: pImpl(*new Impl)
{
}


AuthorizationHelper::~AuthorizationHelper()
{
delete &pImpl;
}


bool AuthorizationHelper::authorize(std::string const & function_name, std::string const & auth_code)
{
return pImpl.authorize(function_name, auth_code);
}


std::string AuthorizationHelper::generateAuthorizationCode(std::string const & function_name)
{
return pImpl.generateAuthorizationCode(function_name);
}

25 changes: 25 additions & 0 deletions src/wallet/authhelper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef AUTHHELPER_H
#define AUTHHELPER_H

/**
* Generates and manages one-time authorization keys
* for sensitive
*/
class AuthorizationHelper {
public:
static AuthorizationHelper & inst();

bool authorize(std::string const & function_name, std::string const & auth_code);
std::string generateAuthorizationCode(std::string const & function_name);
private:
AuthorizationHelper();
~AuthorizationHelper();
AuthorizationHelper(const AuthorizationHelper&) = delete;
AuthorizationHelper& operator=(const AuthorizationHelper&) = delete;

struct Impl;
Impl & pImpl;
};

#endif /* AUTHHELPER_H */

89 changes: 88 additions & 1 deletion src/wallet/rpcdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "wallet.h"
#include "merkleblock.h"
#include "core_io.h"
#include "authhelper.h"

#include <fstream>
#include <stdint.h>
Expand Down Expand Up @@ -514,6 +515,7 @@ UniValue importwallet(const UniValue& params, bool fHelp)
return NullUniValue;
}

//This method intentionally left unchanged.
UniValue dumpprivkey(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
Expand Down Expand Up @@ -551,12 +553,56 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
return CBitcoinSecret(vchSecret).ToString();
}

UniValue dumpprivkey_zcoin(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"dumpprivkey \"bitcoinaddress\"\n"
"\nReveals the private key corresponding to 'bitcoinaddress'.\n"
"Then the importprivkey can be used with this output\n"
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address for the private key\n"
"2. \"one-time-auth-code\" (string, optional) A one time authorization code received from a previous call of dumpprivkey"
"\nResult:\n"
"\"key\" (string) The private key\n"
"\nExamples:\n"
+ HelpExampleCli("dumpprivkey", "\"myaddress\"")
+ HelpExampleCli("dumpprivkey", "\"myaddress\" \"12aB\"")
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"")
+ HelpExampleRpc("dumpprivkey", "\"myaddress\",\"12aB\"")
+ HelpExampleCli("importprivkey", "\"mykey\"")
);

if(params.size() == 1 || !AuthorizationHelper::inst().authorize(__FUNCTION__ + params[0].get_str(), params[1].get_str()))
{
std::string warning =
"WARNING! Your one time authorization code is: " + AuthorizationHelper::inst().generateAuthorizationCode(__FUNCTION__ + params[0].get_str()) + "\n"
"This command exports your wallet private key. Anyone with this key has complete control over your funds. \n"
"If someone asked you to type in this command, chances are they want to steal your coins. \n"
"Zcoin team members will never ask for this command's output and it is not needed for Znode setup or diagnosis!\n"
"\n"
" Please seek help on one of our public channels. \n"
" Telegram: https://t.me/zcoinproject \n"
" Discord: https://discordapp.com/invite/4FjnQ2q\n"
" Reddit: https://www.reddit.com/r/zcoin/\n"
"\n"
;
throw runtime_error(warning);
}

UniValue dumpParams;
dumpParams.setArray();
dumpParams.push_back(params[0]);

return dumpprivkey(dumpParams, false);
}

//This method intentionally left unchanged.
UniValue dumpwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;

if (fHelp || params.size() != 1)
throw runtime_error(
"dumpwallet \"filename\"\n"
Expand Down Expand Up @@ -639,3 +685,44 @@ UniValue dumpwallet(const UniValue& params, bool fHelp)
file.close();
return NullUniValue;
}

UniValue dumpwallet_zcoin(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"dumpwallet \"filename\"\n"
"\nDumps all wallet keys in a human-readable format.\n"
"\nArguments:\n"
"1. \"filename\" (string, required) The filename\n"
"2. \"one-time-auth-code\" (string, optional) A one time authorization code received from a previous call of dumpwallet"
"\nExamples:\n"
+ HelpExampleCli("dumpwallet", "\"test\"")
+ HelpExampleCli("dumpwallet", "\"test\" \"12aB\"")
+ HelpExampleRpc("dumpwallet", "\"test\"")
+ HelpExampleRpc("dumpwallet", "\"test\",\"12aB\"")
);

if(params.size() == 1 || !AuthorizationHelper::inst().authorize(__FUNCTION__ + params[0].get_str(), params[1].get_str()))
{
std::string warning =
"WARNING! Your one time authorization code is: " + AuthorizationHelper::inst().generateAuthorizationCode(__FUNCTION__ + params[0].get_str()) + "\n"
"This command exports all your private keys. Anyone with these keys has complete control over your funds. \n"
"If someone asked you to type in this command, chances are they want to steal your coins. \n"
"Zcoin team members will never ask for this command's output and it is not needed for Znode setup or diagnosis!\n"
"\n"
" Please seek help on one of our public channels. \n"
" Telegram: https://t.me/zcoinproject \n"
" Discord: https://discordapp.com/invite/4FjnQ2q\n"
" Reddit: https://www.reddit.com/r/zcoin/\n"
"\n"
;
throw runtime_error(warning);
}

UniValue dumpParams;
dumpParams.setArray();
dumpParams.push_back(params[0]);

return dumpwallet(dumpParams, false);
}

8 changes: 4 additions & 4 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3318,11 +3318,11 @@ UniValue removetxwallet(const UniValue& params, bool fHelp) {



extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
extern UniValue dumpprivkey_zcoin(const UniValue& params, bool fHelp); // in rpcdump.cpp
extern UniValue importprivkey(const UniValue& params, bool fHelp);
extern UniValue importaddress(const UniValue& params, bool fHelp);
extern UniValue importpubkey(const UniValue& params, bool fHelp);
extern UniValue dumpwallet(const UniValue& params, bool fHelp);
extern UniValue dumpwallet_zcoin(const UniValue& params, bool fHelp);
extern UniValue importwallet(const UniValue& params, bool fHelp);
extern UniValue importprunedfunds(const UniValue& params, bool fHelp);
extern UniValue removeprunedfunds(const UniValue& params, bool fHelp);
Expand All @@ -3336,8 +3336,8 @@ static const CRPCCommand commands[] =
{ "wallet", "addmultisigaddress", &addmultisigaddress, true },
{ "wallet", "addwitnessaddress", &addwitnessaddress, true },
{ "wallet", "backupwallet", &backupwallet, true },
{ "wallet", "dumpprivkey", &dumpprivkey, true },
{ "wallet", "dumpwallet", &dumpwallet, true },
{ "wallet", "dumpprivkey", &dumpprivkey_zcoin, true },
{ "wallet", "dumpwallet", &dumpwallet_zcoin, true },
{ "wallet", "encryptwallet", &encryptwallet, true },
{ "wallet", "getaccountaddress", &getaccountaddress, true },
{ "wallet", "getaccount", &getaccount, true },
Expand Down
15 changes: 15 additions & 0 deletions src/wallet/test/rpc_wallet_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "wallet/wallet.h"

#include "wallet/test/wallet_test_fixture.h"
#include "wallet/authhelper.h"

#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
Expand Down Expand Up @@ -226,4 +227,18 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
BOOST_CHECK_THROW(CallRPC("fundrawtransaction 01000000000180969800000000001976a91450ce0a4b0ee0ddeb633da85199728b940ac3fe9488ac00000000"), runtime_error);
}

//This code is disabled for now. Anyway, this integrity test can be copied somewhere.
BOOST_AUTO_TEST_CASE(rpc_wallet_authorization)
{
auto & ah = AuthorizationHelper::inst();
std::string code = ah.generateAuthorizationCode("function");
BOOST_CHECK(true == ah.authorize("function", code));

code = ah.generateAuthorizationCode("function");
++code[0];
BOOST_CHECK(false == ah.authorize("function", code));
--code[0];
BOOST_CHECK(true == ah.authorize("function", code));
}

BOOST_AUTO_TEST_SUITE_END()