mirror of
https://github.com/fluencelabs/tendermint
synced 2025-05-24 03:31:21 +00:00
commit
dd20358a26
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,5 +1,15 @@
|
||||
# Changelog
|
||||
|
||||
## 0.4.1 (October 27, 2017)
|
||||
|
||||
This release removes support for bcrypt as it was merged too soon without an upgrade plan
|
||||
for existing keys.
|
||||
|
||||
REVERTS THE FOLLOWING COMMITS:
|
||||
|
||||
- Parameterize and lower bcrypt cost - dfc4cdd2d71513e4a9922d679c74f36357c4c862
|
||||
- Upgrade keys to use bcrypt with salts (#38) - 8e7f0e7701f92206679ad093d013b9b162427631
|
||||
|
||||
## 0.4.0 (October 27, 2017)
|
||||
|
||||
BREAKING CHANGES:
|
||||
|
@ -12,21 +12,21 @@ type encryptedStorage struct {
|
||||
}
|
||||
|
||||
func (es encryptedStorage) Put(name, pass string, key crypto.PrivKey) error {
|
||||
saltBytes, encBytes, err := es.coder.Encrypt(key, pass)
|
||||
secret, err := es.coder.Encrypt(key, pass)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ki := info(name, key)
|
||||
return es.store.Put(name, saltBytes, encBytes, ki)
|
||||
return es.store.Put(name, secret, ki)
|
||||
}
|
||||
|
||||
func (es encryptedStorage) Get(name, pass string) (crypto.PrivKey, keys.Info, error) {
|
||||
saltBytes, encBytes, info, err := es.store.Get(name)
|
||||
secret, info, err := es.store.Get(name)
|
||||
if err != nil {
|
||||
return crypto.PrivKey{}, info, err
|
||||
}
|
||||
key, err := es.coder.Decrypt(saltBytes, encBytes, pass)
|
||||
key, err := es.coder.Decrypt(secret, pass)
|
||||
return key, info, err
|
||||
}
|
||||
|
||||
|
@ -2,23 +2,7 @@ package cryptostore
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-crypto/bcrypt"
|
||||
)
|
||||
|
||||
const (
|
||||
// BcryptCost is as parameter to increase the resistance of the
|
||||
// encoded keys to brute force password guessing
|
||||
//
|
||||
// Jae: 14 is good today (2016)
|
||||
//
|
||||
// Ethan: loading the key (at each signing) takes a second on my desktop,
|
||||
// this is hard for laptops and deadly for mobile. You can raise it again,
|
||||
// but for now, I will make this usable
|
||||
//
|
||||
// TODO: review value
|
||||
BCryptCost = 12
|
||||
)
|
||||
|
||||
var (
|
||||
@ -32,55 +16,45 @@ var (
|
||||
//
|
||||
// This should use a well-designed symetric encryption algorithm
|
||||
type Encoder interface {
|
||||
Encrypt(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error)
|
||||
Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error)
|
||||
Encrypt(key crypto.PrivKey, pass string) ([]byte, error)
|
||||
Decrypt(data []byte, pass string) (crypto.PrivKey, error)
|
||||
}
|
||||
|
||||
func secret(passphrase string) []byte {
|
||||
// TODO: Sha256(Bcrypt(passphrase))
|
||||
return crypto.Sha256([]byte(passphrase))
|
||||
}
|
||||
|
||||
type secretbox struct{}
|
||||
|
||||
func (e secretbox) Encrypt(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error) {
|
||||
if passphrase == "" {
|
||||
return nil, privKey.Bytes(), nil
|
||||
func (e secretbox) Encrypt(key crypto.PrivKey, pass string) ([]byte, error) {
|
||||
if pass == "" {
|
||||
return key.Bytes(), nil
|
||||
}
|
||||
|
||||
saltBytes = crypto.CRandBytes(16)
|
||||
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BCryptCost)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "Couldn't generate bcrypt key from passphrase.")
|
||||
}
|
||||
key = crypto.Sha256(key) // Get 32 bytes
|
||||
privKeyBytes := privKey.Bytes()
|
||||
return saltBytes, crypto.EncryptSymmetric(privKeyBytes, key), nil
|
||||
s := secret(pass)
|
||||
cipher := crypto.EncryptSymmetric(key.Bytes(), s)
|
||||
return cipher, nil
|
||||
}
|
||||
|
||||
func (e secretbox) Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
|
||||
privKeyBytes := encBytes
|
||||
// NOTE: Some keys weren't encrypted with a passphrase and hence we have the conditional
|
||||
if passphrase != "" {
|
||||
var key []byte
|
||||
key, err = bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BCryptCost)
|
||||
if err != nil {
|
||||
return crypto.PrivKey{}, errors.Wrap(err, "Invalid Passphrase")
|
||||
}
|
||||
key = crypto.Sha256(key) // Get 32 bytes
|
||||
privKeyBytes, err = crypto.DecryptSymmetric(encBytes, key)
|
||||
func (e secretbox) Decrypt(data []byte, pass string) (key crypto.PrivKey, err error) {
|
||||
private := data
|
||||
if pass != "" {
|
||||
s := secret(pass)
|
||||
private, err = crypto.DecryptSymmetric(data, s)
|
||||
if err != nil {
|
||||
return crypto.PrivKey{}, errors.Wrap(err, "Invalid Passphrase")
|
||||
}
|
||||
}
|
||||
privKey, err = crypto.PrivKeyFromBytes(privKeyBytes)
|
||||
if err != nil {
|
||||
return crypto.PrivKey{}, errors.Wrap(err, "Private Key")
|
||||
}
|
||||
return privKey, nil
|
||||
key, err = crypto.PrivKeyFromBytes(private)
|
||||
return key, errors.Wrap(err, "Invalid Passphrase")
|
||||
}
|
||||
|
||||
type noop struct{}
|
||||
|
||||
func (n noop) Encrypt(key crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error) {
|
||||
return []byte{}, key.Bytes(), nil
|
||||
func (n noop) Encrypt(key crypto.PrivKey, pass string) ([]byte, error) {
|
||||
return key.Bytes(), nil
|
||||
}
|
||||
|
||||
func (n noop) Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
|
||||
return crypto.PrivKeyFromBytes(encBytes)
|
||||
func (n noop) Decrypt(data []byte, pass string) (crypto.PrivKey, error) {
|
||||
return crypto.PrivKeyFromBytes(data)
|
||||
}
|
||||
|
@ -20,22 +20,22 @@ func TestNoopEncoder(t *testing.T) {
|
||||
key2, err := cryptostore.GenSecp256k1.Generate(cmn.RandBytes(16))
|
||||
require.NoError(err)
|
||||
|
||||
_, b, err := noop.Encrypt(key, "encode")
|
||||
b, err := noop.Encrypt(key, "encode")
|
||||
require.Nil(err)
|
||||
assert.NotEmpty(b)
|
||||
|
||||
_, b2, err := noop.Encrypt(key2, "encode")
|
||||
b2, err := noop.Encrypt(key2, "encode")
|
||||
require.Nil(err)
|
||||
assert.NotEmpty(b2)
|
||||
assert.NotEqual(b, b2)
|
||||
|
||||
// note the decode with a different password works - not secure!
|
||||
pk, err := noop.Decrypt(nil, b, "decode")
|
||||
pk, err := noop.Decrypt(b, "decode")
|
||||
require.Nil(err)
|
||||
require.NotNil(pk)
|
||||
assert.Equal(key, pk)
|
||||
|
||||
pk2, err := noop.Decrypt(nil, b2, "kggugougp")
|
||||
pk2, err := noop.Decrypt(b2, "kggugougp")
|
||||
require.Nil(err)
|
||||
require.NotNil(pk2)
|
||||
assert.Equal(key2, pk2)
|
||||
@ -49,17 +49,17 @@ func TestSecretBox(t *testing.T) {
|
||||
require.NoError(err)
|
||||
pass := "some-special-secret"
|
||||
|
||||
s, b, err := enc.Encrypt(key, pass)
|
||||
b, err := enc.Encrypt(key, pass)
|
||||
require.Nil(err)
|
||||
assert.NotEmpty(b)
|
||||
|
||||
// decoding with a different pass is an error
|
||||
pk, err := enc.Decrypt(s, b, "decode")
|
||||
pk, err := enc.Decrypt(b, "decode")
|
||||
require.NotNil(err)
|
||||
require.True(pk.Empty())
|
||||
|
||||
// but decoding with the same passphrase gets us our key
|
||||
pk, err = enc.Decrypt(s, b, pass)
|
||||
pk, err = enc.Decrypt(b, pass)
|
||||
require.Nil(err)
|
||||
assert.Equal(key, pk)
|
||||
}
|
||||
@ -84,11 +84,11 @@ func TestSecretBoxNoPass(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
s, b, err := enc.Encrypt(key, tc.encode)
|
||||
b, err := enc.Encrypt(key, tc.encode)
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
assert.NotEmpty(b, "%d", i)
|
||||
|
||||
pk, err := enc.Decrypt(s, b, tc.decode)
|
||||
pk, err := enc.Decrypt(b, tc.decode)
|
||||
if tc.valid {
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
assert.Equal(key, pk, "%d", i)
|
||||
@ -99,7 +99,7 @@ func TestSecretBoxNoPass(t *testing.T) {
|
||||
|
||||
// now let's make sure raw bytes also work...
|
||||
b := key.Bytes()
|
||||
pk, rerr := enc.Decrypt(nil, b, "")
|
||||
require.NoError(rerr)
|
||||
pk, err := enc.Decrypt(b, "")
|
||||
require.Nil(err, "%+v", err)
|
||||
assert.Equal(key, pk)
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package cryptostore
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-crypto/nano"
|
||||
)
|
||||
|
@ -95,7 +95,7 @@ func (s Manager) List() (keys.Infos, error) {
|
||||
|
||||
// Get returns the public information about one key
|
||||
func (s Manager) Get(name string) (keys.Info, error) {
|
||||
_, _, info, err := s.es.store.Get(name)
|
||||
_, info, err := s.es.store.Get(name)
|
||||
return info, err
|
||||
}
|
||||
|
||||
@ -119,23 +119,21 @@ func (s Manager) Sign(name, passphrase string, tx keys.Signable) error {
|
||||
//
|
||||
// This is designed to copy from one device to another, or provide backups
|
||||
// during version updates.
|
||||
// TODO: How to handle Export with salt?
|
||||
func (s Manager) Export(name, oldpass, transferpass string) (salt, data []byte, err error) {
|
||||
func (s Manager) Export(name, oldpass, transferpass string) ([]byte, error) {
|
||||
key, _, err := s.es.Get(name, oldpass)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
salt, data, err = s.es.coder.Encrypt(key, transferpass)
|
||||
return salt, data, err
|
||||
res, err := s.es.coder.Encrypt(key, transferpass)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Import accepts bytes generated by Export along with the same transferpass
|
||||
// If they are valid, it stores the key under the given name with the
|
||||
// If they are valid, it stores the password under the given name with the
|
||||
// new passphrase.
|
||||
// TODO: How to handle Import with salt?
|
||||
func (s Manager) Import(name, newpass, transferpass string, salt, data []byte) error {
|
||||
key, err := s.es.coder.Decrypt(salt, data, transferpass)
|
||||
func (s Manager) Import(name, newpass, transferpass string, data []byte) error {
|
||||
key, err := s.es.coder.Decrypt(data, transferpass)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ func TestImportUnencrypted(t *testing.T) {
|
||||
pass := "top-secret"
|
||||
|
||||
// import raw bytes
|
||||
err = cstore.Import(name, pass, "", nil, key.Bytes())
|
||||
err = cstore.Import(name, pass, "", key.Bytes())
|
||||
require.Nil(err, "%+v", err)
|
||||
|
||||
// make sure the address matches
|
||||
@ -273,15 +273,15 @@ func TestAdvancedKeyManagement(t *testing.T) {
|
||||
assertPassword(assert, cstore, n1, p2, p1)
|
||||
|
||||
// exporting requires the proper name and passphrase
|
||||
_, _, err = cstore.Export(n2, p2, pt)
|
||||
_, err = cstore.Export(n2, p2, pt)
|
||||
assert.NotNil(err)
|
||||
_, _, err = cstore.Export(n1, p1, pt)
|
||||
_, err = cstore.Export(n1, p1, pt)
|
||||
assert.NotNil(err)
|
||||
salt, exported, err := cstore.Export(n1, p2, pt)
|
||||
exported, err := cstore.Export(n1, p2, pt)
|
||||
require.Nil(err, "%+v", err)
|
||||
|
||||
// import fails on bad transfer pass
|
||||
err = cstore.Import(n2, p3, p2, salt, exported)
|
||||
err = cstore.Import(n2, p3, p2, exported)
|
||||
assert.NotNil(err)
|
||||
}
|
||||
|
||||
|
@ -5,9 +5,9 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
)
|
||||
|
||||
|
@ -6,7 +6,6 @@ like standard ssh key storage.
|
||||
package filestorage
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@ -14,13 +13,11 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
)
|
||||
|
||||
const (
|
||||
// BlockType is the type of block.
|
||||
BlockType = "Tendermint Light Client"
|
||||
|
||||
// PrivExt is the extension for private keys.
|
||||
@ -33,7 +30,6 @@ const (
|
||||
dirPerm = os.FileMode(0700)
|
||||
)
|
||||
|
||||
// FileStore is a file-based key storage with tight permissions.
|
||||
type FileStore struct {
|
||||
keyDir string
|
||||
}
|
||||
@ -44,11 +40,9 @@ type FileStore struct {
|
||||
// be created if it doesn't exist already.
|
||||
func New(dir string) FileStore {
|
||||
err := os.MkdirAll(dir, dirPerm)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return FileStore{dir}
|
||||
}
|
||||
|
||||
@ -57,7 +51,7 @@ var _ keys.Storage = FileStore{}
|
||||
|
||||
// Put creates two files, one with the public info as json, the other
|
||||
// with the (encoded) private key as gpg ascii-armor style
|
||||
func (s FileStore) Put(name string, salt, key []byte, info keys.Info) error {
|
||||
func (s FileStore) Put(name string, key []byte, info keys.Info) error {
|
||||
pub, priv := s.nameToPaths(name)
|
||||
|
||||
// write public info
|
||||
@ -67,22 +61,22 @@ func (s FileStore) Put(name string, salt, key []byte, info keys.Info) error {
|
||||
}
|
||||
|
||||
// write private info
|
||||
return write(priv, name, salt, key)
|
||||
return write(priv, name, key)
|
||||
}
|
||||
|
||||
// Get loads the info and (encoded) private key from the directory
|
||||
// It uses `name` to generate the filename, and returns an error if the
|
||||
// files don't exist or are in the incorrect format
|
||||
func (s FileStore) Get(name string) (salt []byte, key []byte, info keys.Info, err error) {
|
||||
func (s FileStore) Get(name string) ([]byte, keys.Info, error) {
|
||||
pub, priv := s.nameToPaths(name)
|
||||
|
||||
info, err = readInfo(pub)
|
||||
info, err := readInfo(pub)
|
||||
if err != nil {
|
||||
return nil, nil, info, err
|
||||
return nil, info, err
|
||||
}
|
||||
|
||||
salt, key, _, err = read(priv)
|
||||
return salt, key, info.Format(), err
|
||||
key, _, err := read(priv)
|
||||
return key, info.Format(), err
|
||||
}
|
||||
|
||||
// List parses the key directory for public info and returns a list of
|
||||
@ -121,117 +115,63 @@ func (s FileStore) List() (keys.Infos, error) {
|
||||
func (s FileStore) Delete(name string) error {
|
||||
pub, priv := s.nameToPaths(name)
|
||||
err := os.Remove(priv)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Deleting Private Key")
|
||||
}
|
||||
|
||||
err = os.Remove(pub)
|
||||
|
||||
return errors.Wrap(err, "Deleting Public Key")
|
||||
}
|
||||
|
||||
func (s FileStore) nameToPaths(name string) (pub, priv string) {
|
||||
privName := fmt.Sprintf("%s.%s", name, PrivExt)
|
||||
pubName := fmt.Sprintf("%s.%s", name, PubExt)
|
||||
|
||||
return path.Join(s.keyDir, pubName), path.Join(s.keyDir, privName)
|
||||
}
|
||||
|
||||
func readInfo(path string) (info keys.Info, err error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return info, errors.Wrap(err, "Reading data")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
d, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return info, errors.Wrap(err, "Reading data")
|
||||
}
|
||||
|
||||
block, headers, key, err := crypto.DecodeArmor(string(d))
|
||||
if err != nil {
|
||||
return info, errors.Wrap(err, "Invalid Armor")
|
||||
}
|
||||
|
||||
if block != BlockType {
|
||||
return info, errors.Errorf("Unknown key type: %s", block)
|
||||
}
|
||||
|
||||
pk, _ := crypto.PubKeyFromBytes(key)
|
||||
info.Name = headers["name"]
|
||||
info.PubKey = pk
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func read(path string) (salt, key []byte, name string, err error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, nil, "", errors.Wrap(err, "Reading data")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
d, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, nil, "", errors.Wrap(err, "Reading data")
|
||||
}
|
||||
|
||||
block, headers, key, err := crypto.DecodeArmor(string(d))
|
||||
if err != nil {
|
||||
return nil, nil, "", errors.Wrap(err, "Invalid Armor")
|
||||
}
|
||||
|
||||
if block != BlockType {
|
||||
return nil, nil, "", errors.Errorf("Unknown key type: %s", block)
|
||||
}
|
||||
|
||||
if headers["kdf"] != "bcrypt" {
|
||||
return nil, nil, "", errors.Errorf("Unrecognized KDF type: %v", headers["kdf"])
|
||||
}
|
||||
|
||||
if headers["salt"] == "" {
|
||||
return nil, nil, "", errors.Errorf("Missing salt bytes")
|
||||
}
|
||||
|
||||
salt, err = hex.DecodeString(headers["salt"])
|
||||
if err != nil {
|
||||
return nil, nil, "", errors.Errorf("Error decoding salt: %v", err.Error())
|
||||
}
|
||||
|
||||
return salt, key, headers["name"], nil
|
||||
}
|
||||
|
||||
func writeInfo(path string, info keys.Info) error {
|
||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, keyPerm)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Writing data")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
headers := map[string]string{"name": info.Name}
|
||||
text := crypto.EncodeArmor(BlockType, headers, info.PubKey.Bytes())
|
||||
_, err = f.WriteString(text)
|
||||
|
||||
return errors.Wrap(err, "Writing data")
|
||||
return write(path, info.Name, info.PubKey.Bytes())
|
||||
}
|
||||
|
||||
func write(path, name string, salt, key []byte) error {
|
||||
func readInfo(path string) (info keys.Info, err error) {
|
||||
var data []byte
|
||||
data, info.Name, err = read(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
pk, err := crypto.PubKeyFromBytes(data)
|
||||
info.PubKey = pk
|
||||
return
|
||||
}
|
||||
|
||||
func read(path string) ([]byte, string, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrap(err, "Reading data")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
d, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrap(err, "Reading data")
|
||||
}
|
||||
block, headers, key, err := crypto.DecodeArmor(string(d))
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrap(err, "Invalid Armor")
|
||||
}
|
||||
if block != BlockType {
|
||||
return nil, "", errors.Errorf("Unknown key type: %s", block)
|
||||
}
|
||||
return key, headers["name"], nil
|
||||
}
|
||||
|
||||
func write(path, name string, key []byte) error {
|
||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, keyPerm)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Writing data")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
headers := map[string]string{
|
||||
"name": name,
|
||||
"kdf": "bcrypt",
|
||||
"salt": fmt.Sprintf("%X", salt),
|
||||
}
|
||||
|
||||
headers := map[string]string{"name": name}
|
||||
text := crypto.EncodeArmor(BlockType, headers, key)
|
||||
_, err = f.WriteString(text)
|
||||
|
||||
return errors.Wrap(err, "Writing data")
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ func TestBasicCRUD(t *testing.T) {
|
||||
|
||||
name := "bar"
|
||||
key := []byte("secret-key-here")
|
||||
salt := []byte("salt-here")
|
||||
pubkey := crypto.GenPrivKeyEd25519().PubKey()
|
||||
info := keys.Info{
|
||||
Name: name,
|
||||
@ -30,7 +29,7 @@ func TestBasicCRUD(t *testing.T) {
|
||||
}
|
||||
|
||||
// No data: Get and Delete return nothing
|
||||
_, _, _, err = store.Get(name)
|
||||
_, _, err = store.Get(name)
|
||||
assert.NotNil(err)
|
||||
err = store.Delete(name)
|
||||
assert.NotNil(err)
|
||||
@ -40,14 +39,14 @@ func TestBasicCRUD(t *testing.T) {
|
||||
assert.Empty(l)
|
||||
|
||||
// Putting the key in the store must work
|
||||
err = store.Put(name, salt, key, info)
|
||||
err = store.Put(name, key, info)
|
||||
assert.Nil(err)
|
||||
// But a second time is a failure
|
||||
err = store.Put(name, salt, key, info)
|
||||
err = store.Put(name, key, info)
|
||||
assert.NotNil(err)
|
||||
|
||||
// Now, we can get and list properly
|
||||
_, k, i, err := store.Get(name)
|
||||
k, i, err := store.Get(name)
|
||||
require.Nil(err, "%+v", err)
|
||||
assert.Equal(key, k)
|
||||
assert.Equal(info.Name, i.Name)
|
||||
@ -59,7 +58,7 @@ func TestBasicCRUD(t *testing.T) {
|
||||
assert.Equal(i, l[0])
|
||||
|
||||
// querying a non-existent key fails
|
||||
_, _, _, err = store.Get("badname")
|
||||
_, _, err = store.Get("badname")
|
||||
assert.NotNil(err)
|
||||
|
||||
// We can only delete once
|
||||
@ -69,7 +68,7 @@ func TestBasicCRUD(t *testing.T) {
|
||||
assert.NotNil(err)
|
||||
|
||||
// and then Get and List don't work
|
||||
_, _, _, err = store.Get(name)
|
||||
_, _, err = store.Get(name)
|
||||
assert.NotNil(err)
|
||||
// List returns empty list
|
||||
l, err = store.List()
|
||||
|
@ -7,13 +7,11 @@ package memstorage
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
)
|
||||
|
||||
type data struct {
|
||||
info keys.Info
|
||||
salt []byte
|
||||
key []byte
|
||||
}
|
||||
|
||||
@ -29,22 +27,22 @@ var _ keys.Storage = MemStore{}
|
||||
|
||||
// Put adds the given key, returns an error if it another key
|
||||
// is already stored under this name
|
||||
func (s MemStore) Put(name string, salt, key []byte, info keys.Info) error {
|
||||
func (s MemStore) Put(name string, key []byte, info keys.Info) error {
|
||||
if _, ok := s[name]; ok {
|
||||
return errors.Errorf("Key named '%s' already exists", name)
|
||||
}
|
||||
s[name] = data{info, salt, key}
|
||||
s[name] = data{info, key}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the key stored under the name, or returns an error if not present
|
||||
func (s MemStore) Get(name string) (salt, key []byte, info keys.Info, err error) {
|
||||
func (s MemStore) Get(name string) ([]byte, keys.Info, error) {
|
||||
var err error
|
||||
d, ok := s[name]
|
||||
if !ok {
|
||||
err = errors.Errorf("Key named '%s' doesn't exist", name)
|
||||
}
|
||||
|
||||
return d.salt, d.key, d.info.Format(), err
|
||||
return d.key, d.info.Format(), err
|
||||
}
|
||||
|
||||
// List returns the public info of all keys in the MemStore in unsorted order
|
||||
|
@ -14,7 +14,6 @@ func TestBasicCRUD(t *testing.T) {
|
||||
|
||||
name := "foo"
|
||||
key := []byte("secret-key-here")
|
||||
salt := []byte("salt-here")
|
||||
pubkey := crypto.GenPrivKeyEd25519().PubKey()
|
||||
info := keys.Info{
|
||||
Name: name,
|
||||
@ -22,7 +21,7 @@ func TestBasicCRUD(t *testing.T) {
|
||||
}
|
||||
|
||||
// No data: Get and Delete return nothing
|
||||
_, _, _, err := store.Get(name)
|
||||
_, _, err := store.Get(name)
|
||||
assert.NotNil(err)
|
||||
err = store.Delete(name)
|
||||
assert.NotNil(err)
|
||||
@ -32,14 +31,14 @@ func TestBasicCRUD(t *testing.T) {
|
||||
assert.Empty(l)
|
||||
|
||||
// Putting the key in the store must work
|
||||
err = store.Put(name, salt, key, info)
|
||||
err = store.Put(name, key, info)
|
||||
assert.Nil(err)
|
||||
// But a second time is a failure
|
||||
err = store.Put(name, salt, key, info)
|
||||
err = store.Put(name, key, info)
|
||||
assert.NotNil(err)
|
||||
|
||||
// Now, we can get and list properly
|
||||
_, k, i, err := store.Get(name)
|
||||
k, i, err := store.Get(name)
|
||||
assert.Nil(err)
|
||||
assert.Equal(key, k)
|
||||
assert.Equal(info.Name, i.Name)
|
||||
@ -51,7 +50,7 @@ func TestBasicCRUD(t *testing.T) {
|
||||
assert.Equal(i, l[0])
|
||||
|
||||
// querying a non-existent key fails
|
||||
_, _, _, err = store.Get("badname")
|
||||
_, _, err = store.Get("badname")
|
||||
assert.NotNil(err)
|
||||
|
||||
// We can only delete once
|
||||
@ -61,7 +60,7 @@ func TestBasicCRUD(t *testing.T) {
|
||||
assert.NotNil(err)
|
||||
|
||||
// and then Get and List don't work
|
||||
_, _, _, err = store.Get(name)
|
||||
_, _, err = store.Get(name)
|
||||
assert.NotNil(err)
|
||||
// List returns empty list
|
||||
l, err = store.List()
|
||||
|
@ -12,8 +12,8 @@ import (
|
||||
// Storage has many implementation, based on security and sharing requirements
|
||||
// like disk-backed, mem-backed, vault, db, etc.
|
||||
type Storage interface {
|
||||
Put(name string, salt []byte, key []byte, info Info) error
|
||||
Get(name string) (salt []byte, key []byte, info Info, err error)
|
||||
Put(name string, key []byte, info Info) error
|
||||
Get(name string) (key []byte, info Info, err error)
|
||||
List() (Infos, error)
|
||||
Delete(name string) error
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
package crypto
|
||||
|
||||
const Version = "0.4.0"
|
||||
const Version = "0.4.1"
|
||||
|
Loading…
x
Reference in New Issue
Block a user