Merge branch 'master' into jonathan/4875-gov-use-simapp
This commit is contained in:
commit
c0fd5cbda0
|
@ -61,6 +61,7 @@ and provided directly the IAVL store.
|
||||||
* (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`.
|
* (modules) [\#5572](https://github.com/cosmos/cosmos-sdk/pull/5572) Move account balance logic and APIs from `x/auth` to `x/bank`.
|
||||||
* (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis`
|
* (types) [\#5533](https://github.com/cosmos/cosmos-sdk/pull/5533) Refactored `AppModuleBasic` and `AppModuleGenesis`
|
||||||
to now accept a `codec.JSONMarshaler` for modular serialization of genesis state.
|
to now accept a `codec.JSONMarshaler` for modular serialization of genesis state.
|
||||||
|
* (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's Update() function is now no-op.
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return crypto.LedgerShowAddress(*hdpath, info.GetPubKey())
|
return crypto.LedgerShowAddress(*hdpath, info.GetPubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -212,7 +212,7 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t
|
||||||
}
|
}
|
||||||
|
|
||||||
case ledgerInfo:
|
case ledgerInfo:
|
||||||
return kb.base.SignWithLedger(info, msg)
|
return SignWithLedger(info, msg)
|
||||||
|
|
||||||
case offlineInfo, multiInfo:
|
case offlineInfo, multiInfo:
|
||||||
return kb.base.DecodeSignature(info, msg)
|
return kb.base.DecodeSignature(info, msg)
|
||||||
|
|
|
@ -104,24 +104,6 @@ func SecpPrivKeyGen(bz []byte) tmcrypto.PrivKey {
|
||||||
return secp256k1.PrivKeySecp256k1(bzArr)
|
return secp256k1.PrivKeySecp256k1(bzArr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignWithLedger signs a binary message with the ledger device referenced by an Info object
|
|
||||||
// and returns the signed bytes and the public key. It returns an error if the device could
|
|
||||||
// not be queried or it returned an error.
|
|
||||||
func (kb baseKeybase) SignWithLedger(info Info, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) {
|
|
||||||
i := info.(ledgerInfo)
|
|
||||||
priv, err := crypto.NewPrivKeyLedgerSecp256k1Unsafe(i.Path)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sig, err = priv.Sign(msg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sig, priv.PubKey(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeSignature decodes a an length-prefixed binary signature from standard input
|
// DecodeSignature decodes a an length-prefixed binary signature from standard input
|
||||||
// and return it as a byte slice.
|
// and return it as a byte slice.
|
||||||
func (kb baseKeybase) DecodeSignature(info Info, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) {
|
func (kb baseKeybase) DecodeSignature(info Info, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) {
|
||||||
|
@ -296,3 +278,30 @@ func IsSupportedAlgorithm(supported []SigningAlgo, algo SigningAlgo) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignWithLedger signs a binary message with the ledger device referenced by an Info object
|
||||||
|
// and returns the signed bytes and the public key. It returns an error if the device could
|
||||||
|
// not be queried or it returned an error.
|
||||||
|
func SignWithLedger(info Info, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) {
|
||||||
|
switch info.(type) {
|
||||||
|
case *ledgerInfo, ledgerInfo:
|
||||||
|
default:
|
||||||
|
return nil, nil, errors.New("not a ledger object")
|
||||||
|
}
|
||||||
|
path, err := info.GetPath()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
priv, err := crypto.NewPrivKeyLedgerSecp256k1Unsafe(*path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err = priv.Sign(msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sig, priv.PubKey(), nil
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
package keys
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -278,7 +280,7 @@ func TestSignVerify(t *testing.T) {
|
||||||
|
|
||||||
// Now try to sign data with a secret-less key
|
// Now try to sign data with a secret-less key
|
||||||
_, _, err = cstore.Sign(n3, p3, d3)
|
_, _, err = cstore.Sign(n3, p3, d3)
|
||||||
require.NotNil(t, err)
|
require.True(t, errors.Is(io.EOF, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertPassword(t *testing.T, cstore Keybase, name, pass, badpass string) {
|
func assertPassword(t *testing.T, cstore Keybase, name, pass, badpass string) {
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package keyerror_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestErrors(t *testing.T) {
|
||||||
|
err := keyerror.NewErrKeyNotFound("test")
|
||||||
|
require.True(t, keyerror.IsErrKeyNotFound(err))
|
||||||
|
require.Equal(t, "Key test not found", err.Error())
|
||||||
|
require.False(t, keyerror.IsErrKeyNotFound(errors.New("test")))
|
||||||
|
require.False(t, keyerror.IsErrKeyNotFound(nil))
|
||||||
|
|
||||||
|
err = keyerror.NewErrWrongPassword()
|
||||||
|
require.True(t, keyerror.IsErrWrongPassword(err))
|
||||||
|
require.Equal(t, "invalid account password", err.Error())
|
||||||
|
require.False(t, keyerror.IsErrWrongPassword(errors.New("test")))
|
||||||
|
require.False(t, keyerror.IsErrWrongPassword(nil))
|
||||||
|
}
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -218,7 +217,7 @@ func (kb keyringKeybase) Sign(name, passphrase string, msg []byte) (sig []byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
case ledgerInfo:
|
case ledgerInfo:
|
||||||
return kb.base.SignWithLedger(info, msg)
|
return SignWithLedger(info, msg)
|
||||||
|
|
||||||
case offlineInfo, multiInfo:
|
case offlineInfo, multiInfo:
|
||||||
return kb.base.DecodeSignature(info, msg)
|
return kb.base.DecodeSignature(info, msg)
|
||||||
|
@ -419,29 +418,7 @@ func (kb keyringKeybase) Delete(name, _ string, _ bool) error {
|
||||||
// The oldpass must be the current passphrase used for encryption, getNewpass is
|
// The oldpass must be the current passphrase used for encryption, getNewpass is
|
||||||
// a function to get the passphrase to permanently replace the current passphrase.
|
// a function to get the passphrase to permanently replace the current passphrase.
|
||||||
func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error {
|
func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error {
|
||||||
info, err := kb.Get(name)
|
return errors.New("unsupported operation")
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch linfo := info.(type) {
|
|
||||||
case localInfo:
|
|
||||||
key, _, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newpass, err := getNewpass()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
kb.writeLocalKey(name, key, newpass, linfo.GetAlgo())
|
|
||||||
return nil
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("locally stored key required; received: %v", reflect.TypeOf(info).String())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SupportedAlgos returns a list of supported signing algorithms.
|
// SupportedAlgos returns a list of supported signing algorithms.
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
package keys
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -94,8 +95,46 @@ func TestLazyKeyManagementKeyRing(t *testing.T) {
|
||||||
require.Equal(t, 1, len(keyS))
|
require.Equal(t, 1, len(keyS))
|
||||||
|
|
||||||
// addr cache gets nuked - and test skip flag
|
// addr cache gets nuked - and test skip flag
|
||||||
err = kb.Delete(n2, "", true)
|
require.NoError(t, kb.Delete(n2, "", true))
|
||||||
|
|
||||||
|
require.NotPanics(t, kb.CloseDB)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSignVerify does some detailed checks on how we sign and validate
|
||||||
|
// signatures
|
||||||
|
func TestLazySignVerifyKeyRingWithLedger(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
kb, err := NewKeyring("keybasename", "test", dir, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
i1, err := kb.CreateLedger("key", Secp256k1, "cosmos", 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error())
|
||||||
|
t.Skip("ledger nano S: support for ledger devices is not available in this executable")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.Equal(t, "key", i1.GetName())
|
||||||
|
|
||||||
|
p1 := "1234"
|
||||||
|
d1 := []byte("my first message")
|
||||||
|
s1, pub1, err := kb.Sign("key", p1, d1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
s2, pub2, err := SignWithLedger(i1, d1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, i1.GetPubKey(), pub1)
|
||||||
|
require.Equal(t, i1.GetPubKey(), pub2)
|
||||||
|
require.True(t, pub1.VerifyBytes(d1, s1))
|
||||||
|
require.True(t, i1.GetPubKey().VerifyBytes(d1, s1))
|
||||||
|
require.True(t, bytes.Equal(s1, s2))
|
||||||
|
|
||||||
|
localInfo, _, err := kb.CreateMnemonic("test", English, p1, Secp256k1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, _, err = SignWithLedger(localInfo, d1)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Equal(t, "not a ledger object", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLazySignVerifyKeyRing(t *testing.T) {
|
func TestLazySignVerifyKeyRing(t *testing.T) {
|
||||||
|
@ -325,3 +364,50 @@ func TestLazySeedPhraseKeyRing(t *testing.T) {
|
||||||
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
||||||
require.Equal(t, info.GetPubKey(), newInfo.GetPubKey())
|
require.Equal(t, info.GetPubKey(), newInfo.GetPubKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKeyringKeybaseExportImportPrivKey(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
kb, err := NewKeyring("keybasename", "test", dir, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, _, err = kb.CreateMnemonic("john", English, "password", Secp256k1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// no error, password is irrelevant, keystr cointains ASCII armored private key
|
||||||
|
keystr, err := kb.ExportPrivKey("john", "wrongpassword", "password")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, keystr)
|
||||||
|
|
||||||
|
// try import the key - wrong password
|
||||||
|
err = kb.ImportPrivKey("john2", keystr, "somepassword")
|
||||||
|
require.Equal(t, "failed to decrypt private key: ciphertext decryption failed", err.Error())
|
||||||
|
|
||||||
|
// try import the key with the correct password
|
||||||
|
require.NoError(t, kb.ImportPrivKey("john2", keystr, "password"))
|
||||||
|
|
||||||
|
// overwrite is not allowed
|
||||||
|
err = kb.ImportPrivKey("john2", keystr, "password")
|
||||||
|
require.Equal(t, "cannot overwrite key: john2", err.Error())
|
||||||
|
|
||||||
|
// try export non existing key
|
||||||
|
_, err = kb.ExportPrivKey("john3", "wrongpassword", "password")
|
||||||
|
require.Equal(t, "The specified item could not be found in the keyring", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeyringKeybaseUpdate(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
kb, err := NewKeyring("keybasename", "test", dir, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "unsupported operation", kb.Update("john", "oldpassword",
|
||||||
|
func() (string, error) { return "", nil }).Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSupportedAlgos(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
kb, err := NewKeyring("keybasename", "test", dir, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []SigningAlgo([]SigningAlgo{"secp256k1"}), kb.SupportedAlgos())
|
||||||
|
require.Equal(t, []SigningAlgo([]SigningAlgo{"secp256k1"}), kb.SupportedAlgosLedger())
|
||||||
|
}
|
||||||
|
|
|
@ -11,9 +11,8 @@ import (
|
||||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||||
"github.com/tendermint/tendermint/crypto/xsalsa20symmetric"
|
"github.com/tendermint/tendermint/crypto/xsalsa20symmetric"
|
||||||
|
|
||||||
tmos "github.com/tendermint/tendermint/libs/os"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
||||||
|
"github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -134,7 +133,7 @@ func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte
|
||||||
saltBytes = crypto.CRandBytes(16)
|
saltBytes = crypto.CRandBytes(16)
|
||||||
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter)
|
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tmos.Exit("Error generating bcrypt key from passphrase: " + err.Error())
|
panic(errors.Wrap(err, "error generating bcrypt key from passphrase"))
|
||||||
}
|
}
|
||||||
key = crypto.Sha256(key) // get 32 bytes
|
key = crypto.Sha256(key) // get 32 bytes
|
||||||
privKeyBytes := privKey.Bytes()
|
privKeyBytes := privKey.Bytes()
|
||||||
|
@ -151,7 +150,7 @@ func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey crypto.P
|
||||||
return privKey, "", fmt.Errorf("unrecognized armor type: %v", blockType)
|
return privKey, "", fmt.Errorf("unrecognized armor type: %v", blockType)
|
||||||
}
|
}
|
||||||
if header["kdf"] != "bcrypt" {
|
if header["kdf"] != "bcrypt" {
|
||||||
return privKey, "", fmt.Errorf("unrecognized KDF type: %v", header["KDF"])
|
return privKey, "", fmt.Errorf("unrecognized KDF type: %v", header["kdf"])
|
||||||
}
|
}
|
||||||
if header["salt"] == "" {
|
if header["salt"] == "" {
|
||||||
return privKey, "", fmt.Errorf("missing salt bytes")
|
return privKey, "", fmt.Errorf("missing salt bytes")
|
||||||
|
@ -171,7 +170,7 @@ func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey crypto.P
|
||||||
func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
|
func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
|
||||||
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter)
|
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tmos.Exit("error generating bcrypt key from passphrase: " + err.Error())
|
return privKey, errors.Wrap(err, "error generating bcrypt key from passphrase")
|
||||||
}
|
}
|
||||||
key = crypto.Sha256(key) // Get 32 bytes
|
key = crypto.Sha256(key) // Get 32 bytes
|
||||||
privKeyBytes, err := xsalsa20symmetric.DecryptSymmetric(encBytes, key)
|
privKeyBytes, err := xsalsa20symmetric.DecryptSymmetric(encBytes, key)
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
package mintkey_test
|
package mintkey_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tendermint/crypto/bcrypt"
|
||||||
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
"github.com/tendermint/tendermint/crypto/armor"
|
||||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||||
|
"github.com/tendermint/tendermint/crypto/xsalsa20symmetric"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
|
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
|
||||||
|
@ -13,13 +21,48 @@ import (
|
||||||
|
|
||||||
func TestArmorUnarmorPrivKey(t *testing.T) {
|
func TestArmorUnarmorPrivKey(t *testing.T) {
|
||||||
priv := secp256k1.GenPrivKey()
|
priv := secp256k1.GenPrivKey()
|
||||||
armor := mintkey.EncryptArmorPrivKey(priv, "passphrase", "")
|
armored := mintkey.EncryptArmorPrivKey(priv, "passphrase", "")
|
||||||
_, _, err := mintkey.UnarmorDecryptPrivKey(armor, "wrongpassphrase")
|
_, _, err := mintkey.UnarmorDecryptPrivKey(armored, "wrongpassphrase")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
decrypted, algo, err := mintkey.UnarmorDecryptPrivKey(armor, "passphrase")
|
decrypted, algo, err := mintkey.UnarmorDecryptPrivKey(armored, "passphrase")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, string(keys.Secp256k1), algo)
|
require.Equal(t, string(keys.Secp256k1), algo)
|
||||||
require.True(t, priv.Equals(decrypted))
|
require.True(t, priv.Equals(decrypted))
|
||||||
|
|
||||||
|
// empty string
|
||||||
|
decrypted, algo, err = mintkey.UnarmorDecryptPrivKey("", "passphrase")
|
||||||
|
require.Error(t, err)
|
||||||
|
require.True(t, errors.Is(io.EOF, err))
|
||||||
|
require.Nil(t, decrypted)
|
||||||
|
require.Empty(t, algo)
|
||||||
|
|
||||||
|
// wrong key type
|
||||||
|
armored = mintkey.ArmorPubKeyBytes(priv.PubKey().Bytes(), "")
|
||||||
|
decrypted, algo, err = mintkey.UnarmorDecryptPrivKey(armored, "passphrase")
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Contains(t, err.Error(), "unrecognized armor type")
|
||||||
|
|
||||||
|
// armor key manually
|
||||||
|
encryptPrivKeyFn := func(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) {
|
||||||
|
saltBytes = crypto.CRandBytes(16)
|
||||||
|
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), mintkey.BcryptSecurityParameter)
|
||||||
|
require.NoError(t, err)
|
||||||
|
key = crypto.Sha256(key) // get 32 bytes
|
||||||
|
privKeyBytes := privKey.Bytes()
|
||||||
|
return saltBytes, xsalsa20symmetric.EncryptSymmetric(privKeyBytes, key)
|
||||||
|
}
|
||||||
|
saltBytes, encBytes := encryptPrivKeyFn(priv, "passphrase")
|
||||||
|
|
||||||
|
// wrong kdf header
|
||||||
|
headerWrongKdf := map[string]string{
|
||||||
|
"kdf": "wrong",
|
||||||
|
"salt": fmt.Sprintf("%X", saltBytes),
|
||||||
|
"type": "secp256k",
|
||||||
|
}
|
||||||
|
armored = armor.EncodeArmor("TENDERMINT PRIVATE KEY", headerWrongKdf, encBytes)
|
||||||
|
_, _, err = mintkey.UnarmorDecryptPrivKey(armored, "passphrase")
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Equal(t, "unrecognized KDF type: wrong", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArmorUnarmorPubKey(t *testing.T) {
|
func TestArmorUnarmorPubKey(t *testing.T) {
|
||||||
|
@ -29,11 +72,66 @@ func TestArmorUnarmorPubKey(t *testing.T) {
|
||||||
// Add keys and see they return in alphabetical order
|
// Add keys and see they return in alphabetical order
|
||||||
info, _, err := cstore.CreateMnemonic("Bob", keys.English, "passphrase", keys.Secp256k1)
|
info, _, err := cstore.CreateMnemonic("Bob", keys.English, "passphrase", keys.Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
armor := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "")
|
armored := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "")
|
||||||
pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor)
|
pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armored)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pub, err := cryptoAmino.PubKeyFromBytes(pubBytes)
|
pub, err := cryptoAmino.PubKeyFromBytes(pubBytes)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, string(keys.Secp256k1), algo)
|
require.Equal(t, string(keys.Secp256k1), algo)
|
||||||
require.True(t, pub.Equals(info.GetPubKey()))
|
require.True(t, pub.Equals(info.GetPubKey()))
|
||||||
|
|
||||||
|
armored = mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "unknown")
|
||||||
|
pubBytes, algo, err = mintkey.UnarmorPubKeyBytes(armored)
|
||||||
|
require.NoError(t, err)
|
||||||
|
pub, err = cryptoAmino.PubKeyFromBytes(pubBytes)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "unknown", algo)
|
||||||
|
require.True(t, pub.Equals(info.GetPubKey()))
|
||||||
|
|
||||||
|
// armor pubkey manually
|
||||||
|
header := map[string]string{
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "unknown",
|
||||||
|
}
|
||||||
|
armored = armor.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes)
|
||||||
|
_, algo, err = mintkey.UnarmorPubKeyBytes(armored)
|
||||||
|
require.NoError(t, err)
|
||||||
|
// return secp256k1 if version is 0.0.0
|
||||||
|
require.Equal(t, "secp256k1", algo)
|
||||||
|
|
||||||
|
// missing version header
|
||||||
|
header = map[string]string{
|
||||||
|
"type": "unknown",
|
||||||
|
}
|
||||||
|
armored = armor.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes)
|
||||||
|
bz, algo, err := mintkey.UnarmorPubKeyBytes(armored)
|
||||||
|
require.Nil(t, bz)
|
||||||
|
require.Empty(t, algo)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Contains(t, err.Error(), "unrecognized version")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArmorInfoBytes(t *testing.T) {
|
||||||
|
bs := []byte("test")
|
||||||
|
armoredString := mintkey.ArmorInfoBytes(bs)
|
||||||
|
unarmoredBytes, err := mintkey.UnarmorInfoBytes(armoredString)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, bytes.Equal(bs, unarmoredBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnarmorInfoBytesErrors(t *testing.T) {
|
||||||
|
unarmoredBytes, err := mintkey.UnarmorInfoBytes("")
|
||||||
|
require.Error(t, err)
|
||||||
|
require.True(t, errors.Is(io.EOF, err))
|
||||||
|
require.Nil(t, unarmoredBytes)
|
||||||
|
|
||||||
|
header := map[string]string{
|
||||||
|
"type": "Info",
|
||||||
|
"version": "0.0.1",
|
||||||
|
}
|
||||||
|
unarmoredBytes, err = mintkey.UnarmorInfoBytes(armor.EncodeArmor(
|
||||||
|
"TENDERMINT KEY INFO", header, []byte("plain-text")))
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Equal(t, "unrecognized version: 0.0.1", err.Error())
|
||||||
|
require.Nil(t, unarmoredBytes)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
tmsecp256k1 "github.com/tendermint/tendermint/crypto/secp256k1"
|
tmsecp256k1 "github.com/tendermint/tendermint/crypto/secp256k1"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -103,7 +102,9 @@ func (pkl PrivKeyLedgerSecp256k1) Sign(message []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LedgerShowAddress triggers a ledger device to show the corresponding address.
|
// LedgerShowAddress triggers a ledger device to show the corresponding address.
|
||||||
func LedgerShowAddress(path hd.BIP44Params, expectedPubKey tmcrypto.PubKey) error {
|
func LedgerShowAddress(path hd.BIP44Params, expectedPubKey tmcrypto.PubKey,
|
||||||
|
accountAddressPrefix string) error {
|
||||||
|
|
||||||
device, err := getLedgerDevice()
|
device, err := getLedgerDevice()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -119,8 +120,7 @@ func LedgerShowAddress(path hd.BIP44Params, expectedPubKey tmcrypto.PubKey) erro
|
||||||
return fmt.Errorf("the key's pubkey does not match with the one retrieved from Ledger. Check that the HD path and device are the correct ones")
|
return fmt.Errorf("the key's pubkey does not match with the one retrieved from Ledger. Check that the HD path and device are the correct ones")
|
||||||
}
|
}
|
||||||
|
|
||||||
config := sdk.GetConfig()
|
pubKey2, _, err := getPubKeyAddrSafe(device, path, accountAddressPrefix)
|
||||||
pubKey2, _, err := getPubKeyAddrSafe(device, path, config.GetBech32AccountAddrPrefix())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,8 @@ func TestPublicKeySafe(t *testing.T) {
|
||||||
require.Nil(t, err, "%s", err)
|
require.Nil(t, err, "%s", err)
|
||||||
require.NotNil(t, priv)
|
require.NotNil(t, priv)
|
||||||
|
|
||||||
|
require.Nil(t, LedgerShowAddress(path, priv.PubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix()))
|
||||||
|
|
||||||
require.Equal(t, "eb5ae98721034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87",
|
require.Equal(t, "eb5ae98721034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87",
|
||||||
fmt.Sprintf("%x", priv.PubKey().Bytes()),
|
fmt.Sprintf("%x", priv.PubKey().Bytes()),
|
||||||
"Is your device using test mnemonic: %s ?", tests.TestMnemonic)
|
"Is your device using test mnemonic: %s ?", tests.TestMnemonic)
|
||||||
|
|
Loading…
Reference in New Issue