github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/cmd/qctkey/message.go (about)

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