forked from cosmos/cosmos-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
new.go
182 lines (158 loc) · 4.61 KB
/
new.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package keys
import (
"bufio"
"fmt"
"os"
"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)
*/
// nolint: gocyclo
func runNewCmd(cmd *cobra.Command, args []string) error {
name := args[0]
kb, err := GetKeyBase()
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.
// generate key and we're done.
if viper.GetBool(client.FlagUseLedger) {
algo := keys.Secp256k1 // SigningAlgo(viper.GetString(flagType))
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
}
// get the mnemonic
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")
}
}
}
// get the encryption password
printStep()
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 := bufio.NewReader(os.Stdin)
bip44Path := path
// if it wasnt set in the flag, give it a chance to overide interactively
if !flagSet {
printStep()
var err error
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("-------------------------------------")
}