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

IRISHUB-693: Add key subcommand mnemonic and new #559

Merged
merged 1 commit into from
Nov 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/gov/lcd/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec)
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), queryVotesOnProposalHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes/{%s}", RestProposalID, RestVoter), queryVoteHandlerFn(cdc, cliCtx)).Methods("GET")


r.HandleFunc(fmt.Sprint("/gov/proposals/{%s}/tally_result",RestProposalID),queryTallyOnProposalHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc("/gov/params", queryParamsHandlerFn(cdc, cliCtx)).Methods("GET")
}
78 changes: 78 additions & 0 deletions client/keys/cli/mnemonic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package keys

import (
"crypto/sha256"
"fmt"

"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"

bip39 "github.com/bartekn/go-bip39"
)

const (
flagUserEntropy = "unsafe-entropy"

mnemonicEntropySize = 256
)

func mnemonicKeyCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "mnemonic",
Short: "Compute the bip39 mnemonic for some input entropy",
Long: "Create a bip39 mnemonic, sometimes called a seed phrase, by reading from the system entropy. To pass your own entropy, use --unsafe-entropy",
RunE: runMnemonicCmd,
}
cmd.Flags().Bool(flagUserEntropy, false, "Prompt the user to supply their own entropy, instead of relying on the system")
return cmd
}

func runMnemonicCmd(cmd *cobra.Command, args []string) error {
flags := cmd.Flags()

userEntropy, _ := flags.GetBool(flagUserEntropy)

var entropySeed []byte

if userEntropy {
// prompt the user to enter some entropy
buf := client.BufferStdin()
inputEntropy, err := client.GetString("> WARNING: Generate at least 256-bits of entropy and enter the results here:", buf)
if err != nil {
return err
}
if len(inputEntropy) < 43 {
return fmt.Errorf("256-bits is 43 characters in Base-64, and 100 in Base-6. You entered %v, and probably want more", len(inputEntropy))
}
conf, err := client.GetConfirmation(
fmt.Sprintf("> Input length: %d", len(inputEntropy)),
buf)
if err != nil {
return err
}
if !conf {
return nil
}

// hash input entropy to get entropy seed
hashedEntropy := sha256.Sum256([]byte(inputEntropy))
entropySeed = hashedEntropy[:]
printStep()
} else {
// read entropy seed straight from crypto.Rand
var err error
entropySeed, err = bip39.NewEntropy(mnemonicEntropySize)
if err != nil {
return err
}
}

mnemonic, err := bip39.NewMnemonic(entropySeed[:])
if err != nil {
return err
}

fmt.Println(mnemonic)

return nil
}
188 changes: 188 additions & 0 deletions client/keys/cli/new.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package keys

import (
"fmt"

"github.com/bartekn/go-bip39"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
)

const (
flagNewDefault = "default"
flagBIP44Path = "bip44-path"
)

func newKeyCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "new",
Short: "Interactive command to derive a new private key, encrypt it, and save to disk",
Long: `Derive a new private key using an interactive command that will prompt you for each input.
Optionally specify a bip39 mnemonic, a bip39 passphrase to further secure the mnemonic,
and a bip32 HD path to derive a specific account. The key will be stored under the given name
and encrypted with the given password. The only input that is required is the encryption password.`,
Args: cobra.ExactArgs(1),
RunE: runNewCmd,
}
cmd.Flags().Bool(flagNewDefault, false, "Skip the prompts and just use the default values for everything")
cmd.Flags().Bool(client.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device")
cmd.Flags().String(flagBIP44Path, "44'/118'/0'/0/0", "BIP44 path from which to derive a private key")
return cmd
}

/*
input
- bip39 mnemonic
- bip39 passphrase
- bip44 path
- local encryption password
output
- armor encrypted private key (saved to file)
*/
func runNewCmd(cmd *cobra.Command, args []string) error {
name := args[0]
kb, err := GetKeyBaseWithWritePerm()
if err != nil {
return err
}

buf := client.BufferStdin()

_, err = kb.Get(name)
if err == nil {
// account exists, ask for user confirmation
if response, err := client.GetConfirmation(
fmt.Sprintf("> override the existing name %s", name), buf); err != nil || !response {
return err
}
}

flags := cmd.Flags()
useDefaults, _ := flags.GetBool(flagNewDefault)
bipFlag := flags.Lookup(flagBIP44Path)

bip44Params, err := getBIP44ParamsAndPath(bipFlag.Value.String(), bipFlag.Changed || useDefaults)
if err != nil {
return err
}

// If we're using ledger, only thing we need is the path. So generate key and
// we're done.
if viper.GetBool(client.FlagUseLedger) {
algo := keys.Secp256k1
path := bip44Params.DerivationPath() // ccrypto.DerivationPath{44, 118, account, 0, index}

info, err := kb.CreateLedger(name, path, algo)
if err != nil {
return err
}

printCreate(info, "")
return nil
}

var mnemonic string

if !useDefaults {
mnemonic, err = client.GetString("Enter your bip39 mnemonic, or hit enter to generate one.", buf)
if err != nil {
return err
}
}

if len(mnemonic) == 0 {
// read entropy seed straight from crypto.Rand and convert to mnemonic
entropySeed, err := bip39.NewEntropy(mnemonicEntropySize)
if err != nil {
return err
}

mnemonic, err = bip39.NewMnemonic(entropySeed[:])
if err != nil {
return err
}
}

// get bip39 passphrase
var bip39Passphrase string
if !useDefaults {
printStep()
printPrefixed("Enter your bip39 passphrase. This is combined with the mnemonic to derive the seed")

bip39Passphrase, err = client.GetString("Most users should just hit enter to use the default, \"\"", buf)
if err != nil {
return err
}

// if they use one, make them re-enter it
if len(bip39Passphrase) != 0 {
p2, err := client.GetString("Repeat the passphrase:", buf)
if err != nil {
return err
}

if bip39Passphrase != p2 {
return errors.New("passphrases don't match")
}
}
}

printStep()

// get the encryption password
encryptPassword, err := client.GetCheckPassword(
"> Enter a passphrase to encrypt your key to disk:",
"> Repeat the passphrase:", buf)
if err != nil {
return err
}

info, err := kb.Derive(name, mnemonic, bip39Passphrase, encryptPassword, *bip44Params)
if err != nil {
return err
}

_ = info
return nil
}

func getBIP44ParamsAndPath(path string, flagSet bool) (*hd.BIP44Params, error) {
buf := client.BufferStdin()
bip44Path := path

// if it wasn't set in the flag, give it a chance to overide interactively
if !flagSet {
var err error

printStep()

bip44Path, err = client.GetString(fmt.Sprintf("Enter your bip44 path. Default is %s\n", path), buf)
if err != nil {
return nil, err
}

if len(bip44Path) == 0 {
bip44Path = path
}
}

bip44params, err := hd.NewParamsFromPath(bip44Path)
if err != nil {
return nil, err
}

return bip44params, nil
}

func printPrefixed(msg string) {
fmt.Printf("> %s\n", msg)
}

func printStep() {
printPrefixed("-------------------------------------")
}
2 changes: 2 additions & 0 deletions client/keys/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ func Commands() *cobra.Command {
needs to sign with a private key.`,
}
cmd.AddCommand(
mnemonicKeyCommand(),
newKeyCommand(),
addKeyCommand(),
listKeysCmd,
showKeysCmd,
Expand Down
Loading