Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/bnscli: use mnemonic to generate private key #923

Merged
merged 9 commits into from Aug 1, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 54 additions & 4 deletions cmd/bnscli/cmd_key.go
@@ -1,21 +1,25 @@
package main

import (
"bytes"
"flag"
"fmt"
"io"
"io/ioutil"
"os"

"github.com/iov-one/weave/crypto"
"github.com/iov-one/weave/crypto/bech32"
"github.com/stellar/go/exp/crypto/derivation"
"github.com/tyler-smith/go-bip39"
"golang.org/x/crypto/ed25519"
)

func cmdKeygen(input io.Reader, output io.Writer, args []string) error {
fl := flag.NewFlagSet("", flag.ExitOnError)
fl.Usage = func() {
fmt.Fprint(flag.CommandLine.Output(), `
Generate a new private key.
Read mnemonic and generate a new private key.

When successful a new file with binary content containing private key is
created. This command fails if the private key file already exists.
Expand All @@ -25,6 +29,7 @@ created. This command fails if the private key file already exists.
var (
keyPathFl = fl.String("key", env("BNSCLI_PRIV_KEY", os.Getenv("HOME")+"/.bnsd.priv.key"),
"Path to the private key file that transaction should be signed with. You can use BNSCLI_PRIV_KEY environment variable to set it.")
pathFl = fl.String("path", "m/44'/234'/0'", "Derivation path as described in BIP-44.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pp: please add default path to the description so that it can be copied and modified knowing our exact format and numbers if required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default is always printed as part of the help message.

  -path string
        Derivation path as described in BIP-44. (default "m/44'/234'/0'")

)
fl.Parse(args)

Expand All @@ -35,9 +40,17 @@ created. This command fails if the private key file already exists.
return fmt.Errorf("private key file %q already exists, delete this file and try again", *keyPathFl)
}

_, priv, err := ed25519.GenerateKey(nil)
mnemonic, err := readInput(input)
if err != nil {
return fmt.Errorf("cannot generate ed25519 key: %s", err)
return fmt.Errorf("cannot read mnemonic: %s", err)
}

// We do not allow for passphrase.
seed := bip39.NewSeed(string(mnemonic), "")
husio marked this conversation as resolved.
Show resolved Hide resolved

key, err := derivation.DeriveForPath(*pathFl, seed)
husio marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return fmt.Errorf("cannot deriviate master key from seed: %s", err)
}

fd, err := os.OpenFile(*keyPathFl, os.O_CREATE|os.O_WRONLY, 0400)
Expand All @@ -46,6 +59,11 @@ created. This command fails if the private key file already exists.
}
defer fd.Close()

_, priv, err := ed25519.GenerateKey(bytes.NewReader(key.Key))
if err != nil {
return fmt.Errorf("cannot generate ed25519 private key: %s", err)
}

if _, err := fd.Write(priv); err != nil {
return fmt.Errorf("cannot write private key: %s", err)
}
Expand Down Expand Up @@ -83,6 +101,38 @@ Print out a hex-address associated with your private key.
Ed25519: raw,
},
}
_, err = fmt.Fprintln(output, key.PublicKey().Address())

bech, err := bech32.Encode("iov", key.PublicKey().GetEd25519())
webmaster128 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return fmt.Errorf("cannot generate bech32 address format: %s", err)
}

fmt.Fprintf(output, "bech32\t%s\n", bech)
fmt.Fprintf(output, "hex\t%s\n", key.PublicKey().Address())
return nil
}

func cmdMnemonic(input io.Reader, output io.Writer, args []string) error {
fl := flag.NewFlagSet("", flag.ExitOnError)
fl.Usage = func() {
fmt.Fprint(flag.CommandLine.Output(), `
Generate and print out a mnemonic.
`)
}
var (
bitSizeFl = fl.Uint("size", 256, "Bit size of the entropy. Must be between 128 and 256.")
)
fl.Parse(args)

entropy, err := bip39.NewEntropy(int(*bitSizeFl))
if err != nil {
return fmt.Errorf("cannot create entropy instance: %s", err)
}
mnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
return fmt.Errorf("cannot create mnemonic instance: %s", err)
}

_, err = fmt.Fprintln(output, mnemonic)
return err
}
20 changes: 20 additions & 0 deletions cmd/bnscli/common.go
Expand Up @@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strconv"
"strings"
Expand Down Expand Up @@ -182,3 +183,22 @@ func tendermintStore(nodeURL string) weave.ReadOnlyKVStore {
tm := rpcclient.NewHTTP(nodeURL, "/websocket")
return app.NewABCIStore(rpcQueryWrapper{tm})
}

// readInput returns all bytes waiting on given input. This function immediatly
// returns errNoPipe error if the input is not piped to avoid forever waiting.
func readInput(input io.Reader) ([]byte, error) {
// If the given reader is providing a stat information (ie os.Stdin)
// then check if the data is being piped. That should prevent us from
// waiting for a data on a reader that no one ever writes to.
if s, ok := input.(stater); ok {
if info, err := s.Stat(); err == nil {
isPipe := (info.Mode() & os.ModeCharDevice) == 0
if !isPipe {
return nil, errNoPipe
}
}
}
return ioutil.ReadAll(input)
}

var errNoPipe = errors.New("no data piped")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

req: Please move const and vars before the methods using them.

1 change: 1 addition & 0 deletions cmd/bnscli/main.go
Expand Up @@ -42,6 +42,7 @@ var commands = map[string]func(input io.Reader, output io.Writer, args []string)
"from-sequence": cmdFromSequence,
"keyaddr": cmdKeyaddr,
"keygen": cmdKeygen,
"mnemonic": cmdMnemonic,
"multisig": cmdMultisig,
"query": cmdQuery,
"register-username": cmdRegisterUsername,
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Expand Up @@ -17,12 +17,13 @@ require (
github.com/prometheus/client_golang v0.9.3 // indirect
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect
github.com/rs/cors v1.6.0 // indirect
github.com/stellar/go v0.0.0-20190524153138-e5e03dc34e2d
github.com/stellar/go v0.0.0-20190723221356-14eed5a46caf
github.com/stellar/go-xdr v0.0.0-20180917104419-0bc96f33a18e // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/tendermint/go-amino v0.15.0
github.com/tendermint/iavl v0.12.2
github.com/tendermint/tendermint v0.31.5
github.com/tyler-smith/go-bip39 v1.0.0
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f
google.golang.org/grpc v1.21.0 // indirect
)
6 changes: 4 additions & 2 deletions go.sum
Expand Up @@ -108,8 +108,8 @@ github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stellar/go v0.0.0-20190524153138-e5e03dc34e2d h1:qlw1pPjIH7Uo9t1BeP+/pHvqAxB0Yq22zLpWzY1Uu4I=
github.com/stellar/go v0.0.0-20190524153138-e5e03dc34e2d/go.mod h1:Kkro8X6IWn/5XtSicGd6N2LZKMKUCWS5wS5Ctjh6+Vw=
github.com/stellar/go v0.0.0-20190723221356-14eed5a46caf h1:gLIFkwCtIquj9iFCPy595EFSmgJbQIZMLAG6gFHcNrI=
github.com/stellar/go v0.0.0-20190723221356-14eed5a46caf/go.mod h1:Kkro8X6IWn/5XtSicGd6N2LZKMKUCWS5wS5Ctjh6+Vw=
github.com/stellar/go-xdr v0.0.0-20180917104419-0bc96f33a18e h1:n/hfey8pO+RYMoGXyvyzuw5pdO8IFDoyAL/g5OiCesY=
github.com/stellar/go-xdr v0.0.0-20180917104419-0bc96f33a18e/go.mod h1:gpOLVzy6TVYTQ3LvHSN9RJC700FkhFCpSE82u37aNRM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand All @@ -125,6 +125,8 @@ github.com/tendermint/iavl v0.12.2 h1:Ls5p5VINCM1HRT9g5Vvs2zmDOCU/CCIvIHzd/pZ8P0
github.com/tendermint/iavl v0.12.2/go.mod h1:EoKMMv++tDOL5qKKVnoIqtVPshRrEPeJ0WsgDOLAauM=
github.com/tendermint/tendermint v0.31.5 h1:vTet8tCq3B9/J9Yo11dNZ8pOB7NtSy++bVSfkP4KzR4=
github.com/tendermint/tendermint v0.31.5/go.mod h1:ymcPyWblXCplCPQjbOYbrF1fWnpslATMVqiGgWbZrlc=
github.com/tyler-smith/go-bip39 v1.0.0 h1:FOHg9gaQLeBBRbHE/QrTLfEiBHy5pQ/yXzf9JG5pYFM=
github.com/tyler-smith/go-bip39 v1.0.0/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
Expand Down