Browse Source

Merge branch 'develop' into metalinter

pull/1782/head
Ethan Buchman 7 years ago
committed by GitHub
parent
commit
8e031b367f
12 changed files with 190 additions and 99 deletions
  1. +4
    -4
      keys/cryptostore/enc_storage.go
  2. +35
    -24
      keys/cryptostore/encoder.go
  3. +10
    -10
      keys/cryptostore/encoder_test.go
  4. +1
    -0
      keys/cryptostore/generator.go
  5. +10
    -8
      keys/cryptostore/holder.go
  6. +5
    -5
      keys/cryptostore/holder_test.go
  7. +1
    -1
      keys/cryptostore/storage_test.go
  8. +2
    -2
      keys/storage.go
  9. +101
    -28
      keys/storage/filestorage/main.go
  10. +7
    -6
      keys/storage/filestorage/main_test.go
  11. +7
    -5
      keys/storage/memstorage/main.go
  12. +7
    -6
      keys/storage/memstorage/main_test.go

+ 4
- 4
keys/cryptostore/enc_storage.go View File

@ -12,21 +12,21 @@ type encryptedStorage struct {
} }
func (es encryptedStorage) Put(name, pass string, key crypto.PrivKey) error { func (es encryptedStorage) Put(name, pass string, key crypto.PrivKey) error {
secret, err := es.coder.Encrypt(key, pass)
saltBytes, encBytes, err := es.coder.Encrypt(key, pass)
if err != nil { if err != nil {
return err return err
} }
ki := info(name, key) ki := info(name, key)
return es.store.Put(name, secret, ki)
return es.store.Put(name, saltBytes, encBytes, ki)
} }
func (es encryptedStorage) Get(name, pass string) (crypto.PrivKey, keys.Info, error) { func (es encryptedStorage) Get(name, pass string) (crypto.PrivKey, keys.Info, error) {
secret, info, err := es.store.Get(name)
saltBytes, encBytes, info, err := es.store.Get(name)
if err != nil { if err != nil {
return crypto.PrivKey{}, info, err return crypto.PrivKey{}, info, err
} }
key, err := es.coder.Decrypt(secret, pass)
key, err := es.coder.Decrypt(saltBytes, encBytes, pass)
return key, info, err return key, info, err
} }


+ 35
- 24
keys/cryptostore/encoder.go View File

@ -2,7 +2,9 @@ package cryptostore
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
"github.com/tendermint/go-crypto/bcrypt"
) )
var ( var (
@ -16,45 +18,54 @@ var (
// //
// This should use a well-designed symetric encryption algorithm // This should use a well-designed symetric encryption algorithm
type Encoder interface { type Encoder interface {
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))
Encrypt(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error)
Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error)
} }
type secretbox struct{} type secretbox struct{}
func (e secretbox) Encrypt(key crypto.PrivKey, pass string) ([]byte, error) {
if pass == "" {
return key.Bytes(), nil
func (e secretbox) Encrypt(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error) {
if passphrase == "" {
return nil, privKey.Bytes(), nil
}
saltBytes = crypto.CRandBytes(16)
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 14) // TODO parameterize. 14 is good today (2016)
if err != nil {
return nil, nil, errors.Wrap(err, "Couldn't generate bcrypt key from passphrase.")
} }
s := secret(pass)
cipher := crypto.EncryptSymmetric(key.Bytes(), s)
return cipher, nil
key = crypto.Sha256(key) // Get 32 bytes
privKeyBytes := privKey.Bytes()
return saltBytes, crypto.EncryptSymmetric(privKeyBytes, key), nil
} }
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)
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 != "" {
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 14) // TODO parameterize. 14 is good today (2016)
if err != nil { if err != nil {
return crypto.PrivKey{}, errors.Wrap(err, "Invalid Passphrase") return crypto.PrivKey{}, errors.Wrap(err, "Invalid Passphrase")
} }
key = crypto.Sha256(key) // Get 32 bytes
privKeyBytes, err = crypto.DecryptSymmetric(encBytes, key)
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, "Couldn't get privKey from bytes")
} }
key, err = crypto.PrivKeyFromBytes(private)
return key, errors.Wrap(err, "Invalid Passphrase")
return privKey, nil
} }
type noop struct{} type noop struct{}
func (n noop) Encrypt(key crypto.PrivKey, pass string) ([]byte, error) {
return key.Bytes(), nil
func (n noop) Encrypt(key crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error) {
return []byte{}, key.Bytes(), nil
} }
func (n noop) Decrypt(data []byte, pass string) (crypto.PrivKey, error) {
return crypto.PrivKeyFromBytes(data)
func (n noop) Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
return crypto.PrivKeyFromBytes(encBytes)
} }

