Merge pull request #818

89d9f38 wallet: add command and RPC to sign/verify data (moneromooo-monero)
This commit is contained in:
Riccardo Spagni 2016-07-20 13:50:41 +02:00
commit 77e1d8774a
No known key found for this signature in database
GPG Key ID: 55432DF31CCD4FCD
8 changed files with 195 additions and 2 deletions

View File

@ -658,6 +658,8 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("set_tx_note", boost::bind(&simple_wallet::set_tx_note, this, _1), tr("Set an arbitrary string note for a txid")); m_cmd_binder.set_handler("set_tx_note", boost::bind(&simple_wallet::set_tx_note, this, _1), tr("Set an arbitrary string note for a txid"));
m_cmd_binder.set_handler("get_tx_note", boost::bind(&simple_wallet::get_tx_note, this, _1), tr("Get a string note for a txid")); m_cmd_binder.set_handler("get_tx_note", boost::bind(&simple_wallet::get_tx_note, this, _1), tr("Get a string note for a txid"));
m_cmd_binder.set_handler("status", boost::bind(&simple_wallet::status, this, _1), tr("Show wallet status information")); m_cmd_binder.set_handler("status", boost::bind(&simple_wallet::status, this, _1), tr("Show wallet status information"));
m_cmd_binder.set_handler("sign", boost::bind(&simple_wallet::sign, this, _1), tr("Sign the contents of a file"));
m_cmd_binder.set_handler("verify", boost::bind(&simple_wallet::verify, this, _1), tr("Verify a signature on the contents of a file"));
m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("Show this help")); m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("Show this help"));
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -3368,6 +3370,71 @@ bool simple_wallet::status(const std::vector<std::string> &args)
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::sign(const std::vector<std::string> &args)
{
if (args.size() != 1)
{
fail_msg_writer() << tr("usage: sign <filename>");
return true;
}
if (m_wallet->watch_only())
{
fail_msg_writer() << tr("wallet is watch-only and cannot sign");
return true;
}
std::string filename = args[0];
std::string data;
bool r = epee::file_io_utils::load_file_to_string(filename, data);
if (!r)
{
fail_msg_writer() << tr("failed to read file ") << filename;
return true;
}
std::string signature = m_wallet->sign(data);
success_msg_writer() << signature;
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::verify(const std::vector<std::string> &args)
{
if (args.size() != 3)
{
fail_msg_writer() << tr("usage: verify <filename> <address> <signature>");
return true;
}
std::string filename = args[0];
std::string address_string = args[1];
std::string signature= args[2];
std::string data;
bool r = epee::file_io_utils::load_file_to_string(filename, data);
if (!r)
{
fail_msg_writer() << tr("failed to read file ") << filename;
return true;
}
cryptonote::account_public_address address;
bool has_payment_id;
crypto::hash8 payment_id;
if(!get_account_integrated_address_from_str(address, has_payment_id, payment_id, m_wallet->testnet(), address_string))
{
fail_msg_writer() << tr("failed to parse address");
return true;
}
r = m_wallet->verify(data, address, signature);
if (!r)
{
fail_msg_writer() << tr("Bad signature from ") << address_string;
}
else
{
success_msg_writer() << tr("Good signature from ") << address_string;
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::process_command(const std::vector<std::string> &args) bool simple_wallet::process_command(const std::vector<std::string> &args)
{ {
return m_cmd_binder.process_command_vec(args); return m_cmd_binder.process_command_vec(args);

View File

@ -143,6 +143,8 @@ namespace cryptonote
bool get_tx_note(const std::vector<std::string> &args); bool get_tx_note(const std::vector<std::string> &args);
bool status(const std::vector<std::string> &args); bool status(const std::vector<std::string> &args);
bool set_default_fee_multiplier(const std::vector<std::string> &args); bool set_default_fee_multiplier(const std::vector<std::string> &args);
bool sign(const std::vector<std::string> &args);
bool verify(const std::vector<std::string> &args);
uint64_t get_daemon_blockchain_height(std::string& err); uint64_t get_daemon_blockchain_height(std::string& err);
bool try_connect_to_daemon(); bool try_connect_to_daemon();

View File

@ -53,6 +53,7 @@ using namespace epee;
#include "rapidjson/writer.h" #include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h" #include "rapidjson/stringbuffer.h"
#include "common/json_util.h" #include "common/json_util.h"
#include "common/base58.h"
extern "C" extern "C"
{ {
@ -3106,6 +3107,40 @@ std::string wallet2::get_tx_note(const crypto::hash &txid) const
return std::string(); return std::string();
return i->second; return i->second;
} }
std::string wallet2::sign(const std::string &data) const
{
crypto::hash hash;
crypto::cn_fast_hash(data.data(), data.size(), hash);
const cryptonote::account_keys &keys = m_account.get_keys();
crypto::signature signature;
crypto::generate_signature(hash, keys.m_account_address.m_spend_public_key, keys.m_spend_secret_key, signature);
return std::string("SigV1") + tools::base58::encode(std::string((const char *)&signature, sizeof(signature)));
}
bool wallet2::verify(const std::string &data, const cryptonote::account_public_address &address, const std::string &signature) const
{
const size_t header_len = strlen("SigV1");
if (signature.size() < header_len || signature.substr(0, header_len) != "SigV1") {
LOG_PRINT_L0("Signature header check error");
return false;
}
crypto::hash hash;
crypto::cn_fast_hash(data.data(), data.size(), hash);
std::string decoded;
if (!tools::base58::decode(signature.substr(header_len), decoded)) {
LOG_PRINT_L0("Signature decoding error");
return false;
}
crypto::signature s;
if (sizeof(s) != decoded.size()) {
LOG_PRINT_L0("Signature decoding error");
return false;
}
memcpy(&s, decoded.data(), sizeof(s));
return crypto::check_signature(hash, address.m_spend_public_key, s);
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void wallet2::generate_genesis(cryptonote::block& b) { void wallet2::generate_genesis(cryptonote::block& b) {
if (m_testnet) if (m_testnet)

View File

@ -386,6 +386,9 @@ namespace tools
void set_tx_note(const crypto::hash &txid, const std::string &note); void set_tx_note(const crypto::hash &txid, const std::string &note);
std::string get_tx_note(const crypto::hash &txid) const; std::string get_tx_note(const crypto::hash &txid) const;
std::string sign(const std::string &data) const;
bool verify(const std::string &data, const cryptonote::account_public_address &address, const std::string &signature) const;
private: private:
/*! /*!
* \brief Stores wallet information to wallet file. * \brief Stores wallet information to wallet file.

View File

@ -747,6 +747,42 @@ namespace tools
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_sign(const wallet_rpc::COMMAND_RPC_SIGN::request& req, wallet_rpc::COMMAND_RPC_SIGN::response& res, epee::json_rpc::error& er)
{
if (m_wallet.restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
res.signature = m_wallet.sign(req.data);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_verify(const wallet_rpc::COMMAND_RPC_VERIFY::request& req, wallet_rpc::COMMAND_RPC_VERIFY::response& res, epee::json_rpc::error& er)
{
if (m_wallet.restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
cryptonote::account_public_address address;
bool has_payment_id;
crypto::hash8 payment_id;
if(!get_account_integrated_address_from_str(address, has_payment_id, payment_id, m_wallet.testnet(), req.address))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "";
return false;
}
res.good = m_wallet.verify(req.data, address, req.signature);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_stop_wallet(const wallet_rpc::COMMAND_RPC_STOP_WALLET::request& req, wallet_rpc::COMMAND_RPC_STOP_WALLET::response& res, epee::json_rpc::error& er) bool wallet_rpc_server::on_stop_wallet(const wallet_rpc::COMMAND_RPC_STOP_WALLET::request& req, wallet_rpc::COMMAND_RPC_STOP_WALLET::response& res, epee::json_rpc::error& er)
{ {
if (m_wallet.restricted()) if (m_wallet.restricted())

View File

@ -80,6 +80,8 @@ namespace tools
MAP_JON_RPC_WE("set_tx_notes", on_set_tx_notes, wallet_rpc::COMMAND_RPC_SET_TX_NOTES) MAP_JON_RPC_WE("set_tx_notes", on_set_tx_notes, wallet_rpc::COMMAND_RPC_SET_TX_NOTES)
MAP_JON_RPC_WE("get_tx_notes", on_get_tx_notes, wallet_rpc::COMMAND_RPC_GET_TX_NOTES) MAP_JON_RPC_WE("get_tx_notes", on_get_tx_notes, wallet_rpc::COMMAND_RPC_GET_TX_NOTES)
MAP_JON_RPC_WE("get_transfers", on_get_transfers, wallet_rpc::COMMAND_RPC_GET_TRANSFERS) MAP_JON_RPC_WE("get_transfers", on_get_transfers, wallet_rpc::COMMAND_RPC_GET_TRANSFERS)
MAP_JON_RPC_WE("sign", on_sign, wallet_rpc::COMMAND_RPC_SIGN)
MAP_JON_RPC_WE("verify", on_verify, wallet_rpc::COMMAND_RPC_VERIFY)
END_JSON_RPC_MAP() END_JSON_RPC_MAP()
END_URI_MAP2() END_URI_MAP2()
@ -103,6 +105,8 @@ namespace tools
bool on_set_tx_notes(const wallet_rpc::COMMAND_RPC_SET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_SET_TX_NOTES::response& res, epee::json_rpc::error& er); bool on_set_tx_notes(const wallet_rpc::COMMAND_RPC_SET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_SET_TX_NOTES::response& res, epee::json_rpc::error& er);
bool on_get_tx_notes(const wallet_rpc::COMMAND_RPC_GET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_GET_TX_NOTES::response& res, epee::json_rpc::error& er); bool on_get_tx_notes(const wallet_rpc::COMMAND_RPC_GET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_GET_TX_NOTES::response& res, epee::json_rpc::error& er);
bool on_get_transfers(const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response& res, epee::json_rpc::error& er); bool on_get_transfers(const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response& res, epee::json_rpc::error& er);
bool on_sign(const wallet_rpc::COMMAND_RPC_SIGN::request& req, wallet_rpc::COMMAND_RPC_SIGN::response& res, epee::json_rpc::error& er);
bool on_verify(const wallet_rpc::COMMAND_RPC_VERIFY::request& req, wallet_rpc::COMMAND_RPC_VERIFY::response& res, epee::json_rpc::error& er);
bool handle_command_line(const boost::program_options::variables_map& vm); bool handle_command_line(const boost::program_options::variables_map& vm);

View File

@ -551,6 +551,51 @@ namespace wallet_rpc
}; };
}; };
} struct COMMAND_RPC_SIGN
} {
struct request
{
std::string data;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(data);
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string signature;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(signature);
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_VERIFY
{
struct request
{
std::string data;
std::string address;
std::string signature;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(data);
KV_SERIALIZE(address);
KV_SERIALIZE(signature);
END_KV_SERIALIZE_MAP()
};
struct response
{
bool good;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(good);
END_KV_SERIALIZE_MAP()
};
};
}
}

View File

@ -39,3 +39,4 @@
#define WALLET_RPC_ERROR_CODE_TRANSFER_TYPE -6 #define WALLET_RPC_ERROR_CODE_TRANSFER_TYPE -6
#define WALLET_RPC_ERROR_CODE_DENIED -7 #define WALLET_RPC_ERROR_CODE_DENIED -7
#define WALLET_RPC_ERROR_CODE_WRONG_TXID -8 #define WALLET_RPC_ERROR_CODE_WRONG_TXID -8
#define WALLET_RPC_ERROR_CODE_WRONG_SIGNATURE -9