signmessage.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto 2 // Copyright (c) 2009-2022 The Bitcoin Core developers 3 // Distributed under the MIT software license, see the accompanying 4 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 6 #include <key.h> 7 #include <key_io.h> 8 #include <rpc/protocol.h> 9 #include <rpc/request.h> 10 #include <rpc/server.h> 11 #include <rpc/util.h> 12 #include <univalue.h> 13 #include <util/message.h> 14 15 #include <string> 16 17 static RPCHelpMan verifymessage() 18 { 19 return RPCHelpMan{"verifymessage", 20 "Verify a signed message.", 21 { 22 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the signature."}, 23 {"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "The signature provided by the signer in base 64 encoding (see signmessage)."}, 24 {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message that was signed."}, 25 }, 26 RPCResult{ 27 RPCResult::Type::BOOL, "", "If the signature is verified or not." 28 }, 29 RPCExamples{ 30 "\nUnlock the wallet for 30 seconds\n" 31 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + 32 "\nCreate the signature\n" 33 + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") + 34 "\nVerify the signature\n" 35 + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") + 36 "\nAs a JSON-RPC call\n" 37 + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"") 38 }, 39 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 40 { 41 std::string strAddress = request.params[0].get_str(); 42 std::string strSign = request.params[1].get_str(); 43 std::string strMessage = request.params[2].get_str(); 44 45 switch (MessageVerify(strAddress, strSign, strMessage)) { 46 case MessageVerificationResult::ERR_INVALID_ADDRESS: 47 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); 48 case MessageVerificationResult::ERR_ADDRESS_NO_KEY: 49 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); 50 case MessageVerificationResult::ERR_MALFORMED_SIGNATURE: 51 throw JSONRPCError(RPC_TYPE_ERROR, "Malformed base64 encoding"); 52 case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED: 53 case MessageVerificationResult::ERR_NOT_SIGNED: 54 return false; 55 case MessageVerificationResult::OK: 56 return true; 57 } 58 59 return false; 60 }, 61 }; 62 } 63 64 static RPCHelpMan signmessagewithprivkey() 65 { 66 return RPCHelpMan{"signmessagewithprivkey", 67 "\nSign a message with the private key of an address\n", 68 { 69 {"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key to sign the message with."}, 70 {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."}, 71 }, 72 RPCResult{ 73 RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64" 74 }, 75 RPCExamples{ 76 "\nCreate the signature\n" 77 + HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") + 78 "\nVerify the signature\n" 79 + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") + 80 "\nAs a JSON-RPC call\n" 81 + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"") 82 }, 83 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 84 { 85 std::string strPrivkey = request.params[0].get_str(); 86 std::string strMessage = request.params[1].get_str(); 87 88 CKey key = DecodeSecret(strPrivkey); 89 if (!key.IsValid()) { 90 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); 91 } 92 93 std::string signature; 94 95 if (!MessageSign(key, strMessage, signature)) { 96 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); 97 } 98 99 return signature; 100 }, 101 }; 102 } 103 104 void RegisterSignMessageRPCCommands(CRPCTable& t) 105 { 106 static const CRPCCommand commands[]{ 107 {"util", &verifymessage}, 108 {"util", &signmessagewithprivkey}, 109 }; 110 for (const auto& c : commands) { 111 t.appendCommand(c.name, &c); 112 } 113 }