+ 10
- 10
keys/cryptostore/encoder_test.go View File

@ -18,22 +18,22 @@ func TestNoopEncoder(t *testing.T) {
key := cryptostore.GenEd25519.Generate(cmn.RandBytes(16)) key := cryptostore.GenEd25519.Generate(cmn.RandBytes(16))
key2 := cryptostore.GenSecp256k1.Generate(cmn.RandBytes(16)) key2 := cryptostore.GenSecp256k1.Generate(cmn.RandBytes(16))
b, err := noop.Encrypt(key, "encode")
_, b, err := noop.Encrypt(key, "encode")
require.Nil(err) require.Nil(err)
assert.NotEmpty(b) assert.NotEmpty(b)
b2, err := noop.Encrypt(key2, "encode")
_, b2, err := noop.Encrypt(key2, "encode")
require.Nil(err) require.Nil(err)
assert.NotEmpty(b2) assert.NotEmpty(b2)
assert.NotEqual(b, b2) assert.NotEqual(b, b2)
// note the decode with a different password works - not secure! // note the decode with a different password works - not secure!
pk, err := noop.Decrypt(b, "decode")
pk, err := noop.Decrypt(nil, b, "decode")
require.Nil(err) require.Nil(err)
require.NotNil(pk) require.NotNil(pk)
assert.Equal(key, pk) assert.Equal(key, pk)
pk2, err := noop.Decrypt(b2, "kggugougp")
pk2, err := noop.Decrypt(nil, b2, "kggugougp")
require.Nil(err) require.Nil(err)
require.NotNil(pk2) require.NotNil(pk2)
assert.Equal(key2, pk2) assert.Equal(key2, pk2)
@ -46,17 +46,17 @@ func TestSecretBox(t *testing.T) {
key := cryptostore.GenEd25519.Generate(cmn.RandBytes(16)) key := cryptostore.GenEd25519.Generate(cmn.RandBytes(16))
pass := "some-special-secret" pass := "some-special-secret"
b, err := enc.Encrypt(key, pass)
s, b, err := enc.Encrypt(key, pass)
require.Nil(err) require.Nil(err)
assert.NotEmpty(b) assert.NotEmpty(b)
// decoding with a different pass is an error // decoding with a different pass is an error
pk, err := enc.Decrypt(b, "decode")
pk, err := enc.Decrypt(s, b, "decode")
require.NotNil(err) require.NotNil(err)
require.True(pk.Empty()) require.True(pk.Empty())
// but decoding with the same passphrase gets us our key // but decoding with the same passphrase gets us our key
pk, err = enc.Decrypt(b, pass)
pk, err = enc.Decrypt(s, b, pass)
require.Nil(err) require.Nil(err)
assert.Equal(key, pk) assert.Equal(key, pk)
} }
@ -80,11 +80,11 @@ func TestSecretBoxNoPass(t *testing.T) {
} }
for i, tc := range cases { for i, tc := range cases {
b, err := enc.Encrypt(key, tc.encode)
s, b, err := enc.Encrypt(key, tc.encode)
require.Nil(err, "%d: %+v", i, err) require.Nil(err, "%d: %+v", i, err)
assert.NotEmpty(b, "%d", i) assert.NotEmpty(b, "%d", i)
pk, err := enc.Decrypt(b, tc.decode)
pk, err := enc.Decrypt(s, b, tc.decode)
if tc.valid { if tc.valid {
require.Nil(err, "%d: %+v", i, err) require.Nil(err, "%d: %+v", i, err)
assert.Equal(key, pk, "%d", i) assert.Equal(key, pk, "%d", i)
@ -95,7 +95,7 @@ func TestSecretBoxNoPass(t *testing.T) {
// now let's make sure raw bytes also work... // now let's make sure raw bytes also work...
b := key.Bytes() b := key.Bytes()
pk, err := enc.Decrypt(b, "")
pk, err := enc.Decrypt(nil, b, "")
require.Nil(err, "%+v", err) require.Nil(err, "%+v", err)
assert.Equal(key, pk) assert.Equal(key, pk)
} }

+ 1
- 0
keys/cryptostore/generator.go View File

@ -2,6 +2,7 @@ package cryptostore
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
) )


+ 10
- 8
keys/cryptostore/holder.go View File

@ -94,7 +94,7 @@ func (s Manager) List() (keys.Infos, error) {
// Get returns the public information about one key // Get returns the public information about one key
func (s Manager) Get(name string) (keys.Info, error) { 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 return info, err
} }
@ -118,21 +118,23 @@ func (s Manager) Sign(name, passphrase string, tx keys.Signable) error {
// //
// This is designed to copy from one device to another, or provide backups // This is designed to copy from one device to another, or provide backups
// during version updates. // during version updates.
func (s Manager) Export(name, oldpass, transferpass string) ([]byte, error) {
// TODO: How to handle Export with salt?
func (s Manager) Export(name, oldpass, transferpass string) (salt, data []byte, err error) {
key, _, err := s.es.Get(name, oldpass) key, _, err := s.es.Get(name, oldpass)
if err != nil { if err != nil {
return nil, err
return nil, nil, err
} }
res, err := s.es.coder.Encrypt(key, transferpass)
return res, err
salt, data, err = s.es.coder.Encrypt(key, transferpass)
return salt, data, err
} }
// Import accepts bytes generated by Export along with the same transferpass // Import accepts bytes generated by Export along with the same transferpass
// If they are valid, it stores the password under the given name with the
// If they are valid, it stores the key under the given name with the
// new passphrase. // new passphrase.
func (s Manager) Import(name, newpass, transferpass string, data []byte) error {
key, err := s.es.coder.Decrypt(data, transferpass)
// 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)
if err != nil { if err != nil {
return err return err
} }


+ 5
- 5
keys/cryptostore/holder_test.go View File

@ -168,7 +168,7 @@ func TestImportUnencrypted(t *testing.T) {
pass := "top-secret" pass := "top-secret"
// import raw bytes // import raw bytes
err := cstore.Import(name, pass, "", key.Bytes())
err := cstore.Import(name, pass, "", nil, key.Bytes())
require.Nil(err, "%+v", err) require.Nil(err, "%+v", err)
// make sure the address matches // make sure the address matches
@ -209,15 +209,15 @@ func TestAdvancedKeyManagement(t *testing.T) {
assertPassword(assert, cstore, n1, p2, p1) assertPassword(assert, cstore, n1, p2, p1)
// exporting requires the proper name and passphrase // exporting requires the proper name and passphrase
_, err = cstore.Export(n2, p2, pt)
_, _, err = cstore.Export(n2, p2, pt)
assert.NotNil(err) assert.NotNil(err)
_, err = cstore.Export(n1, p1, pt)
_, _, err = cstore.Export(n1, p1, pt)
assert.NotNil(err) assert.NotNil(err)
exported, err := cstore.Export(n1, p2, pt)
salt, exported, err := cstore.Export(n1, p2, pt)
require.Nil(err, "%+v", err) require.Nil(err, "%+v", err)
// import fails on bad transfer pass // import fails on bad transfer pass
err = cstore.Import(n2, p3, p2, exported)
err = cstore.Import(n2, p3, p2, salt, exported)
assert.NotNil(err) assert.NotNil(err)
} }


+ 1
- 1
keys/cryptostore/storage_test.go View File

@ -5,9 +5,9 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
crypto "github.com/tendermint/go-crypto"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
crypto "github.com/tendermint/go-crypto"
keys "github.com/tendermint/go-crypto/keys" keys "github.com/tendermint/go-crypto/keys"
) )


+ 2
- 2
keys/storage.go View File

@ -3,8 +3,8 @@ package keys
// Storage has many implementation, based on security and sharing requirements // Storage has many implementation, based on security and sharing requirements
// like disk-backed, mem-backed, vault, db, etc. // like disk-backed, mem-backed, vault, db, etc.
type Storage interface { type Storage interface {
Put(name string, key []byte, info Info) error
Get(name string) ([]byte, Info, error)
Put(name string, salt []byte, key []byte, info Info) error
Get(name string) (salt []byte, key []byte, info Info, err error)
List() (Infos, error) List() (Infos, error)
Delete(name string) error Delete(name string) error
} }

+ 101
- 28
keys/storage/filestorage/main.go View File

@ -6,6 +6,7 @@ like standard ssh key storage.
package filestorage package filestorage
import ( import (
"encoding/hex"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@ -13,19 +14,26 @@ import (
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
keys "github.com/tendermint/go-crypto/keys" keys "github.com/tendermint/go-crypto/keys"
) )
const ( const (
// BlockType is the type of block.
BlockType = "Tendermint Light Client" BlockType = "Tendermint Light Client"
PrivExt = "tlc"
PubExt = "pub"
keyPerm = os.FileMode(0600)
// pubPerm = os.FileMode(0644)
// PrivExt is the extension for private keys.
PrivExt = "tlc"
// PubExt is the extensions for public keys.
PubExt = "pub"
keyPerm = os.FileMode(0600)
// pubPerm = os.FileMode(0644)
dirPerm = os.FileMode(0700) dirPerm = os.FileMode(0700)
) )
// FileStore is a file-based key storage with tight permissions.
type FileStore struct { type FileStore struct {
keyDir string keyDir string
} }
@ -36,9 +44,11 @@ type FileStore struct {
// be created if it doesn't exist already. // be created if it doesn't exist already.
func New(dir string) FileStore { func New(dir string) FileStore {
err := os.MkdirAll(dir, dirPerm) err := os.MkdirAll(dir, dirPerm)
if err != nil { if err != nil {
panic(err) panic(err)
} }
return FileStore{dir} return FileStore{dir}
} }
@ -47,7 +57,7 @@ var _ keys.Storage = FileStore{}
// Put creates two files, one with the public info as json, the other // Put creates two files, one with the public info as json, the other
// with the (encoded) private key as gpg ascii-armor style // with the (encoded) private key as gpg ascii-armor style
func (s FileStore) Put(name string, key []byte, info keys.Info) error {
func (s FileStore) Put(name string, salt, key []byte, info keys.Info) error {
pub, priv := s.nameToPaths(name) pub, priv := s.nameToPaths(name)
// write public info // write public info
@ -57,31 +67,34 @@ func (s FileStore) Put(name string, key []byte, info keys.Info) error {
} }
// write private info // write private info
return write(priv, name, key)
return write(priv, name, salt, key)
} }
// Get loads the info and (encoded) private key from the directory // Get loads the info and (encoded) private key from the directory
// It uses `name` to generate the filename, and returns an error if the // It uses `name` to generate the filename, and returns an error if the
// files don't exist or are in the incorrect format // files don't exist or are in the incorrect format
func (s FileStore) Get(name string) ([]byte, keys.Info, error) {
func (s FileStore) Get(name string) (salt []byte, key []byte, info keys.Info, err error) {
pub, priv := s.nameToPaths(name) pub, priv := s.nameToPaths(name)
info, err := readInfo(pub)
info, err = readInfo(pub)
if err != nil { if err != nil {
return nil, info, err
return nil, nil, info, err
} }
key, _, err := read(priv)
return key, info.Format(), err
salt, key, _, err = read(priv)
return salt, key, info.Format(), err
} }
// List parses the key directory for public info and returns a list of // List parses the key directory for public info and returns a list of
// Info for all keys located in this directory. // Info for all keys located in this directory.
func (s FileStore) List() (keys.Infos, error) { func (s FileStore) List() (keys.Infos, error) {
dir, err := os.Open(s.keyDir) dir, err := os.Open(s.keyDir)
defer dir.Close()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "List Keys") return nil, errors.Wrap(err, "List Keys")
} }
names, err := dir.Readdirnames(0) names, err := dir.Readdirnames(0)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "List Keys") return nil, errors.Wrap(err, "List Keys")
@ -109,61 +122,121 @@ func (s FileStore) List() (keys.Infos, error) {
func (s FileStore) Delete(name string) error { func (s FileStore) Delete(name string) error {
pub, priv := s.nameToPaths(name) pub, priv := s.nameToPaths(name)
err := os.Remove(priv) err := os.Remove(priv)
if err != nil { if err != nil {
return errors.Wrap(err, "Deleting Private Key") return errors.Wrap(err, "Deleting Private Key")
} }
err = os.Remove(pub) err = os.Remove(pub)
return errors.Wrap(err, "Deleting Public Key") return errors.Wrap(err, "Deleting Public Key")
} }
func (s FileStore) nameToPaths(name string) (pub, priv string) { func (s FileStore) nameToPaths(name string) (pub, priv string) {
privName := fmt.Sprintf("%s.%s", name, PrivExt) privName := fmt.Sprintf("%s.%s", name, PrivExt)
pubName := fmt.Sprintf("%s.%s", name, PubExt) pubName := fmt.Sprintf("%s.%s", name, PubExt)
return path.Join(s.keyDir, pubName), path.Join(s.keyDir, privName)
}
func writeInfo(path string, info keys.Info) error {
return write(path, info.Name, info.PubKey.Bytes())
return path.Join(s.keyDir, pubName), path.Join(s.keyDir, privName)
} }
func readInfo(path string) (info keys.Info, err error) { func readInfo(path string) (info keys.Info, err error) {
var data []byte
data, info.Name, err = read(path)
f, err := os.Open(path)
defer f.Close()
if err != nil {
return info, errors.Wrap(err, "Reading data")
}
d, err := ioutil.ReadAll(f)
if err != nil { if err != nil {
return
return info, errors.Wrap(err, "Reading data")
} }
pk, err := crypto.PubKeyFromBytes(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 info.PubKey = pk
return
return info, nil
} }
func read(path string) ([]byte, string, error) {
func read(path string) (salt, key []byte, name string, err error) {
f, err := os.Open(path) f, err := os.Open(path)
defer f.Close()
if err != nil { if err != nil {
return nil, "", errors.Wrap(err, "Reading data")
return nil, nil, "", errors.Wrap(err, "Reading data")
} }
d, err := ioutil.ReadAll(f) d, err := ioutil.ReadAll(f)
if err != nil { if err != nil {
return nil, "", errors.Wrap(err, "Reading data")
return nil, nil, "", errors.Wrap(err, "Reading data")
} }
block, headers, key, err := crypto.DecodeArmor(string(d)) block, headers, key, err := crypto.DecodeArmor(string(d))
if err != nil { if err != nil {
return nil, "", errors.Wrap(err, "Invalid Armor")
return nil, nil, "", errors.Wrap(err, "Invalid Armor")
} }
if block != BlockType { if block != BlockType {
return nil, "", errors.Errorf("Unknown key type: %s", block)
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")
} }
return key, headers["name"], nil
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 write(path, name string, key []byte) error {
func writeInfo(path string, info keys.Info) error {
f, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, keyPerm) f, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, keyPerm)
defer f.Close()
if err != nil { if err != nil {
return errors.Wrap(err, "Writing data") return errors.Wrap(err, "Writing data")
} }
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")
}
func write(path, name string, salt, key []byte) error {
f, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, keyPerm)
defer f.Close() defer f.Close()
headers := map[string]string{"name": name}
if err != nil {
return errors.Wrap(err, "Writing data")
}
headers := map[string]string{
"name": name,
"kdf": "bcrypt",
"salt": fmt.Sprintf("%X", salt),
}
text := crypto.EncodeArmor(BlockType, headers, key) text := crypto.EncodeArmor(BlockType, headers, key)
_, err = f.WriteString(text) _, err = f.WriteString(text)
return errors.Wrap(err, "Writing data") return errors.Wrap(err, "Writing data")
} }

+ 7
- 6
keys/storage/filestorage/main_test.go View File

@ -22,6 +22,7 @@ func TestBasicCRUD(t *testing.T) {
name := "bar" name := "bar"
key := []byte("secret-key-here") key := []byte("secret-key-here")
salt := []byte("salt-here")
pubkey := crypto.GenPrivKeyEd25519().PubKey() pubkey := crypto.GenPrivKeyEd25519().PubKey()
info := keys.Info{ info := keys.Info{
Name: name, Name: name,
@ -29,7 +30,7 @@ func TestBasicCRUD(t *testing.T) {
} }
// No data: Get and Delete return nothing // No data: Get and Delete return nothing
_, _, err = store.Get(name)
_, _, _, err = store.Get(name)
assert.NotNil(err) assert.NotNil(err)
err = store.Delete(name) err = store.Delete(name)
assert.NotNil(err) assert.NotNil(err)
@ -39,14 +40,14 @@ func TestBasicCRUD(t *testing.T) {
assert.Empty(l) assert.Empty(l)
// Putting the key in the store must work // Putting the key in the store must work
err = store.Put(name, key, info)
err = store.Put(name, salt, key, info)
assert.Nil(err) assert.Nil(err)
// But a second time is a failure // But a second time is a failure
err = store.Put(name, key, info)
err = store.Put(name, salt, key, info)
assert.NotNil(err) assert.NotNil(err)
// Now, we can get and list properly // Now, we can get and list properly
k, i, err := store.Get(name)
_, k, i, err := store.Get(name)
require.Nil(err, "%+v", err) require.Nil(err, "%+v", err)
assert.Equal(key, k) assert.Equal(key, k)
assert.Equal(info.Name, i.Name) assert.Equal(info.Name, i.Name)
@ -58,7 +59,7 @@ func TestBasicCRUD(t *testing.T) {
assert.Equal(i, l[0]) assert.Equal(i, l[0])
// querying a non-existent key fails // querying a non-existent key fails
_, _, err = store.Get("badname")
_, _, _, err = store.Get("badname")
assert.NotNil(err) assert.NotNil(err)
// We can only delete once // We can only delete once
@ -68,7 +69,7 @@ func TestBasicCRUD(t *testing.T) {
assert.NotNil(err) assert.NotNil(err)
// and then Get and List don't work // and then Get and List don't work
_, _, err = store.Get(name)
_, _, _, err = store.Get(name)
assert.NotNil(err) assert.NotNil(err)
// List returns empty list // List returns empty list
l, err = store.List() l, err = store.List()


+ 7
- 5
keys/storage/memstorage/main.go View File

@ -7,11 +7,13 @@ package memstorage
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
keys "github.com/tendermint/go-crypto/keys" keys "github.com/tendermint/go-crypto/keys"
) )
type data struct { type data struct {
info keys.Info info keys.Info
salt []byte
key []byte key []byte
} }
@ -27,22 +29,22 @@ var _ keys.Storage = MemStore{}
// Put adds the given key, returns an error if it another key // Put adds the given key, returns an error if it another key
// is already stored under this name // is already stored under this name
func (s MemStore) Put(name string, key []byte, info keys.Info) error {
func (s MemStore) Put(name string, salt, key []byte, info keys.Info) error {
if _, ok := s[name]; ok { if _, ok := s[name]; ok {
return errors.Errorf("Key named '%s' already exists", name) return errors.Errorf("Key named '%s' already exists", name)
} }
s[name] = data{info, key}
s[name] = data{info, salt, key}
return nil return nil
} }
// Get returns the key stored under the name, or returns an error if not present // Get returns the key stored under the name, or returns an error if not present
func (s MemStore) Get(name string) ([]byte, keys.Info, error) {
var err error
func (s MemStore) Get(name string) (salt, key []byte, info keys.Info, err error) {
d, ok := s[name] d, ok := s[name]
if !ok { if !ok {
err = errors.Errorf("Key named '%s' doesn't exist", name) err = errors.Errorf("Key named '%s' doesn't exist", name)
} }
return d.key, d.info.Format(), err
return d.salt, d.key, d.info.Format(), err
} }
// List returns the public info of all keys in the MemStore in unsorted order // List returns the public info of all keys in the MemStore in unsorted order


+ 7
- 6
keys/storage/memstorage/main_test.go View File

@ -14,6 +14,7 @@ func TestBasicCRUD(t *testing.T) {
name := "foo" name := "foo"
key := []byte("secret-key-here") key := []byte("secret-key-here")
salt := []byte("salt-here")
pubkey := crypto.GenPrivKeyEd25519().PubKey() pubkey := crypto.GenPrivKeyEd25519().PubKey()
info := keys.Info{ info := keys.Info{
Name: name, Name: name,
@ -21,7 +22,7 @@ func TestBasicCRUD(t *testing.T) {
} }
// No data: Get and Delete return nothing // No data: Get and Delete return nothing
_, _, err := store.Get(name)
_, _, _, err := store.Get(name)
assert.NotNil(err) assert.NotNil(err)
err = store.Delete(name) err = store.Delete(name)
assert.NotNil(err) assert.NotNil(err)
@ -31,14 +32,14 @@ func TestBasicCRUD(t *testing.T) {
assert.Empty(l) assert.Empty(l)
// Putting the key in the store must work // Putting the key in the store must work
err = store.Put(name, key, info)
err = store.Put(name, salt, key, info)
assert.Nil(err) assert.Nil(err)
// But a second time is a failure // But a second time is a failure
err = store.Put(name, key, info)
err = store.Put(name, salt, key, info)
assert.NotNil(err) assert.NotNil(err)
// Now, we can get and list properly // Now, we can get and list properly
k, i, err := store.Get(name)
_, k, i, err := store.Get(name)
assert.Nil(err) assert.Nil(err)
assert.Equal(key, k) assert.Equal(key, k)
assert.Equal(info.Name, i.Name) assert.Equal(info.Name, i.Name)
@ -50,7 +51,7 @@ func TestBasicCRUD(t *testing.T) {
assert.Equal(i, l[0]) assert.Equal(i, l[0])
// querying a non-existent key fails // querying a non-existent key fails
_, _, err = store.Get("badname")
_, _, _, err = store.Get("badname")
assert.NotNil(err) assert.NotNil(err)
// We can only delete once // We can only delete once
@ -60,7 +61,7 @@ func TestBasicCRUD(t *testing.T) {
assert.NotNil(err) assert.NotNil(err)
// and then Get and List don't work // and then Get and List don't work
_, _, err = store.Get(name)
_, _, _, err = store.Get(name)
assert.NotNil(err) assert.NotNil(err)
// List returns empty list // List returns empty list
l, err = store.List() l, err = store.List()


Loading…
Cancel
Save