/
import_export.go
198 lines (173 loc) · 6.67 KB
/
import_export.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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package keys
import (
"bufio"
"bytes"
"encoding/hex"
"fmt"
"os"
"strings"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/input"
"github.com/cosmos/cosmos-sdk/crypto"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/ethereum/go-ethereum/accounts/keystore"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
hd2 "github.com/evmos/ethermint/crypto/hd"
"github.com/spf13/cobra"
)
const (
flagUnarmoredHex = "unarmored-hex"
flagUnsafe = "unsafe"
flagASCIIArmored = "ascii-armor"
)
// ExportKeyCommand exports private keys from the key store.
func ExportKeyCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "export <name>",
Short: "Export private keys",
Long: `Export a private key from the local keyring in encrypted format.
When both the --unarmored-hex and --unsafe flags are selected, cryptographic
private key material is exported in an INSECURE fashion that is designed to
allow users to import their keys in hot wallets. This feature is for advanced
users only that are confident about how to handle private keys work and are
FULLY AWARE OF THE RISKS. If you are unsure, you may want to do some research
and export your keys in encrypted format.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
buf := bufio.NewReader(clientCtx.Input)
unarmored, _ := cmd.Flags().GetBool(flagUnarmoredHex)
unsafe, _ := cmd.Flags().GetBool(flagUnsafe)
if unarmored && unsafe {
return exportUnsafeUnarmored(cmd, args[0], buf, clientCtx.Keyring)
} else if unarmored || unsafe {
return fmt.Errorf("the flags %s and %s must be used together", flagUnsafe, flagUnarmoredHex)
}
encryptPassword, err := input.GetPassword("Enter passphrase to encrypt the exported key:", buf)
if err != nil {
return err
}
asciiArmored, _ := cmd.Flags().GetBool(flagASCIIArmored)
if asciiArmored {
armored, err := clientCtx.Keyring.ExportPrivKeyArmor(args[0], encryptPassword)
if err != nil {
return err
}
cmd.Println(armored)
return nil
}
privKey, err := clientCtx.Keyring.(unsafeExporter).ExportPrivateKeyObject(args[0])
if err != nil {
return err
}
hexPrivKey := hex.EncodeToString(privKey.Bytes())
if err != nil {
return err
}
priv, err := ethcrypto.HexToECDSA(hexPrivKey)
if err != nil {
return err
}
key := &keystore.Key{
PrivateKey: priv,
Address: ethcrypto.PubkeyToAddress(priv.PublicKey),
}
keyjson, err := keystore.EncryptKey(key, encryptPassword, keystore.StandardScryptN, keystore.StandardScryptP)
if err != nil {
return err
}
cmd.Println(string(keyjson))
return nil
},
}
cmd.Flags().Bool(flagUnarmoredHex, false, "Export unarmored hex privkey. Requires --unsafe.")
cmd.Flags().Bool(flagUnsafe, false, "Enable unsafe operations. This flag must be switched on along with all unsafe operation-specific options.")
cmd.Flags().Bool(flagASCIIArmored, false, "Enable ASCII-armored encrypted format")
return cmd
}
func exportUnsafeUnarmored(cmd *cobra.Command, uid string, buf *bufio.Reader, kr keyring.Keyring) error {
// confirm deletion, unless -y is passed
if yes, err := input.GetConfirmation("WARNING: The private key will be exported as an unarmored hexadecimal string. USE AT YOUR OWN RISK. Continue?", buf, cmd.ErrOrStderr()); err != nil {
return err
} else if !yes {
return nil
}
priv, err := kr.(unsafeExporter).ExportPrivateKeyObject(uid)
if err != nil {
return err
}
hexPrivKey := hex.EncodeToString(priv.Bytes())
cmd.Print(hexPrivKey)
return nil
}
func ImportKeyCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "import <name> <keyfile>",
Short: "Import private keys into the local keybase",
Long: "Import a ASCII armored or ethereum keystore or unencrypted private key into the local keybase.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
buf := bufio.NewReader(clientCtx.Input)
bz, err := os.ReadFile(args[1])
if err != nil {
return err
}
// os.ReadFile read all data, contains line break at the end of a file
bz = bytes.TrimPrefix(bytes.TrimSuffix(bz, []byte{'\n'}), []byte("0x"))
if len(bz) == 64 {
priv, err := ethcrypto.HexToECDSA(string(bz))
if err != nil {
return err
}
algoStr, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm)
var armoPrivKey string
if hd.PubKeyType(algoStr) == hd.Secp256k1Type {
armoPrivKey = crypto.EncryptArmorPrivKey(&secp256k1.PrivKey{Key: ethcrypto.FromECDSA(priv)}, "", string(hd.Secp256k1Type))
} else if hd.PubKeyType(algoStr) == hd2.EthSecp256k1Type {
armoPrivKey = crypto.EncryptArmorPrivKey(ðsecp256k1.PrivKey{Key: ethcrypto.FromECDSA(priv)}, "", string(hd2.EthSecp256k1Type))
} else {
return fmt.Errorf("provided algorithm %q is not supported", algoStr)
}
return clientCtx.Keyring.ImportPrivKey(args[0], armoPrivKey, "")
}
passphrase, err := input.GetPassword("Enter passphrase to decrypt your key:", buf)
if err != nil && !strings.Contains(err.Error(), "password must be at least") {
return err
}
key, err := keystore.DecryptKey(bz, passphrase)
if err == nil {
algoStr, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm)
var armoPrivKey string
if hd.PubKeyType(algoStr) == hd.Secp256k1Type {
armoPrivKey = crypto.EncryptArmorPrivKey(&secp256k1.PrivKey{Key: ethcrypto.FromECDSA(key.PrivateKey)}, "", string(hd.Secp256k1Type))
} else if hd.PubKeyType(algoStr) == hd2.EthSecp256k1Type {
armoPrivKey = crypto.EncryptArmorPrivKey(ðsecp256k1.PrivKey{Key: ethcrypto.FromECDSA(key.PrivateKey)}, "", string(hd2.EthSecp256k1Type))
} else {
return fmt.Errorf("provided algorithm %q is not supported", algoStr)
}
return clientCtx.Keyring.ImportPrivKey(args[0], armoPrivKey, "")
}
return clientCtx.Keyring.ImportPrivKey(args[0], string(bz), passphrase)
},
}
cmd.Flags().String(flags.FlagKeyAlgorithm, ethsecp256k1.KeyType, "Key signing algorithm to generate keys for")
return cmd
}
// unsafeExporter is implemented by key stores that support unsafe export
// of private keys' material.
type unsafeExporter interface {
// ExportPrivateKeyObject returns a private key in unarmored format.
ExportPrivateKeyObject(uid string) (cryptotypes.PrivKey, error)
}