Since no one else did...
This adds a new RPC which does not rely on the wallet to sign messages. Continuation of #7899
New rpc 'signmessagewithprivkey' which takes a private key to sign a message without using the wallet.
370 | +{ 371 | + if (fHelp || params.size() != 2) 372 | + throw runtime_error( 373 | + "signmessage \"privkey\" \"message\"\n" 374 | + "\nSign a message with the private key of an address" 375 | + + HelpRequiringPassphrase() + "\n"
You do not need HelpRequiringPassphrase here. It is unavailable in no-wallet builds (see https://travis-ci.org/bitcoin/bitcoin/jobs/126001935#L1864).
Fixed
365 | @@ -366,6 +366,49 @@ UniValue verifymessage(const UniValue& params, bool fHelp) 366 | return (pubkey.GetID() == keyID); 367 | } 368 | 369 | +UniValue signmessagewithprivkey(const UniValue& params, bool fHelp) 370 | +{ 371 | + if (fHelp || params.size() != 2) 372 | + throw runtime_error( 373 | + "signmessage \"privkey\" \"message\"\n"
This has to be signmessagewithprivkey instead of signmessage.
Fixed
404 | + vector<unsigned char> vchSig; 405 | + if (!key.SignCompact(ss.GetHash(), vchSig)) 406 | + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); 407 | + 408 | + return EncodeBase64(&vchSig[0], vchSig.size()); 409 | +}
IMO strPrivkey, vchSecret and params[0] should be mem-cleansed before the function returns.
I guess key RAII -cleans itself.
However, params[] is a const parameter vector passed in, provided by a third-party library. I don't think this issue can be solved in general (except by never passing private keys in the API in the first place). The http server, JSON parsing, the RPC mechanism leaves the parameters all over memory. We have a similar problem in importprivkey. No need to solve in this pull.
Agree. Its just a nitpick (I forgot to pre-fix it with "nit:"). As long as we are dealing with privatekeys in bitcoin-core there will always be memory containing sensitive stuff.
utACK f90efbfeef9cd733aa7590fdf581ff82b999c4b5
ACK https://github.com/bitcoin/bitcoin/commit/f90efbfeef9cd733aa7590fdf581ff82b999c4b5
@jonasschnelli Right. We should also recommend using -stdin for this when document this new RPC in release notes.
Can you please write some test for this new RPC?
@paveljanik I've added a test. I think I did it correctly.
25 | + privKey = 'cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N' 26 | + address = 'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB' 27 | + try: 28 | + signature = self.nodes[0].signmessagewithprivkey(privKey, message) 29 | + except JSONRPCException as e: 30 | + assert("Invalid private key" not in e.error['message'])
All of those seem dead code, so you might as well remove them?
What I mean is: If you don't expect an exception, don't catch it. The whole purpose of the test framework is to fail on any unexpected exception.
Other than that, you may want to try this syntax:
try:
something_that_fails()
assert(False)
except:
assert(thing_on_failure())
or
try:
something_that_fails()
except:
assert(thing_on_failure())
else:
assert(False)
Ok, I'll remove them. I should probably add a failure condition, right?
Right, if you feel like adding a case that should fail to check if it fails properly, you are very welcome to do so.
32 | + # Test the signing with an address with wallet 33 | + address = self.nodes[0].getnewaddress() 34 | + signature = self.nodes[0].signmessage(address, message) 35 | + 36 | + # Verify the message 37 | + self.nodes[0].verifymessage(address, signature, message)
You should assert the result from verifymessage
done
New rpc test for signing and verifying messages.
Tested ACK. Binaries: https://bitcoin.jonasschnelli.ch/pulls/7953/