client/keys: support export of unarmored private key (#8043)

The --unarmored-hex and --unsafe flags are added to
the keys export command. Users must use both to
export private keys material. The output would be in
hexadecimal format and unarmored.

See #8042 for scope and motivations.

introduce new UnsafeKeyring interface.

Unsafe operations are supported by UnsafeKeyring types.
By doing so, we try to make the client developer aware
of the risks.

Co-authored-by: Sunny Aggarwal <sunnya97@protonmail.ch>
This commit is contained in:
Alessio Treglia
2020-11-30 20:55:39 +00:00
committed by GitHub
co-authored by Sunny Aggarwal
parent 6476b09b64
commit 513dabaec8
4 changed files with 133 additions and 6 deletions
+38
View File
@@ -88,6 +88,13 @@ type Keyring interface {
Exporter
}
// UnsafeKeyring exposes unsafe operations such as unsafe unarmored export in
// addition to those that are made available by the Keyring interface.
type UnsafeKeyring interface {
Keyring
UnsafeExporter
}
// Signer is implemented by key stores that want to provide signing capabilities.
type Signer interface {
// Sign sign byte messages with a user key.
@@ -110,12 +117,20 @@ type Exporter interface {
// Export public key
ExportPubKeyArmor(uid string) (string, error)
ExportPubKeyArmorByAddress(address sdk.Address) (string, error)
// ExportPrivKey returns a private key in ASCII armored format.
// It returns an error if the key does not exist or a wrong encryption passphrase is supplied.
ExportPrivKeyArmor(uid, encryptPassphrase string) (armor string, err error)
ExportPrivKeyArmorByAddress(address sdk.Address, encryptPassphrase string) (armor string, err error)
}
// UnsafeExporter is implemented by key stores that support unsafe export
// of private keys' material.
type UnsafeExporter interface {
// UnsafeExportPrivKeyHex returns a private key in unarmored hex format
UnsafeExportPrivKeyHex(uid string) (string, error)
}
// Option overrides keyring configuration options.
type Option func(options *Options)
@@ -774,6 +789,29 @@ func (ks keystore) writeMultisigKey(name string, pub types.PubKey) (Info, error)
return info, nil
}
type unsafeKeystore struct {
keystore
}
// NewUnsafe returns a new keyring that provides support for unsafe operations.
func NewUnsafe(kr Keyring) UnsafeKeyring {
// The type assertion is against the only keystore
// implementation that is currently provided.
ks := kr.(keystore)
return unsafeKeystore{ks}
}
// UnsafeExportPrivKeyHex exports private keys in unarmored hexadecimal format.
func (ks unsafeKeystore) UnsafeExportPrivKeyHex(uid string) (privkey string, err error) {
priv, err := ks.ExportPrivateKeyObject(uid)
if err != nil {
return "", err
}
return hex.EncodeToString(priv.Bytes()), nil
}
func addrHexKeyAsString(address sdk.Address) string {
return fmt.Sprintf("%s.%s", hex.EncodeToString(address.Bytes()), addressSuffix)
}
+24
View File
@@ -1,6 +1,7 @@
package keyring
import (
"encoding/hex"
"fmt"
"strings"
"testing"
@@ -1092,6 +1093,29 @@ func TestAltKeyring_ImportExportPubKey_ByAddress(t *testing.T) {
require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID))
}
func TestAltKeyring_UnsafeExportPrivKeyHex(t *testing.T) {
keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil)
require.NoError(t, err)
uid := theID
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
require.NoError(t, err)
unsafeKeyring := NewUnsafe(keyring)
privKey, err := unsafeKeyring.UnsafeExportPrivKeyHex(uid)
require.NoError(t, err)
require.Equal(t, 64, len(privKey))
_, err = hex.DecodeString(privKey)
require.NoError(t, err)
// test error on non existing key
_, err = unsafeKeyring.UnsafeExportPrivKeyHex("non-existing")
require.Error(t, err)
}
func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) {
keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil)
require.NoError(t, err)