tendermint/keys/keybase.go

203 lines
5.4 KiB
Go
Raw Normal View History

2017-11-02 14:09:59 -05:00
package keys
import (
2017-11-02 18:32:12 -05:00
"fmt"
"strings"
2017-11-02 16:31:29 -05:00
"github.com/pkg/errors"
crypto "github.com/tendermint/go-crypto"
2017-12-30 16:46:58 -05:00
"github.com/tendermint/go-crypto/keys/words"
dbm "github.com/tendermint/tmlibs/db"
)
2017-11-01 16:38:11 -05:00
// dbKeybase combines encyption and storage implementation to provide
// a full-featured key manager
2017-11-01 16:38:11 -05:00
type dbKeybase struct {
db dbm.DB
2017-12-30 16:46:58 -05:00
codec words.Codec
}
2017-12-30 16:46:58 -05:00
func New(db dbm.DB, codec words.Codec) dbKeybase {
2017-11-01 16:38:11 -05:00
return dbKeybase{
2017-11-02 16:46:10 -05:00
db: db,
codec: codec,
}
}
2017-11-01 16:38:11 -05:00
var _ Keybase = dbKeybase{}
2017-10-04 18:16:48 -04:00
// Create generates a new key and persists it to storage, encrypted
// using the passphrase. It returns the generated seedphrase
// (mnemonic) and the key Info. It returns an error if it fails to
// generate a key for the given algo type, or if another key is
// already stored under the same name.
func (kb dbKeybase) Create(name, passphrase string, algo CryptoAlgo) (Info, string, error) {
2017-12-30 17:02:18 -05:00
// NOTE: secret is SHA256 hashed by secp256k1 and ed25519.
// 16 byte secret corresponds to 12 BIP39 words.
// XXX: Ledgers use 24 words now - should we ?
secret := crypto.CRandBytes(16)
priv, err := generate(algo, secret)
2017-02-28 19:43:18 +01:00
if err != nil {
return Info{}, "", err
2017-02-28 19:43:18 +01:00
}
2017-12-30 17:02:18 -05:00
// encrypt and persist the key
info := kb.writeKey(priv, name, passphrase)
// we append the type byte to the serialized secret to help with
// recovery
// ie [secret] = [type] + [secret]
typ := cryptoAlgoToByte(algo)
secret = append([]byte{typ}, secret...)
2017-12-30 17:02:18 -05:00
// return the mnemonic phrase
words, err := kb.codec.BytesToWords(secret)
seed := strings.Join(words, " ")
return info, seed, err
2017-12-30 17:02:18 -05:00
}
2017-07-22 05:53:46 -04:00
// Recover converts a seedphrase to a private key and persists it,
// encrypted with the given passphrase. Functions like Create, but
// seedphrase is input not output.
func (kb dbKeybase) Recover(name, passphrase, seedphrase string) (Info, error) {
2017-12-30 17:02:18 -05:00
words := strings.Split(strings.TrimSpace(seedphrase), " ")
secret, err := kb.codec.WordsToBytes(words)
2017-07-22 05:53:46 -04:00
if err != nil {
return Info{}, err
2017-07-22 05:53:46 -04:00
}
// secret is comprised of the actual secret with the type
// appended.
// ie [secret] = [type] + [secret]
typ, secret := secret[0], secret[1:]
algo := byteToCryptoAlgo(typ)
priv, err := generate(algo, secret)
2017-12-30 17:02:18 -05:00
if err != nil {
return Info{}, err
2017-12-30 17:02:18 -05:00
}
// encrypt and persist key.
public := kb.writeKey(priv, name, passphrase)
return public, err
}
2017-12-30 17:02:18 -05:00
// List returns the keys from storage in alphabetical order.
2017-11-02 16:46:10 -05:00
func (kb dbKeybase) List() ([]Info, error) {
2017-11-02 18:32:12 -05:00
var res []Info
2017-12-27 14:37:37 -08:00
iter := kb.db.Iterator(nil, nil)
defer iter.Close()
for ; iter.Valid(); iter.Next() {
// key := iter.Key()
info, err := readInfo(iter.Value())
if err != nil {
return nil, err
2017-11-02 18:32:12 -05:00
}
res = append(res, info)
2017-11-02 18:32:12 -05:00
}
return res, nil
}
2017-12-30 17:02:18 -05:00
// Get returns the public information about one key.
2017-11-02 16:46:10 -05:00
func (kb dbKeybase) Get(name string) (Info, error) {
bs := kb.db.Get(infoKey(name))
2017-11-02 18:32:12 -05:00
return readInfo(bs)
}
2017-12-30 17:02:18 -05:00
// Sign signs the msg with the named key.
// It returns an error if the key doesn't exist or the decryption fails.
func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig crypto.Signature, pub crypto.PubKey, err error) {
info, err := kb.Get(name)
if err != nil {
2017-11-02 16:46:10 -05:00
return
}
priv, err := unarmorDecryptPrivKey(info.PrivKeyArmor, passphrase)
if err != nil {
return
}
sig = priv.Sign(msg)
pub = priv.PubKey()
return
}
func (kb dbKeybase) Export(name string) (armor string, err error) {
bz := kb.db.Get(infoKey(name))
if bz == nil {
return "", errors.New("No key to export with name " + name)
2017-11-02 18:32:12 -05:00
}
return armorInfoBytes(bz), nil
}
func (kb dbKeybase) Import(name string, armor string) (err error) {
bz := kb.db.Get(infoKey(name))
if len(bz) > 0 {
return errors.New("Cannot overwrite data for name " + name)
2017-11-02 18:32:12 -05:00
}
infoBytes, err := unarmorInfoBytes(armor)
if err != nil {
return
}
kb.db.Set(infoKey(name), infoBytes)
2017-11-02 18:32:12 -05:00
return nil
}
// Delete removes key forever, but we must present the
2017-12-30 17:02:18 -05:00
// proper passphrase before deleting it (for security).
2017-11-02 16:46:10 -05:00
func (kb dbKeybase) Delete(name, passphrase string) error {
// verify we have the proper password before deleting
info, err := kb.Get(name)
if err != nil {
return err
}
_, err = unarmorDecryptPrivKey(info.PrivKeyArmor, passphrase)
if err != nil {
return err
}
kb.db.DeleteSync(infoKey(name))
2017-11-02 18:32:12 -05:00
return nil
}
// Update changes the passphrase with which an already stored key is
// encrypted.
//
// oldpass must be the current passphrase used for encryption,
// newpass will be the only valid passphrase from this time forward.
2017-11-02 16:46:10 -05:00
func (kb dbKeybase) Update(name, oldpass, newpass string) error {
info, err := kb.Get(name)
if err != nil {
return err
}
key, err := unarmorDecryptPrivKey(info.PrivKeyArmor, oldpass)
if err != nil {
return err
}
kb.writeKey(key, name, newpass)
2017-11-02 18:32:12 -05:00
return nil
}
func (kb dbKeybase) writeKey(priv crypto.PrivKey, name, passphrase string) Info {
// generate the encrypted privkey
privArmor := encryptArmorPrivKey(priv, passphrase)
// make Info
info := newInfo(name, priv.PubKey(), privArmor)
2017-11-02 18:32:12 -05:00
// write them both
kb.db.SetSync(infoKey(name), info.bytes())
return info
}
2017-11-02 16:31:29 -05:00
func generate(algo CryptoAlgo, secret []byte) (crypto.PrivKey, error) {
2017-11-02 16:31:29 -05:00
switch algo {
case AlgoEd25519:
2017-11-02 16:31:29 -05:00
return crypto.GenPrivKeyEd25519FromSecret(secret).Wrap(), nil
case AlgoSecp256k1:
2017-11-02 16:31:29 -05:00
return crypto.GenPrivKeySecp256k1FromSecret(secret).Wrap(), nil
default:
err := errors.Errorf("Cannot generate keys for algorithm: %s", algo)
return crypto.PrivKey{}, err
}
}
func infoKey(name string) []byte {
return []byte(fmt.Sprintf("%s.info", name))
2017-11-02 16:46:10 -05:00
}