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