github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/cmd/ethkey/message.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:27</date>
    10  //</624342589478277120>
    11  
    12  
    13  package main
    14  
    15  import (
    16  	"encoding/hex"
    17  	"fmt"
    18  	"io/ioutil"
    19  
    20  	"github.com/ethereum/go-ethereum/accounts/keystore"
    21  	"github.com/ethereum/go-ethereum/cmd/utils"
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/crypto"
    24  	"gopkg.in/urfave/cli.v1"
    25  )
    26  
    27  type outputSign struct {
    28  	Signature string
    29  }
    30  
    31  var msgfileFlag = cli.StringFlag{
    32  	Name:  "msgfile",
    33  	Usage: "file containing the message to sign/verify",
    34  }
    35  
    36  var commandSignMessage = cli.Command{
    37  	Name:      "signmessage",
    38  	Usage:     "sign a message",
    39  	ArgsUsage: "<keyfile> <message>",
    40  	Description: `
    41  Sign the message with a keyfile.
    42  
    43  To sign a message contained in a file, use the --msgfile flag.
    44  `,
    45  	Flags: []cli.Flag{
    46  		passphraseFlag,
    47  		jsonFlag,
    48  		msgfileFlag,
    49  	},
    50  	Action: func(ctx *cli.Context) error {
    51  		message := getMessage(ctx, 1)
    52  
    53  //加载密钥文件。
    54  		keyfilepath := ctx.Args().First()
    55  		keyjson, err := ioutil.ReadFile(keyfilepath)
    56  		if err != nil {
    57  			utils.Fatalf("Failed to read the keyfile at '%s': %v", keyfilepath, err)
    58  		}
    59  
    60  //用密码短语解密密钥。
    61  		passphrase := getPassphrase(ctx)
    62  		key, err := keystore.DecryptKey(keyjson, passphrase)
    63  		if err != nil {
    64  			utils.Fatalf("Error decrypting key: %v", err)
    65  		}
    66  
    67  		signature, err := crypto.Sign(signHash(message), key.PrivateKey)
    68  		if err != nil {
    69  			utils.Fatalf("Failed to sign message: %v", err)
    70  		}
    71  		out := outputSign{Signature: hex.EncodeToString(signature)}
    72  		if ctx.Bool(jsonFlag.Name) {
    73  			mustPrintJSON(out)
    74  		} else {
    75  			fmt.Println("Signature:", out.Signature)
    76  		}
    77  		return nil
    78  	},
    79  }
    80  
    81  type outputVerify struct {
    82  	Success            bool
    83  	RecoveredAddress   string
    84  	RecoveredPublicKey string
    85  }
    86  
    87  var commandVerifyMessage = cli.Command{
    88  	Name:      "verifymessage",
    89  	Usage:     "verify the signature of a signed message",
    90  	ArgsUsage: "<address> <signature> <message>",
    91  	Description: `
    92  Verify the signature of the message.
    93  It is possible to refer to a file containing the message.`,
    94  	Flags: []cli.Flag{
    95  		jsonFlag,
    96  		msgfileFlag,
    97  	},
    98  	Action: func(ctx *cli.Context) error {
    99  		addressStr := ctx.Args().First()
   100  		signatureHex := ctx.Args().Get(1)
   101  		message := getMessage(ctx, 2)
   102  
   103  		if !common.IsHexAddress(addressStr) {
   104  			utils.Fatalf("Invalid address: %s", addressStr)
   105  		}
   106  		address := common.HexToAddress(addressStr)
   107  		signature, err := hex.DecodeString(signatureHex)
   108  		if err != nil {
   109  			utils.Fatalf("Signature encoding is not hexadecimal: %v", err)
   110  		}
   111  
   112  		recoveredPubkey, err := crypto.SigToPub(signHash(message), signature)
   113  		if err != nil || recoveredPubkey == nil {
   114  			utils.Fatalf("Signature verification failed: %v", err)
   115  		}
   116  		recoveredPubkeyBytes := crypto.FromECDSAPub(recoveredPubkey)
   117  		recoveredAddress := crypto.PubkeyToAddress(*recoveredPubkey)
   118  		success := address == recoveredAddress
   119  
   120  		out := outputVerify{
   121  			Success:            success,
   122  			RecoveredPublicKey: hex.EncodeToString(recoveredPubkeyBytes),
   123  			RecoveredAddress:   recoveredAddress.Hex(),
   124  		}
   125  		if ctx.Bool(jsonFlag.Name) {
   126  			mustPrintJSON(out)
   127  		} else {
   128  			if out.Success {
   129  				fmt.Println("Signature verification successful!")
   130  			} else {
   131  				fmt.Println("Signature verification failed!")
   132  			}
   133  			fmt.Println("Recovered public key:", out.RecoveredPublicKey)
   134  			fmt.Println("Recovered address:", out.RecoveredAddress)
   135  		}
   136  		return nil
   137  	},
   138  }
   139  
   140  func getMessage(ctx *cli.Context, msgarg int) []byte {
   141  	if file := ctx.String("msgfile"); file != "" {
   142  		if len(ctx.Args()) > msgarg {
   143  			utils.Fatalf("Can't use --msgfile and message argument at the same time.")
   144  		}
   145  		msg, err := ioutil.ReadFile(file)
   146  		if err != nil {
   147  			utils.Fatalf("Can't read message file: %v", err)
   148  		}
   149  		return msg
   150  	} else if len(ctx.Args()) == msgarg+1 {
   151  		return []byte(ctx.Args().Get(msgarg))
   152  	}
   153  	utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, len(ctx.Args()))
   154  	return nil
   155  }
   156