message.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package main
  2. import (
  3. "encoding/hex"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "strings"
  8. "github.com/ethereum/go-ethereum/accounts/keystore"
  9. "github.com/ethereum/go-ethereum/cmd/utils"
  10. "github.com/ethereum/go-ethereum/common"
  11. "github.com/ethereum/go-ethereum/crypto"
  12. "gopkg.in/urfave/cli.v1"
  13. )
  14. type outputSign struct {
  15. Signature string
  16. }
  17. var commandSignMessage = cli.Command{
  18. Name: "signmessage",
  19. Usage: "sign a message",
  20. ArgsUsage: "<keyfile> <message/file>",
  21. Description: `
  22. Sign the message with a keyfile.
  23. It is possible to refer to a file containing the message.`,
  24. Flags: []cli.Flag{
  25. passphraseFlag,
  26. jsonFlag,
  27. },
  28. Action: func(ctx *cli.Context) error {
  29. keyfilepath := ctx.Args().First()
  30. message := []byte(ctx.Args().Get(1))
  31. // Load the keyfile.
  32. keyjson, err := ioutil.ReadFile(keyfilepath)
  33. if err != nil {
  34. utils.Fatalf("Failed to read the keyfile at '%s': %v",
  35. keyfilepath, err)
  36. }
  37. // Decrypt key with passphrase.
  38. passphrase := getPassPhrase(ctx, false)
  39. key, err := keystore.DecryptKey(keyjson, passphrase)
  40. if err != nil {
  41. utils.Fatalf("Error decrypting key: %v", err)
  42. }
  43. if len(message) == 0 {
  44. utils.Fatalf("A message must be provided")
  45. }
  46. // Read message if file.
  47. if _, err := os.Stat(string(message)); err == nil {
  48. message, err = ioutil.ReadFile(string(message))
  49. if err != nil {
  50. utils.Fatalf("Failed to read the message file: %v", err)
  51. }
  52. }
  53. signature, err := crypto.Sign(signHash(message), key.PrivateKey)
  54. if err != nil {
  55. utils.Fatalf("Failed to sign message: %v", err)
  56. }
  57. out := outputSign{
  58. Signature: hex.EncodeToString(signature),
  59. }
  60. if ctx.Bool(jsonFlag.Name) {
  61. mustPrintJSON(out)
  62. } else {
  63. fmt.Println("Signature: ", out.Signature)
  64. }
  65. return nil
  66. },
  67. }
  68. type outputVerify struct {
  69. Success bool
  70. RecoveredAddress string
  71. RecoveredPublicKey string
  72. }
  73. var commandVerifyMessage = cli.Command{
  74. Name: "verifymessage",
  75. Usage: "verify the signature of a signed message",
  76. ArgsUsage: "<address> <signature> <message/file>",
  77. Description: `
  78. Verify the signature of the message.
  79. It is possible to refer to a file containing the message.`,
  80. Flags: []cli.Flag{
  81. jsonFlag,
  82. },
  83. Action: func(ctx *cli.Context) error {
  84. addressStr := ctx.Args().First()
  85. signatureHex := ctx.Args().Get(1)
  86. message := []byte(ctx.Args().Get(2))
  87. // Determine whether it is a keyfile, public key or address.
  88. if !common.IsHexAddress(addressStr) {
  89. utils.Fatalf("Invalid address: %s", addressStr)
  90. }
  91. address := common.HexToAddress(addressStr)
  92. signature, err := hex.DecodeString(signatureHex)
  93. if err != nil {
  94. utils.Fatalf("Signature encoding is not hexadecimal: %v", err)
  95. }
  96. if len(message) == 0 {
  97. utils.Fatalf("A message must be provided")
  98. }
  99. // Read message if file.
  100. if _, err := os.Stat(string(message)); err == nil {
  101. message, err = ioutil.ReadFile(string(message))
  102. if err != nil {
  103. utils.Fatalf("Failed to read the message file: %v", err)
  104. }
  105. }
  106. recoveredPubkey, err := crypto.SigToPub(signHash(message), signature)
  107. if err != nil || recoveredPubkey == nil {
  108. utils.Fatalf("Signature verification failed: %v", err)
  109. }
  110. recoveredPubkeyBytes := crypto.FromECDSAPub(recoveredPubkey)
  111. recoveredAddress := crypto.PubkeyToAddress(*recoveredPubkey)
  112. success := address == recoveredAddress
  113. out := outputVerify{
  114. Success: success,
  115. RecoveredPublicKey: hex.EncodeToString(recoveredPubkeyBytes),
  116. RecoveredAddress: strings.ToLower(recoveredAddress.Hex()),
  117. }
  118. if ctx.Bool(jsonFlag.Name) {
  119. mustPrintJSON(out)
  120. } else {
  121. if out.Success {
  122. fmt.Println("Signature verification successful!")
  123. } else {
  124. fmt.Println("Signature verification failed!")
  125. }
  126. fmt.Println("Recovered public key: ", out.RecoveredPublicKey)
  127. fmt.Println("Recovered address: ", out.RecoveredAddress)
  128. }
  129. return nil
  130. },
  131. }