github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/cmd/burrow/commands/keys.go (about)

     1  package commands
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"net"
    10  	"os"
    11  	"time"
    12  
    13  	"github.com/hyperledger/burrow/encoding"
    14  
    15  	"github.com/howeyc/gopass"
    16  	"github.com/hyperledger/burrow/config"
    17  	"github.com/hyperledger/burrow/config/deployment"
    18  	"github.com/hyperledger/burrow/crypto"
    19  	"github.com/hyperledger/burrow/keys"
    20  	cli "github.com/jawher/mow.cli"
    21  )
    22  
    23  // Keys runs as either client or server
    24  func Keys(output Output) func(cmd *cli.Cmd) {
    25  	return func(cmd *cli.Cmd) {
    26  		keysHost := cmd.String(cli.StringOpt{
    27  			Name:   "host",
    28  			Desc:   "set the host for talking to the key daemon",
    29  			Value:  keys.DefaultHost,
    30  			EnvVar: "BURROW_KEYS_HOST",
    31  		})
    32  
    33  		keysPort := cmd.String(cli.StringOpt{
    34  			Name:   "port",
    35  			Desc:   "set the port for key daemon",
    36  			Value:  keys.DefaultPort,
    37  			EnvVar: "BURROW_KEYS_PORT",
    38  		})
    39  
    40  		grpcKeysClient := func(output Output) keys.KeysClient {
    41  			conn, err := encoding.GRPCDial(*keysHost + ":" + *keysPort)
    42  			if err != nil {
    43  				output.Fatalf("Failed to connect to grpc server: %v", err)
    44  			}
    45  			return keys.NewKeysClient(conn)
    46  		}
    47  
    48  		cmd.Command("server", "run keys server", func(cmd *cli.Cmd) {
    49  			keysDir := cmd.StringOpt("dir", "", "specify the location of the directory containing key files")
    50  			badPerm := cmd.BoolOpt("allow-bad-perm", false, "Allow unix key file permissions to be readable other than user")
    51  			configOpt := cmd.StringOpt("c config", "", "Use the specified burrow config file")
    52  
    53  			var conf *config.BurrowConfig
    54  
    55  			cmd.Before = func() {
    56  				var err error
    57  				conf, err = obtainDefaultConfig(*configOpt, "")
    58  				if err != nil {
    59  					output.Fatalf("Could not obtain config: %v", err)
    60  				}
    61  			}
    62  
    63  			cmd.Action = func() {
    64  				conf.Keys.AllowBadFilePermissions = *badPerm
    65  
    66  				if *keysDir != "" {
    67  					conf.Keys.KeysDirectory = *keysDir
    68  				}
    69  
    70  				server := keys.StandAloneServer(conf.Keys.KeysDirectory, conf.Keys.AllowBadFilePermissions)
    71  				address := fmt.Sprintf("%s:%s", *keysHost, *keysPort)
    72  				listener, err := net.Listen("tcp", address)
    73  				if err != nil {
    74  					output.Fatalf("Could not listen on %s: %v", address, err)
    75  				}
    76  				err = server.Serve(listener)
    77  				if err != nil {
    78  					output.Fatalf("Keys server terminated with error: %v", err)
    79  				}
    80  			}
    81  		})
    82  
    83  		cmd.Command("gen", "Generates a key using (insert crypto pkgs used)", func(cmd *cli.Cmd) {
    84  			noPassword := cmd.BoolOpt("n no-password", false, "don't use a password for this key")
    85  
    86  			keyType := cmd.StringOpt("t curvetype", "ed25519", "specify the curve type of key to create. Supports 'secp256k1' (ethereum),  'ed25519' (tendermint)")
    87  
    88  			keyName := cmd.StringOpt("name", "", "name of key to use")
    89  
    90  			cmd.Action = func() {
    91  				curve, err := crypto.CurveTypeFromString(*keyType)
    92  				if err != nil {
    93  					output.Fatalf("Unrecognised curve type %v", *keyType)
    94  				}
    95  
    96  				var password string
    97  				if !*noPassword {
    98  					fmt.Printf("Enter Password:")
    99  					pwd, err := gopass.GetPasswdMasked()
   100  					if err != nil {
   101  						os.Exit(1)
   102  					}
   103  					password = string(pwd)
   104  				}
   105  
   106  				c := grpcKeysClient(output)
   107  				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   108  				defer cancel()
   109  				resp, err := c.GenerateKey(ctx, &keys.GenRequest{Passphrase: password, CurveType: curve.String(), KeyName: *keyName})
   110  				if err != nil {
   111  					output.Fatalf("failed to generate key: %v", err)
   112  				}
   113  
   114  				fmt.Printf("%v\n", resp.GetAddress())
   115  			}
   116  		})
   117  
   118  		cmd.Command("hash", "hash <some data>", func(cmd *cli.Cmd) {
   119  			hashType := cmd.StringOpt("t type", keys.DefaultHashType, "specify the hash function to use")
   120  
   121  			hexByte := cmd.BoolOpt("hex", false, "the input should be hex decoded to bytes first")
   122  
   123  			msg := cmd.StringArg("MSG", "", "message to hash")
   124  
   125  			cmd.Action = func() {
   126  				var message []byte
   127  				var err error
   128  				if *hexByte {
   129  					message, err = hex.DecodeString(*msg)
   130  					if err != nil {
   131  						output.Fatalf("failed to hex decode message: %v", err)
   132  					}
   133  				} else {
   134  					message = []byte(*msg)
   135  				}
   136  
   137  				c := grpcKeysClient(output)
   138  				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   139  				defer cancel()
   140  				resp, err := c.Hash(ctx, &keys.HashRequest{Hashtype: *hashType, Message: message})
   141  				if err != nil {
   142  					output.Fatalf("failed to get public key: %v", err)
   143  				}
   144  
   145  				fmt.Printf("%v\n", resp.GetHash())
   146  			}
   147  		})
   148  
   149  		cmd.Command("export", "Export a key to tendermint format", func(cmd *cli.Cmd) {
   150  			keyName := cmd.StringOpt("name", "", "name of key to use")
   151  			keyAddr := cmd.StringOpt("addr", "", "address of key to use")
   152  			passphrase := cmd.StringOpt("passphrase", "", "passphrase for encrypted key")
   153  			keyTemplate := cmd.StringOpt("t template", deployment.DefaultKeysExportFormat, "template for export key")
   154  
   155  			cmd.Action = func() {
   156  				c := grpcKeysClient(output)
   157  				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   158  				defer cancel()
   159  				resp, err := c.Export(ctx, &keys.ExportRequest{Passphrase: *passphrase, Name: *keyName, Address: *keyAddr})
   160  				if err != nil {
   161  					output.Fatalf("failed to export key: %v", err)
   162  				}
   163  
   164  				addr, err := crypto.AddressFromBytes(resp.GetAddress())
   165  				if err != nil {
   166  					output.Fatalf("failed to convert address: %v", err)
   167  				}
   168  
   169  				key := deployment.Key{
   170  					Name:       *keyName,
   171  					CurveType:  resp.GetCurveType(),
   172  					Address:    addr,
   173  					PublicKey:  resp.GetPublickey(),
   174  					PrivateKey: resp.GetPrivatekey(),
   175  				}
   176  
   177  				str, err := key.Dump(*keyTemplate)
   178  				if err != nil {
   179  					output.Fatalf("failed to template key: %v", err)
   180  				}
   181  
   182  				fmt.Printf("%s\n", str)
   183  			}
   184  		})
   185  
   186  		cmd.Command("import", "import <priv key> | /path/to/keyfile | <key json>", func(cmd *cli.Cmd) {
   187  			curveType := cmd.StringOpt("t curvetype", "ed25519", "specify the curve type of key to create. Supports 'secp256k1' (ethereum),  'ed25519' (tendermint)")
   188  			noPassword := cmd.BoolOpt("n no-password", false, "don't use a password for this key")
   189  			key := cmd.StringArg("KEY", "", "private key, filename, or raw json")
   190  
   191  			cmd.Action = func() {
   192  				var password string
   193  				if !*noPassword {
   194  					fmt.Printf("Enter Password:")
   195  					pwd, err := gopass.GetPasswdMasked()
   196  					if err != nil {
   197  						os.Exit(1)
   198  					}
   199  					password = string(pwd)
   200  				}
   201  
   202  				var privKeyBytes []byte
   203  				fileContents, err := ioutil.ReadFile(*key)
   204  				if err == nil {
   205  					*key = string(fileContents)
   206  				}
   207  
   208  				c := grpcKeysClient(output)
   209  				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   210  				defer cancel()
   211  
   212  				if (*key)[:1] == "{" {
   213  					resp, err := c.ImportJSON(ctx, &keys.ImportJSONRequest{JSON: *key})
   214  					if err != nil {
   215  						output.Fatalf("failed to import json key: %v", err)
   216  					}
   217  
   218  					fmt.Printf("%s\n", resp.GetAddress())
   219  				} else {
   220  					privKeyBytes, err = hex.DecodeString(*key)
   221  					if err != nil {
   222  						output.Fatalf("failed to hex decode key: %s", *key)
   223  					}
   224  					resp, err := c.Import(ctx, &keys.ImportRequest{Passphrase: password, KeyBytes: privKeyBytes, CurveType: *curveType})
   225  					if err != nil {
   226  						output.Fatalf("failed to import json key: %v", err)
   227  					}
   228  
   229  					fmt.Printf("%s\n", resp.GetAddress())
   230  
   231  				}
   232  			}
   233  		})
   234  
   235  		cmd.Command("pub", "public key", func(cmd *cli.Cmd) {
   236  			name := cmd.StringOpt("name", "", "name of key to use")
   237  			addr := cmd.StringOpt("addr", "", "address of key to use")
   238  
   239  			cmd.Action = func() {
   240  				c := grpcKeysClient(output)
   241  				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   242  				defer cancel()
   243  				resp, err := c.PublicKey(ctx, &keys.PubRequest{Name: *name, Address: *addr})
   244  				if err != nil {
   245  					output.Fatalf("failed to get public key: %v", err)
   246  				}
   247  
   248  				fmt.Printf("%X\n", resp.GetPublicKey())
   249  			}
   250  		})
   251  
   252  		cmd.Command("sign", "sign <some data>", func(cmd *cli.Cmd) {
   253  			name := cmd.StringOpt("name", "", "name of key to use")
   254  			addr := cmd.StringOpt("addr", "", "address of key to use")
   255  			msg := cmd.StringArg("MSG", "", "message to sign")
   256  			passphrase := cmd.StringOpt("passphrase", "", "passphrase for encrypted key")
   257  
   258  			cmd.Action = func() {
   259  				message, err := hex.DecodeString(*msg)
   260  				if err != nil {
   261  					output.Fatalf("failed to hex decode message: %v", err)
   262  				}
   263  
   264  				c := grpcKeysClient(output)
   265  				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   266  				defer cancel()
   267  				resp, err := c.Sign(ctx, &keys.SignRequest{Passphrase: *passphrase, Name: *name, Address: *addr, Message: message})
   268  				if err != nil {
   269  					output.Fatalf("failed to get public key: %v", err)
   270  				}
   271  				fmt.Printf("%X\n", resp.GetSignature().Signature)
   272  			}
   273  		})
   274  
   275  		cmd.Command("verify", "verify <some data> <sig> <pubkey>", func(cmd *cli.Cmd) {
   276  			curveTypeOpt := cmd.StringOpt("t curvetype", "ed25519", "specify the curve type of key to create. Supports 'secp256k1' (ethereum),  'ed25519' (tendermint)")
   277  
   278  			msg := cmd.StringArg("MSG", "", "hash/message to check")
   279  			sig := cmd.StringArg("SIG", "", "signature")
   280  			pub := cmd.StringArg("PUBLIC", "", "public key")
   281  
   282  			cmd.Action = func() {
   283  				message, err := hex.DecodeString(*msg)
   284  				if err != nil {
   285  					output.Fatalf("failed to hex decode message: %v", err)
   286  				}
   287  				curveType, err := crypto.CurveTypeFromString(*curveTypeOpt)
   288  				if err != nil {
   289  					output.Fatalf("invalid curve type: %v", err)
   290  				}
   291  
   292  				signatureBytes, err := hex.DecodeString(*sig)
   293  				if err != nil {
   294  					output.Fatalf("failed to hex decode signature: %v", err)
   295  				}
   296  
   297  				signature, err := crypto.SignatureFromBytes(signatureBytes, curveType)
   298  				if err != nil {
   299  					output.Fatalf("could not form signature: %v", err)
   300  				}
   301  
   302  				publickey, err := hex.DecodeString(*pub)
   303  				if err != nil {
   304  					output.Fatalf("failed to hex decode publickey: %v", err)
   305  				}
   306  
   307  				c := grpcKeysClient(output)
   308  				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   309  				defer cancel()
   310  				_, err = c.Verify(ctx, &keys.VerifyRequest{
   311  					PublicKey: publickey,
   312  					Signature: signature,
   313  					Message:   message,
   314  				})
   315  				if err != nil {
   316  					output.Fatalf("failed to verify: %v", err)
   317  				}
   318  				output.Printf("true\n")
   319  			}
   320  		})
   321  
   322  		cmd.Command("name", "add key name to addr", func(cmd *cli.Cmd) {
   323  			keyname := cmd.StringArg("NAME", "", "name of key to use")
   324  			addr := cmd.StringArg("ADDR", "", "address of key to use")
   325  
   326  			cmd.Action = func() {
   327  				c := grpcKeysClient(output)
   328  				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   329  				defer cancel()
   330  				_, err := c.AddName(ctx, &keys.AddNameRequest{Keyname: *keyname, Address: *addr})
   331  				if err != nil {
   332  					output.Fatalf("failed to add name to addr: %v", err)
   333  				}
   334  			}
   335  		})
   336  
   337  		cmd.Command("list", "list keys", func(cmd *cli.Cmd) {
   338  			name := cmd.StringOpt("name", "", "name or address of key to use")
   339  
   340  			cmd.Action = func() {
   341  				c := grpcKeysClient(output)
   342  				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   343  				defer cancel()
   344  				resp, err := c.List(ctx, &keys.ListRequest{KeyName: *name})
   345  				if err != nil {
   346  					output.Fatalf("failed to list key: %v", err)
   347  				}
   348  				printKeys := resp.Key
   349  				if printKeys == nil {
   350  					printKeys = make([]*keys.KeyID, 0)
   351  				}
   352  				bs, err := json.MarshalIndent(printKeys, "", "    ")
   353  				if err != nil {
   354  					output.Fatalf("failed to json encode keys: %v", err)
   355  				}
   356  				fmt.Printf("%s\n", string(bs))
   357  			}
   358  		})
   359  
   360  		cmd.Command("rm", "rm key name", func(cmd *cli.Cmd) {
   361  			name := cmd.StringArg("NAME", "", "key to remove")
   362  
   363  			cmd.Action = func() {
   364  				c := grpcKeysClient(output)
   365  				ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   366  				defer cancel()
   367  				_, err := c.RemoveName(ctx, &keys.RemoveNameRequest{KeyName: *name})
   368  				if err != nil {
   369  					output.Fatalf("failed to remove key: %v", err)
   370  				}
   371  			}
   372  		})
   373  	}
   374  }