1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2020 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 <hash.h> // For CHashWriter
7 #include <key.h> // For CKey
8 #include <key_io.h> // For DecodeDestination()
9 #include <pubkey.h> // For CPubKey
10 #include <script/standard.h> // For CTxDestination, IsValidDestination(), PKHash
11 #include <serialize.h> // For SER_GETHASH
12 #include <util/message.h>
13 #include <util/strencodings.h> // For DecodeBase64()
14
15 #include <string>
16 #include <vector>
17
18 /**
19 * Text used to signify that a signed message follows and to prevent
20 * inadvertently signing a transaction.
21 */
22 const std::string MESSAGE_MAGIC = "Namecoin Signed Message:\n";
23
MessageVerify(const std::string & address,const std::string & signature,const std::string & message)24 MessageVerificationResult MessageVerify(
25 const std::string& address,
26 const std::string& signature,
27 const std::string& message)
28 {
29 CTxDestination destination = DecodeDestination(address);
30 if (!IsValidDestination(destination)) {
31 return MessageVerificationResult::ERR_INVALID_ADDRESS;
32 }
33
34 if (boost::get<PKHash>(&destination) == nullptr) {
35 return MessageVerificationResult::ERR_ADDRESS_NO_KEY;
36 }
37
38 bool invalid = false;
39 std::vector<unsigned char> signature_bytes = DecodeBase64(signature.c_str(), &invalid);
40 if (invalid) {
41 return MessageVerificationResult::ERR_MALFORMED_SIGNATURE;
42 }
43
44 CPubKey pubkey;
45 if (!pubkey.RecoverCompact(MessageHash(message), signature_bytes)) {
46 return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED;
47 }
48
49 if (!(CTxDestination(PKHash(pubkey)) == destination)) {
50 return MessageVerificationResult::ERR_NOT_SIGNED;
51 }
52
53 return MessageVerificationResult::OK;
54 }
55
MessageSign(const CKey & privkey,const std::string & message,std::string & signature)56 bool MessageSign(
57 const CKey& privkey,
58 const std::string& message,
59 std::string& signature)
60 {
61 std::vector<unsigned char> signature_bytes;
62
63 if (!privkey.SignCompact(MessageHash(message), signature_bytes)) {
64 return false;
65 }
66
67 signature = EncodeBase64(signature_bytes);
68
69 return true;
70 }
71
MessageHash(const std::string & message)72 uint256 MessageHash(const std::string& message)
73 {
74 CHashWriter hasher(SER_GETHASH, 0);
75 hasher << MESSAGE_MAGIC << message;
76
77 return hasher.GetHash();
78 }
79
SigningResultString(const SigningResult res)80 std::string SigningResultString(const SigningResult res)
81 {
82 switch (res) {
83 case SigningResult::OK:
84 return "No error";
85 case SigningResult::PRIVATE_KEY_NOT_AVAILABLE:
86 return "Private key not available";
87 case SigningResult::SIGNING_FAILED:
88 return "Sign failed";
89 // no default case, so the compiler can warn about missing cases
90 }
91 assert(false);
92 }
93