github.com/core-coin/go-core/v2@v2.1.9/cmd/xcbkey/message.go (about) 1 // Copyright 2017 by the Authors 2 // This file is part of go-core. 3 // 4 // go-core 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-core 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-core. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "encoding/hex" 21 "fmt" 22 "io/ioutil" 23 24 "gopkg.in/urfave/cli.v1" 25 26 "github.com/core-coin/go-core/v2/accounts/keystore" 27 "github.com/core-coin/go-core/v2/cmd/utils" 28 "github.com/core-coin/go-core/v2/common" 29 "github.com/core-coin/go-core/v2/crypto" 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 utils.NetworkIdFlag, 55 }, 56 Action: func(ctx *cli.Context) error { 57 if ctx.IsSet(utils.NetworkIdFlag.Name) { 58 common.DefaultNetworkID = common.NetworkID(ctx.Uint64(utils.NetworkIdFlag.Name)) 59 } 60 61 message := getMessage(ctx, 1) 62 63 // Load the keyfile. 64 keyfilepath := ctx.Args().First() 65 keyjson, err := ioutil.ReadFile(keyfilepath) 66 if err != nil { 67 utils.Fatalf("Failed to read the keyfile at '%s': %v", keyfilepath, err) 68 } 69 70 // Decrypt key with passphrase. 71 passphrase := getPassphrase(ctx, false) 72 key, err := keystore.DecryptKey(keyjson, passphrase) 73 if err != nil { 74 utils.Fatalf("Error decrypting key: %v", err) 75 } 76 77 signature, err := crypto.Sign(signHash(message), key.PrivateKey) 78 if err != nil { 79 utils.Fatalf("Failed to sign message: %v", err) 80 } 81 out := outputSign{Signature: hex.EncodeToString(signature)} 82 if ctx.Bool(jsonFlag.Name) { 83 mustPrintJSON(out) 84 } else { 85 fmt.Println("Signature:", out.Signature) 86 } 87 return nil 88 }, 89 } 90 91 type outputVerify struct { 92 Success bool 93 RecoveredAddress string 94 RecoveredPublicKey string 95 } 96 97 var commandVerifyMessage = cli.Command{ 98 Name: "verifymessage", 99 Usage: "verify the signature of a signed message", 100 ArgsUsage: "<address> <signature> <message>", 101 Description: ` 102 Verify the signature of the message. 103 It is possible to refer to a file containing the message.`, 104 Flags: []cli.Flag{ 105 jsonFlag, 106 msgfileFlag, 107 utils.NetworkIdFlag, 108 }, 109 Action: func(ctx *cli.Context) error { 110 if ctx.IsSet(utils.NetworkIdFlag.Name) { 111 common.DefaultNetworkID = common.NetworkID(ctx.Uint64(utils.NetworkIdFlag.Name)) 112 } 113 114 addressStr := ctx.Args().First() 115 signatureHex := ctx.Args().Get(1) 116 message := getMessage(ctx, 2) 117 118 if !common.IsHexAddress(addressStr) { 119 utils.Fatalf("Invalid address: %s", addressStr) 120 } 121 address, err := common.HexToAddress(addressStr) 122 if err != nil { 123 utils.Fatalf("invalid address %v, err: %v", addressStr, err) 124 } 125 signature, err := hex.DecodeString(signatureHex) 126 if err != nil { 127 utils.Fatalf("Signature encoding is not hexadecimal: %v", err) 128 } 129 130 recoveredPubkey, err := crypto.SigToPub(signHash(message), signature) 131 if err != nil || recoveredPubkey == nil { 132 utils.Fatalf("Signature verification failed: %v", err) 133 } 134 recoveredAddress := crypto.PubkeyToAddress(recoveredPubkey) 135 success := address == recoveredAddress 136 137 out := outputVerify{ 138 Success: success, 139 RecoveredPublicKey: hex.EncodeToString(recoveredPubkey[:]), 140 RecoveredAddress: recoveredAddress.Hex(), 141 } 142 if ctx.Bool(jsonFlag.Name) { 143 mustPrintJSON(out) 144 } else { 145 if out.Success { 146 fmt.Println("Signature verification successful!") 147 } else { 148 fmt.Println("Signature verification failed!") 149 } 150 fmt.Println("Recovered public key:", out.RecoveredPublicKey) 151 fmt.Println("Recovered address:", out.RecoveredAddress) 152 } 153 return nil 154 }, 155 } 156 157 func getMessage(ctx *cli.Context, msgarg int) []byte { 158 if file := ctx.String("msgfile"); file != "" { 159 if len(ctx.Args()) > msgarg { 160 utils.Fatalf("Can't use --msgfile and message argument at the same time.") 161 } 162 msg, err := ioutil.ReadFile(file) 163 if err != nil { 164 utils.Fatalf("Can't read message file: %v", err) 165 } 166 return msg 167 } else if len(ctx.Args()) == msgarg+1 { 168 return []byte(ctx.Args().Get(msgarg)) 169 } 170 utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, len(ctx.Args())) 171 return nil 172 }