Line data Source code
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 650 : const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n"; 23 : 24 19 : MessageVerificationResult MessageVerify( 25 : const std::string& address, 26 : const std::string& signature, 27 : const std::string& message) 28 : { 29 19 : CTxDestination destination = DecodeDestination(address); 30 19 : if (!IsValidDestination(destination)) { 31 1 : return MessageVerificationResult::ERR_INVALID_ADDRESS; 32 : } 33 : 34 18 : if (boost::get<PKHash>(&destination) == nullptr) { 35 1 : return MessageVerificationResult::ERR_ADDRESS_NO_KEY; 36 : } 37 : 38 17 : bool invalid = false; 39 17 : std::vector<unsigned char> signature_bytes = DecodeBase64(signature.c_str(), &invalid); 40 17 : if (invalid) { 41 1 : return MessageVerificationResult::ERR_MALFORMED_SIGNATURE; 42 : } 43 : 44 16 : CPubKey pubkey; 45 16 : if (!pubkey.RecoverCompact(MessageHash(message), signature_bytes)) { 46 1 : return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED; 47 : } 48 : 49 15 : if (!(CTxDestination(PKHash(pubkey)) == destination)) { 50 3 : return MessageVerificationResult::ERR_NOT_SIGNED; 51 : } 52 : 53 12 : return MessageVerificationResult::OK; 54 19 : } 55 : 56 15 : bool MessageSign( 57 : const CKey& privkey, 58 : const std::string& message, 59 : std::string& signature) 60 : { 61 15 : std::vector<unsigned char> signature_bytes; 62 : 63 15 : if (!privkey.SignCompact(MessageHash(message), signature_bytes)) { 64 1 : return false; 65 : } 66 : 67 14 : signature = EncodeBase64(signature_bytes); 68 : 69 14 : return true; 70 15 : } 71 : 72 32 : uint256 MessageHash(const std::string& message) 73 : { 74 32 : CHashWriter hasher(SER_GETHASH, 0); 75 32 : hasher << MESSAGE_MAGIC << message; 76 : 77 32 : return hasher.GetHash(); 78 32 : } 79 : 80 0 : std::string SigningResultString(const SigningResult res) 81 : { 82 0 : switch (res) { 83 : case SigningResult::OK: 84 0 : return "No error"; 85 : case SigningResult::PRIVATE_KEY_NOT_AVAILABLE: 86 0 : return "Private key not available"; 87 : case SigningResult::SIGNING_FAILED: 88 0 : return "Sign failed"; 89 : // no default case, so the compiler can warn about missing cases 90 : } 91 0 : assert(false); 92 0 : }