Files
cosmos-sdk/crypto/armor_test.go
T
Matt Kocubinski c99a631814 refactor(crypto): remove dependency on simapp from tests (#12614)
## Description

Closes: #12612 



---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
2022-07-18 14:45:09 +00:00

197 lines
6.5 KiB
Go

package crypto_test
import (
"bytes"
"errors"
"fmt"
"io"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/crypto/bcrypt"
tmcrypto "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/xsalsa20symmetric"
"cosmossdk.io/depinject"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/legacy"
"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/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/testutil/configurator"
"github.com/cosmos/cosmos-sdk/types"
)
func TestArmorUnarmorPrivKey(t *testing.T) {
priv := secp256k1.GenPrivKey()
armored := crypto.EncryptArmorPrivKey(priv, "passphrase", "")
_, _, err := crypto.UnarmorDecryptPrivKey(armored, "wrongpassphrase")
require.Error(t, err)
decrypted, algo, err := crypto.UnarmorDecryptPrivKey(armored, "passphrase")
require.NoError(t, err)
require.Equal(t, string(hd.Secp256k1Type), algo)
require.True(t, priv.Equals(decrypted))
// empty string
decrypted, algo, err = crypto.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 = crypto.ArmorPubKeyBytes(priv.PubKey().Bytes(), "")
_, _, err = crypto.UnarmorDecryptPrivKey(armored, "passphrase")
require.Error(t, err)
require.Contains(t, err.Error(), "unrecognized armor type")
// armor key manually
encryptPrivKeyFn := func(privKey cryptotypes.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) {
saltBytes = tmcrypto.CRandBytes(16)
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), crypto.BcryptSecurityParameter)
require.NoError(t, err)
key = tmcrypto.Sha256(key) // get 32 bytes
privKeyBytes := legacy.Cdc.Amino.MustMarshalBinaryBare(privKey)
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 = crypto.EncodeArmor("TENDERMINT PRIVATE KEY", headerWrongKdf, encBytes)
_, _, err = crypto.UnarmorDecryptPrivKey(armored, "passphrase")
require.Error(t, err)
require.Equal(t, "unrecognized KDF type: wrong", err.Error())
}
func TestArmorUnarmorPubKey(t *testing.T) {
// Select the encryption and storage for your cryptostore
var cdc codec.Codec
err := depinject.Inject(configurator.NewAppConfig(), &cdc)
require.NoError(t, err)
cstore := keyring.NewInMemory(cdc)
// Add keys and see they return in alphabetical order
k, _, err := cstore.NewMnemonic("Bob", keyring.English, types.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
key, err := k.GetPubKey()
require.NoError(t, err)
armored := crypto.ArmorPubKeyBytes(legacy.Cdc.Amino.MustMarshalBinaryBare(key), "")
pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armored)
require.NoError(t, err)
pub, err := legacy.PubKeyFromBytes(pubBytes)
require.NoError(t, err)
require.Equal(t, string(hd.Secp256k1Type), algo)
require.True(t, pub.Equals(key))
armored = crypto.ArmorPubKeyBytes(legacy.Cdc.Amino.MustMarshalBinaryBare(key), "unknown")
pubBytes, algo, err = crypto.UnarmorPubKeyBytes(armored)
require.NoError(t, err)
pub, err = legacy.PubKeyFromBytes(pubBytes)
require.NoError(t, err)
require.Equal(t, "unknown", algo)
require.True(t, pub.Equals(key))
armored, err = cstore.ExportPrivKeyArmor("Bob", "passphrase")
require.NoError(t, err)
_, _, err = crypto.UnarmorPubKeyBytes(armored)
require.Error(t, err)
require.Equal(t, `couldn't unarmor bytes: unrecognized armor type "TENDERMINT PRIVATE KEY", expected: "TENDERMINT PUBLIC KEY"`, err.Error())
// armor pubkey manually
header := map[string]string{
"version": "0.0.0",
"type": "unknown",
}
armored = crypto.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes)
_, algo, err = crypto.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 = crypto.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes)
bz, algo, err := crypto.UnarmorPubKeyBytes(armored)
require.Nil(t, bz)
require.Empty(t, algo)
require.Error(t, err)
require.Equal(t, "header's version field is empty", err.Error())
// unknown version header
header = map[string]string{
"type": "unknown",
"version": "unknown",
}
armored = crypto.EncodeArmor("TENDERMINT PUBLIC KEY", header, pubBytes)
bz, algo, err = crypto.UnarmorPubKeyBytes(armored)
require.Nil(t, bz)
require.Empty(t, algo)
require.Error(t, err)
require.Equal(t, "unrecognized version: unknown", err.Error())
}
func TestArmorInfoBytes(t *testing.T) {
bs := []byte("test")
armoredString := crypto.ArmorInfoBytes(bs)
unarmoredBytes, err := crypto.UnarmorInfoBytes(armoredString)
require.NoError(t, err)
require.True(t, bytes.Equal(bs, unarmoredBytes))
}
func TestUnarmorInfoBytesErrors(t *testing.T) {
unarmoredBytes, err := crypto.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 = crypto.UnarmorInfoBytes(crypto.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)
}
func BenchmarkBcryptGenerateFromPassword(b *testing.B) {
passphrase := []byte("passphrase")
for securityParam := 9; securityParam < 16; securityParam++ {
param := securityParam
b.Run(fmt.Sprintf("benchmark-security-param-%d", param), func(b *testing.B) {
b.ReportAllocs()
saltBytes := tmcrypto.CRandBytes(16)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := bcrypt.GenerateFromPassword(saltBytes, passphrase, param)
require.Nil(b, err)
}
})
}
}
func TestArmor(t *testing.T) {
blockType := "MINT TEST"
data := []byte("somedata")
armorStr := crypto.EncodeArmor(blockType, nil, data)
// Decode armorStr and test for equivalence.
blockType2, _, data2, err := crypto.DecodeArmor(armorStr)
require.Nil(t, err, "%+v", err)
assert.Equal(t, blockType, blockType2)
assert.Equal(t, data, data2)
}