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