| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | // Copyright 2017 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of go-ethereum. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/hex" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/accounts/keystore" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/cmd/utils" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							|  |  |  | 	"gopkg.in/urfave/cli.v1" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type outputSign struct { | 
					
						
							|  |  |  | 	Signature string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | var msgfileFlag = cli.StringFlag{ | 
					
						
							|  |  |  | 	Name:  "msgfile", | 
					
						
							|  |  |  | 	Usage: "file containing the message to sign/verify", | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | var commandSignMessage = cli.Command{ | 
					
						
							|  |  |  | 	Name:      "signmessage", | 
					
						
							|  |  |  | 	Usage:     "sign a message", | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 	ArgsUsage: "<keyfile> <message>", | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 	Description: ` | 
					
						
							|  |  |  | Sign the message with a keyfile. | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | To sign a message contained in a file, use the --msgfile flag. | 
					
						
							|  |  |  | `, | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 	Flags: []cli.Flag{ | 
					
						
							|  |  |  | 		passphraseFlag, | 
					
						
							|  |  |  | 		jsonFlag, | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 		msgfileFlag, | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	Action: func(ctx *cli.Context) error { | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 		message := getMessage(ctx, 1) | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Load the keyfile. | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 		keyfilepath := ctx.Args().First() | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 		keyjson, err := ioutil.ReadFile(keyfilepath) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 			utils.Fatalf("Failed to read the keyfile at '%s': %v", keyfilepath, err) | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Decrypt key with passphrase. | 
					
						
							| 
									
										
										
										
											2018-06-08 15:07:07 +02:00
										 |  |  | 		passphrase := getPassphrase(ctx) | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 		key, err := keystore.DecryptKey(keyjson, passphrase) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("Error decrypting key: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		signature, err := crypto.Sign(signHash(message), key.PrivateKey) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("Failed to sign message: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 		out := outputSign{Signature: hex.EncodeToString(signature)} | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 		if ctx.Bool(jsonFlag.Name) { | 
					
						
							|  |  |  | 			mustPrintJSON(out) | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 			fmt.Println("Signature:", out.Signature) | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type outputVerify struct { | 
					
						
							|  |  |  | 	Success            bool | 
					
						
							|  |  |  | 	RecoveredAddress   string | 
					
						
							|  |  |  | 	RecoveredPublicKey string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var commandVerifyMessage = cli.Command{ | 
					
						
							|  |  |  | 	Name:      "verifymessage", | 
					
						
							|  |  |  | 	Usage:     "verify the signature of a signed message", | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 	ArgsUsage: "<address> <signature> <message>", | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 	Description: ` | 
					
						
							|  |  |  | Verify the signature of the message. | 
					
						
							|  |  |  | It is possible to refer to a file containing the message.`, | 
					
						
							|  |  |  | 	Flags: []cli.Flag{ | 
					
						
							|  |  |  | 		jsonFlag, | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 		msgfileFlag, | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	Action: func(ctx *cli.Context) error { | 
					
						
							|  |  |  | 		addressStr := ctx.Args().First() | 
					
						
							|  |  |  | 		signatureHex := ctx.Args().Get(1) | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 		message := getMessage(ctx, 2) | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if !common.IsHexAddress(addressStr) { | 
					
						
							|  |  |  | 			utils.Fatalf("Invalid address: %s", addressStr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		address := common.HexToAddress(addressStr) | 
					
						
							|  |  |  | 		signature, err := hex.DecodeString(signatureHex) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("Signature encoding is not hexadecimal: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		recoveredPubkey, err := crypto.SigToPub(signHash(message), signature) | 
					
						
							|  |  |  | 		if err != nil || recoveredPubkey == nil { | 
					
						
							|  |  |  | 			utils.Fatalf("Signature verification failed: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		recoveredPubkeyBytes := crypto.FromECDSAPub(recoveredPubkey) | 
					
						
							|  |  |  | 		recoveredAddress := crypto.PubkeyToAddress(*recoveredPubkey) | 
					
						
							|  |  |  | 		success := address == recoveredAddress | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		out := outputVerify{ | 
					
						
							|  |  |  | 			Success:            success, | 
					
						
							|  |  |  | 			RecoveredPublicKey: hex.EncodeToString(recoveredPubkeyBytes), | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 			RecoveredAddress:   recoveredAddress.Hex(), | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if ctx.Bool(jsonFlag.Name) { | 
					
						
							|  |  |  | 			mustPrintJSON(out) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if out.Success { | 
					
						
							|  |  |  | 				fmt.Println("Signature verification successful!") | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				fmt.Println("Signature verification failed!") | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 			fmt.Println("Recovered public key:", out.RecoveredPublicKey) | 
					
						
							|  |  |  | 			fmt.Println("Recovered address:", out.RecoveredAddress) | 
					
						
							| 
									
										
										
										
											2017-12-21 11:36:05 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-16 15:42:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func getMessage(ctx *cli.Context, msgarg int) []byte { | 
					
						
							|  |  |  | 	if file := ctx.String("msgfile"); file != "" { | 
					
						
							|  |  |  | 		if len(ctx.Args()) > msgarg { | 
					
						
							|  |  |  | 			utils.Fatalf("Can't use --msgfile and message argument at the same time.") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		msg, err := ioutil.ReadFile(file) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("Can't read message file: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return msg | 
					
						
							|  |  |  | 	} else if len(ctx.Args()) == msgarg+1 { | 
					
						
							|  |  |  | 		return []byte(ctx.Args().Get(msgarg)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, len(ctx.Args())) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |