github.com/ethw3/go-ethereuma@v0.0.0-20221013053120-c14602a4c23c/cmd/ethkey/message.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "encoding/hex" 21 "fmt" 22 "os" 23 24 "github.com/ethw3/go-ethereuma/accounts" 25 "github.com/ethw3/go-ethereuma/accounts/keystore" 26 "github.com/ethw3/go-ethereuma/cmd/utils" 27 "github.com/ethw3/go-ethereuma/common" 28 "github.com/ethw3/go-ethereuma/crypto" 29 "github.com/urfave/cli/v2" 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 := os.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, false) 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(accounts.TextHash(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(accounts.TextHash(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(msgfileFlag.Name); file != "" { 147 if ctx.NArg() > msgarg { 148 utils.Fatalf("Can't use --msgfile and message argument at the same time.") 149 } 150 msg, err := os.ReadFile(file) 151 if err != nil { 152 utils.Fatalf("Can't read message file: %v", err) 153 } 154 return msg 155 } else if ctx.NArg() == msgarg+1 { 156 return []byte(ctx.Args().Get(msgarg)) 157 } 158 utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, ctx.NArg()) 159 return nil 160 }