github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/cmd/ethkey/message.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package main 19 20 import ( 21 "encoding/hex" 22 "fmt" 23 "io/ioutil" 24 25 "github.com/AigarNetwork/aigar/accounts/keystore" 26 "github.com/AigarNetwork/aigar/cmd/utils" 27 "github.com/AigarNetwork/aigar/common" 28 "github.com/AigarNetwork/aigar/crypto" 29 "gopkg.in/urfave/cli.v1" 30 ) 31 32 type outputSign struct { 33 Signature string 34 } 35 36 var msgfileFlag = cli.StringFlag{ 37 Name: "msgfile", 38 Usage: "file containing the message to sign/verify", 39 } 40 41 var commandSignMessage = cli.Command{ 42 Name: "signmessage", 43 Usage: "sign a message", 44 ArgsUsage: "<keyfile> <message>", 45 Description: ` 46 Sign the message with a keyfile. 47 48 To sign a message contained in a file, use the --msgfile flag. 49 `, 50 Flags: []cli.Flag{ 51 passphraseFlag, 52 jsonFlag, 53 msgfileFlag, 54 }, 55 Action: func(ctx *cli.Context) error { 56 message := getMessage(ctx, 1) 57 58 // Load the keyfile. 59 keyfilepath := ctx.Args().First() 60 keyjson, err := ioutil.ReadFile(keyfilepath) 61 if err != nil { 62 utils.Fatalf("Failed to read the keyfile at '%s': %v", keyfilepath, err) 63 } 64 65 // Decrypt key with passphrase. 66 passphrase := getPassphrase(ctx) 67 key, err := keystore.DecryptKey(keyjson, passphrase) 68 if err != nil { 69 utils.Fatalf("Error decrypting key: %v", err) 70 } 71 72 signature, err := crypto.Sign(signHash(message), key.PrivateKey) 73 if err != nil { 74 utils.Fatalf("Failed to sign message: %v", err) 75 } 76 out := outputSign{Signature: hex.EncodeToString(signature)} 77 if ctx.Bool(jsonFlag.Name) { 78 mustPrintJSON(out) 79 } else { 80 fmt.Println("Signature:", out.Signature) 81 } 82 return nil 83 }, 84 } 85 86 type outputVerify struct { 87 Success bool 88 RecoveredAddress string 89 RecoveredPublicKey string 90 } 91 92 var commandVerifyMessage = cli.Command{ 93 Name: "verifymessage", 94 Usage: "verify the signature of a signed message", 95 ArgsUsage: "<address> <signature> <message>", 96 Description: ` 97 Verify the signature of the message. 98 It is possible to refer to a file containing the message.`, 99 Flags: []cli.Flag{ 100 jsonFlag, 101 msgfileFlag, 102 }, 103 Action: func(ctx *cli.Context) error { 104 addressStr := ctx.Args().First() 105 signatureHex := ctx.Args().Get(1) 106 message := getMessage(ctx, 2) 107 108 if !common.IsHexAddress(addressStr) { 109 utils.Fatalf("Invalid address: %s", addressStr) 110 } 111 address := common.HexToAddress(addressStr) 112 signature, err := hex.DecodeString(signatureHex) 113 if err != nil { 114 utils.Fatalf("Signature encoding is not hexadecimal: %v", err) 115 } 116 117 recoveredPubkey, err := crypto.SigToPub(signHash(message), signature) 118 if err != nil || recoveredPubkey == nil { 119 utils.Fatalf("Signature verification failed: %v", err) 120 } 121 recoveredPubkeyBytes := crypto.FromECDSAPub(recoveredPubkey) 122 recoveredAddress := crypto.PubkeyToAddress(*recoveredPubkey) 123 success := address == recoveredAddress 124 125 out := outputVerify{ 126 Success: success, 127 RecoveredPublicKey: hex.EncodeToString(recoveredPubkeyBytes), 128 RecoveredAddress: recoveredAddress.Hex(), 129 } 130 if ctx.Bool(jsonFlag.Name) { 131 mustPrintJSON(out) 132 } else { 133 if out.Success { 134 fmt.Println("Signature verification successful!") 135 } else { 136 fmt.Println("Signature verification failed!") 137 } 138 fmt.Println("Recovered public key:", out.RecoveredPublicKey) 139 fmt.Println("Recovered address:", out.RecoveredAddress) 140 } 141 return nil 142 }, 143 } 144 145 func getMessage(ctx *cli.Context, msgarg int) []byte { 146 if file := ctx.String("msgfile"); file != "" { 147 if len(ctx.Args()) > msgarg { 148 utils.Fatalf("Can't use --msgfile and message argument at the same time.") 149 } 150 msg, err := ioutil.ReadFile(file) 151 if err != nil { 152 utils.Fatalf("Can't read message file: %v", err) 153 } 154 return msg 155 } else if len(ctx.Args()) == msgarg+1 { 156 return []byte(ctx.Args().Get(msgarg)) 157 } 158 utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, len(ctx.Args())) 159 return nil 160 }