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