mirror of
https://github.com/btcsuite/btcd.git
synced 2025-01-18 13:22:34 +01:00
Implement signmessagewithprivkey JSON-RPC command
Reuse the Bitcoin message signature header const also in verifymessage.
This commit is contained in:
parent
b68c50e33c
commit
d2c0123bef
@ -806,6 +806,24 @@ func NewSetGenerateCmd(generate bool, genProcLimit *int) *SetGenerateCmd {
|
||||
}
|
||||
}
|
||||
|
||||
// SignMessageWithPrivKeyCmd defines the signmessagewithprivkey JSON-RPC command.
|
||||
type SignMessageWithPrivKeyCmd struct {
|
||||
PrivKey string // base 58 Wallet Import format private key
|
||||
Message string // Message to sign
|
||||
}
|
||||
|
||||
// NewSignMessageWithPrivKey returns a new instance which can be used to issue a
|
||||
// signmessagewithprivkey JSON-RPC command.
|
||||
//
|
||||
// The first parameter is a private key in base 58 Wallet Import format.
|
||||
// The second parameter is the message to sign.
|
||||
func NewSignMessageWithPrivKey(privKey, message string) *SignMessageWithPrivKeyCmd {
|
||||
return &SignMessageWithPrivKeyCmd{
|
||||
PrivKey: privKey,
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// StopCmd defines the stop JSON-RPC command.
|
||||
type StopCmd struct{}
|
||||
|
||||
@ -971,6 +989,7 @@ func init() {
|
||||
MustRegisterCmd("searchrawtransactions", (*SearchRawTransactionsCmd)(nil), flags)
|
||||
MustRegisterCmd("sendrawtransaction", (*SendRawTransactionCmd)(nil), flags)
|
||||
MustRegisterCmd("setgenerate", (*SetGenerateCmd)(nil), flags)
|
||||
MustRegisterCmd("signmessagewithprivkey", (*SignMessageWithPrivKeyCmd)(nil), flags)
|
||||
MustRegisterCmd("stop", (*StopCmd)(nil), flags)
|
||||
MustRegisterCmd("submitblock", (*SubmitBlockCmd)(nil), flags)
|
||||
MustRegisterCmd("uptime", (*UptimeCmd)(nil), flags)
|
||||
|
@ -1186,6 +1186,20 @@ func TestChainSvrCmds(t *testing.T) {
|
||||
GenProcLimit: btcjson.Int(6),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "signmessagewithprivkey",
|
||||
newCmd: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("signmessagewithprivkey", "5Hue", "Hey")
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewSignMessageWithPrivKey("5Hue", "Hey")
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"signmessagewithprivkey","params":["5Hue","Hey"],"id":1}`,
|
||||
unmarshalled: &btcjson.SignMessageWithPrivKeyCmd{
|
||||
PrivKey: "5Hue",
|
||||
Message: "Hey",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stop",
|
||||
newCmd: func() (interface{}, error) {
|
||||
|
141
rpcserver.go
141
rpcserver.go
@ -127,52 +127,53 @@ type commandHandler func(*rpcServer, interface{}, <-chan struct{}) (interface{},
|
||||
// a dependency loop.
|
||||
var rpcHandlers map[string]commandHandler
|
||||
var rpcHandlersBeforeInit = map[string]commandHandler{
|
||||
"addnode": handleAddNode,
|
||||
"createrawtransaction": handleCreateRawTransaction,
|
||||
"debuglevel": handleDebugLevel,
|
||||
"decoderawtransaction": handleDecodeRawTransaction,
|
||||
"decodescript": handleDecodeScript,
|
||||
"estimatefee": handleEstimateFee,
|
||||
"generate": handleGenerate,
|
||||
"getaddednodeinfo": handleGetAddedNodeInfo,
|
||||
"getbestblock": handleGetBestBlock,
|
||||
"getbestblockhash": handleGetBestBlockHash,
|
||||
"getblock": handleGetBlock,
|
||||
"getblockchaininfo": handleGetBlockChainInfo,
|
||||
"getblockcount": handleGetBlockCount,
|
||||
"getblockhash": handleGetBlockHash,
|
||||
"getblockheader": handleGetBlockHeader,
|
||||
"getblocktemplate": handleGetBlockTemplate,
|
||||
"getcfilter": handleGetCFilter,
|
||||
"getcfilterheader": handleGetCFilterHeader,
|
||||
"getconnectioncount": handleGetConnectionCount,
|
||||
"getcurrentnet": handleGetCurrentNet,
|
||||
"getdifficulty": handleGetDifficulty,
|
||||
"getgenerate": handleGetGenerate,
|
||||
"gethashespersec": handleGetHashesPerSec,
|
||||
"getheaders": handleGetHeaders,
|
||||
"getinfo": handleGetInfo,
|
||||
"getmempoolinfo": handleGetMempoolInfo,
|
||||
"getmininginfo": handleGetMiningInfo,
|
||||
"getnettotals": handleGetNetTotals,
|
||||
"getnetworkhashps": handleGetNetworkHashPS,
|
||||
"getpeerinfo": handleGetPeerInfo,
|
||||
"getrawmempool": handleGetRawMempool,
|
||||
"getrawtransaction": handleGetRawTransaction,
|
||||
"gettxout": handleGetTxOut,
|
||||
"help": handleHelp,
|
||||
"node": handleNode,
|
||||
"ping": handlePing,
|
||||
"searchrawtransactions": handleSearchRawTransactions,
|
||||
"sendrawtransaction": handleSendRawTransaction,
|
||||
"setgenerate": handleSetGenerate,
|
||||
"stop": handleStop,
|
||||
"submitblock": handleSubmitBlock,
|
||||
"uptime": handleUptime,
|
||||
"validateaddress": handleValidateAddress,
|
||||
"verifychain": handleVerifyChain,
|
||||
"verifymessage": handleVerifyMessage,
|
||||
"version": handleVersion,
|
||||
"addnode": handleAddNode,
|
||||
"createrawtransaction": handleCreateRawTransaction,
|
||||
"debuglevel": handleDebugLevel,
|
||||
"decoderawtransaction": handleDecodeRawTransaction,
|
||||
"decodescript": handleDecodeScript,
|
||||
"estimatefee": handleEstimateFee,
|
||||
"generate": handleGenerate,
|
||||
"getaddednodeinfo": handleGetAddedNodeInfo,
|
||||
"getbestblock": handleGetBestBlock,
|
||||
"getbestblockhash": handleGetBestBlockHash,
|
||||
"getblock": handleGetBlock,
|
||||
"getblockchaininfo": handleGetBlockChainInfo,
|
||||
"getblockcount": handleGetBlockCount,
|
||||
"getblockhash": handleGetBlockHash,
|
||||
"getblockheader": handleGetBlockHeader,
|
||||
"getblocktemplate": handleGetBlockTemplate,
|
||||
"getcfilter": handleGetCFilter,
|
||||
"getcfilterheader": handleGetCFilterHeader,
|
||||
"getconnectioncount": handleGetConnectionCount,
|
||||
"getcurrentnet": handleGetCurrentNet,
|
||||
"getdifficulty": handleGetDifficulty,
|
||||
"getgenerate": handleGetGenerate,
|
||||
"gethashespersec": handleGetHashesPerSec,
|
||||
"getheaders": handleGetHeaders,
|
||||
"getinfo": handleGetInfo,
|
||||
"getmempoolinfo": handleGetMempoolInfo,
|
||||
"getmininginfo": handleGetMiningInfo,
|
||||
"getnettotals": handleGetNetTotals,
|
||||
"getnetworkhashps": handleGetNetworkHashPS,
|
||||
"getpeerinfo": handleGetPeerInfo,
|
||||
"getrawmempool": handleGetRawMempool,
|
||||
"getrawtransaction": handleGetRawTransaction,
|
||||
"gettxout": handleGetTxOut,
|
||||
"help": handleHelp,
|
||||
"node": handleNode,
|
||||
"ping": handlePing,
|
||||
"searchrawtransactions": handleSearchRawTransactions,
|
||||
"sendrawtransaction": handleSendRawTransaction,
|
||||
"setgenerate": handleSetGenerate,
|
||||
"signmessagewithprivkey": handleSignMessageWithPrivKey,
|
||||
"stop": handleStop,
|
||||
"submitblock": handleSubmitBlock,
|
||||
"uptime": handleUptime,
|
||||
"validateaddress": handleValidateAddress,
|
||||
"verifychain": handleVerifyChain,
|
||||
"verifymessage": handleVerifyMessage,
|
||||
"version": handleVersion,
|
||||
}
|
||||
|
||||
// list of commands that we recognize, but for which btcd has no support because
|
||||
@ -3435,6 +3436,52 @@ func handleSetGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{})
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Text used to signify that a signed message follows and to prevent
|
||||
// inadvertently signing a transaction.
|
||||
const messageSignatureHeader = "Bitcoin Signed Message:\n"
|
||||
|
||||
// handleSignMessageWithPrivKey implements the signmessagewithprivkey command.
|
||||
func handleSignMessageWithPrivKey(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||
c := cmd.(*btcjson.SignMessageWithPrivKeyCmd)
|
||||
|
||||
wif, err := btcutil.DecodeWIF(c.PrivKey)
|
||||
if err != nil {
|
||||
message := "Invalid private key"
|
||||
switch err {
|
||||
case btcutil.ErrMalformedPrivateKey:
|
||||
message = "Malformed private key"
|
||||
case btcutil.ErrChecksumMismatch:
|
||||
message = "Private key checksum mismatch"
|
||||
}
|
||||
return nil, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCInvalidAddressOrKey,
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
if !wif.IsForNet(s.cfg.ChainParams) {
|
||||
return nil, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCInvalidAddressOrKey,
|
||||
Message: "Private key for wrong network",
|
||||
}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
wire.WriteVarString(&buf, 0, messageSignatureHeader)
|
||||
wire.WriteVarString(&buf, 0, c.Message)
|
||||
messageHash := chainhash.DoubleHashB(buf.Bytes())
|
||||
|
||||
sig, err := btcec.SignCompact(btcec.S256(), wif.PrivKey,
|
||||
messageHash, wif.CompressPubKey)
|
||||
if err != nil {
|
||||
return nil, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCInvalidAddressOrKey,
|
||||
Message: "Sign failed",
|
||||
}
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(sig), nil
|
||||
}
|
||||
|
||||
// handleStop implements the stop command.
|
||||
func handleStop(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||
select {
|
||||
@ -3615,7 +3662,7 @@ func handleVerifyMessage(s *rpcServer, cmd interface{}, closeChan <-chan struct{
|
||||
// Validate the signature - this just shows that it was valid at all.
|
||||
// we will compare it with the key next.
|
||||
var buf bytes.Buffer
|
||||
wire.WriteVarString(&buf, 0, "Bitcoin Signed Message:\n")
|
||||
wire.WriteVarString(&buf, 0, messageSignatureHeader)
|
||||
wire.WriteVarString(&buf, 0, c.Message)
|
||||
expectedMessageHash := chainhash.DoubleHashB(buf.Bytes())
|
||||
pk, wasCompressed, err := btcec.RecoverCompact(btcec.S256(), sig,
|
||||
|
@ -559,6 +559,12 @@ var helpDescsEnUS = map[string]string{
|
||||
"setgenerate-generate": "Use true to enable generation, false to disable it",
|
||||
"setgenerate-genproclimit": "The number of processors (cores) to limit generation to or -1 for default",
|
||||
|
||||
// SignMessageWithPrivKeyCmd help.
|
||||
"signmessagewithprivkey--synopsis": "Sign a message with the private key of an address",
|
||||
"signmessagewithprivkey-privkey": "The private key to sign the message with",
|
||||
"signmessagewithprivkey-message": "The message to create a signature of",
|
||||
"signmessagewithprivkey--result0": "The signature of the message encoded in base 64",
|
||||
|
||||
// StopCmd help.
|
||||
"stop--synopsis": "Shutdown btcd.",
|
||||
"stop--result0": "The string 'btcd stopping.'",
|
||||
@ -691,52 +697,53 @@ var helpDescsEnUS = map[string]string{
|
||||
// This information is used to generate the help. Each result type must be a
|
||||
// pointer to the type (or nil to indicate no return value).
|
||||
var rpcResultTypes = map[string][]interface{}{
|
||||
"addnode": nil,
|
||||
"createrawtransaction": {(*string)(nil)},
|
||||
"debuglevel": {(*string)(nil), (*string)(nil)},
|
||||
"decoderawtransaction": {(*btcjson.TxRawDecodeResult)(nil)},
|
||||
"decodescript": {(*btcjson.DecodeScriptResult)(nil)},
|
||||
"estimatefee": {(*float64)(nil)},
|
||||
"generate": {(*[]string)(nil)},
|
||||
"getaddednodeinfo": {(*[]string)(nil), (*[]btcjson.GetAddedNodeInfoResult)(nil)},
|
||||
"getbestblock": {(*btcjson.GetBestBlockResult)(nil)},
|
||||
"getbestblockhash": {(*string)(nil)},
|
||||
"getblock": {(*string)(nil), (*btcjson.GetBlockVerboseResult)(nil)},
|
||||
"getblockcount": {(*int64)(nil)},
|
||||
"getblockhash": {(*string)(nil)},
|
||||
"getblockheader": {(*string)(nil), (*btcjson.GetBlockHeaderVerboseResult)(nil)},
|
||||
"getblocktemplate": {(*btcjson.GetBlockTemplateResult)(nil), (*string)(nil), nil},
|
||||
"getblockchaininfo": {(*btcjson.GetBlockChainInfoResult)(nil)},
|
||||
"getcfilter": {(*string)(nil)},
|
||||
"getcfilterheader": {(*string)(nil)},
|
||||
"getconnectioncount": {(*int32)(nil)},
|
||||
"getcurrentnet": {(*uint32)(nil)},
|
||||
"getdifficulty": {(*float64)(nil)},
|
||||
"getgenerate": {(*bool)(nil)},
|
||||
"gethashespersec": {(*float64)(nil)},
|
||||
"getheaders": {(*[]string)(nil)},
|
||||
"getinfo": {(*btcjson.InfoChainResult)(nil)},
|
||||
"getmempoolinfo": {(*btcjson.GetMempoolInfoResult)(nil)},
|
||||
"getmininginfo": {(*btcjson.GetMiningInfoResult)(nil)},
|
||||
"getnettotals": {(*btcjson.GetNetTotalsResult)(nil)},
|
||||
"getnetworkhashps": {(*int64)(nil)},
|
||||
"getpeerinfo": {(*[]btcjson.GetPeerInfoResult)(nil)},
|
||||
"getrawmempool": {(*[]string)(nil), (*btcjson.GetRawMempoolVerboseResult)(nil)},
|
||||
"getrawtransaction": {(*string)(nil), (*btcjson.TxRawResult)(nil)},
|
||||
"gettxout": {(*btcjson.GetTxOutResult)(nil)},
|
||||
"node": nil,
|
||||
"help": {(*string)(nil), (*string)(nil)},
|
||||
"ping": nil,
|
||||
"searchrawtransactions": {(*string)(nil), (*[]btcjson.SearchRawTransactionsResult)(nil)},
|
||||
"sendrawtransaction": {(*string)(nil)},
|
||||
"setgenerate": nil,
|
||||
"stop": {(*string)(nil)},
|
||||
"submitblock": {nil, (*string)(nil)},
|
||||
"uptime": {(*int64)(nil)},
|
||||
"validateaddress": {(*btcjson.ValidateAddressChainResult)(nil)},
|
||||
"verifychain": {(*bool)(nil)},
|
||||
"verifymessage": {(*bool)(nil)},
|
||||
"version": {(*map[string]btcjson.VersionResult)(nil)},
|
||||
"addnode": nil,
|
||||
"createrawtransaction": {(*string)(nil)},
|
||||
"debuglevel": {(*string)(nil), (*string)(nil)},
|
||||
"decoderawtransaction": {(*btcjson.TxRawDecodeResult)(nil)},
|
||||
"decodescript": {(*btcjson.DecodeScriptResult)(nil)},
|
||||
"estimatefee": {(*float64)(nil)},
|
||||
"generate": {(*[]string)(nil)},
|
||||
"getaddednodeinfo": {(*[]string)(nil), (*[]btcjson.GetAddedNodeInfoResult)(nil)},
|
||||
"getbestblock": {(*btcjson.GetBestBlockResult)(nil)},
|
||||
"getbestblockhash": {(*string)(nil)},
|
||||
"getblock": {(*string)(nil), (*btcjson.GetBlockVerboseResult)(nil)},
|
||||
"getblockcount": {(*int64)(nil)},
|
||||
"getblockhash": {(*string)(nil)},
|
||||
"getblockheader": {(*string)(nil), (*btcjson.GetBlockHeaderVerboseResult)(nil)},
|
||||
"getblocktemplate": {(*btcjson.GetBlockTemplateResult)(nil), (*string)(nil), nil},
|
||||
"getblockchaininfo": {(*btcjson.GetBlockChainInfoResult)(nil)},
|
||||
"getcfilter": {(*string)(nil)},
|
||||
"getcfilterheader": {(*string)(nil)},
|
||||
"getconnectioncount": {(*int32)(nil)},
|
||||
"getcurrentnet": {(*uint32)(nil)},
|
||||
"getdifficulty": {(*float64)(nil)},
|
||||
"getgenerate": {(*bool)(nil)},
|
||||
"gethashespersec": {(*float64)(nil)},
|
||||
"getheaders": {(*[]string)(nil)},
|
||||
"getinfo": {(*btcjson.InfoChainResult)(nil)},
|
||||
"getmempoolinfo": {(*btcjson.GetMempoolInfoResult)(nil)},
|
||||
"getmininginfo": {(*btcjson.GetMiningInfoResult)(nil)},
|
||||
"getnettotals": {(*btcjson.GetNetTotalsResult)(nil)},
|
||||
"getnetworkhashps": {(*int64)(nil)},
|
||||
"getpeerinfo": {(*[]btcjson.GetPeerInfoResult)(nil)},
|
||||
"getrawmempool": {(*[]string)(nil), (*btcjson.GetRawMempoolVerboseResult)(nil)},
|
||||
"getrawtransaction": {(*string)(nil), (*btcjson.TxRawResult)(nil)},
|
||||
"gettxout": {(*btcjson.GetTxOutResult)(nil)},
|
||||
"node": nil,
|
||||
"help": {(*string)(nil), (*string)(nil)},
|
||||
"ping": nil,
|
||||
"searchrawtransactions": {(*string)(nil), (*[]btcjson.SearchRawTransactionsResult)(nil)},
|
||||
"sendrawtransaction": {(*string)(nil)},
|
||||
"setgenerate": nil,
|
||||
"signmessagewithprivkey": {(*string)(nil)},
|
||||
"stop": {(*string)(nil)},
|
||||
"submitblock": {nil, (*string)(nil)},
|
||||
"uptime": {(*int64)(nil)},
|
||||
"validateaddress": {(*btcjson.ValidateAddressChainResult)(nil)},
|
||||
"verifychain": {(*bool)(nil)},
|
||||
"verifymessage": {(*bool)(nil)},
|
||||
"version": {(*map[string]btcjson.VersionResult)(nil)},
|
||||
|
||||
// Websocket commands.
|
||||
"loadtxfilter": nil,
|
||||
|
Loading…
Reference in New Issue
Block a user