github.com/kivutar/go-ethereum@v1.7.4-0.20180117074026-6fdb126e9630/cmd/ethkey/message.go (about)

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