Skip to content

Commit

Permalink
cmd/bnscli: use mnemonic to generate private key
Browse files Browse the repository at this point in the history
Instead of generating a random private key use algorithm described in
https://github.com/iov-one/iov-core/blob/master/docs/address-derivation-v1.md
to create a mnemonic and later use that mnemonic to create a private
key.

resolve #855

Tests are missing.
  • Loading branch information
husio committed Jul 29, 2019
1 parent d5aada8 commit b74eecc
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 7 deletions.
58 changes: 54 additions & 4 deletions cmd/bnscli/cmd_key.go
Original file line number Diff line number Diff line change
@@ -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.")
)
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), "")

key, err := derivation.DeriveForPath(*pathFl, seed)
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())
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
Original file line number Diff line number Diff line change
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")
1 change: 1 addition & 0 deletions cmd/bnscli/main.go
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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

0 comments on commit b74eecc

Please sign in to comment.