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 }