Merge pull request #818
89d9f38
wallet: add command and RPC to sign/verify data (moneromooo-monero)
This commit is contained in:
commit
77e1d8774a
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -386,6 +386,9 @@ namespace tools
|
||||||
void set_tx_note(const crypto::hash &txid, const std::string ¬e);
|
void set_tx_note(const crypto::hash &txid, const std::string ¬e);
|
||||||
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.
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue