2018-06-28 17:54:47 -07:00
|
|
|
package keys
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2019-02-08 12:45:23 -08:00
|
|
|
"reflect"
|
2018-06-28 17:54:47 -07:00
|
|
|
"strings"
|
|
|
|
|
2019-03-01 13:29:33 -08:00
|
|
|
"github.com/pkg/errors"
|
2019-09-21 09:54:14 -07:00
|
|
|
tmcrypto "github.com/tendermint/tendermint/crypto"
|
|
|
|
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
|
|
|
dbm "github.com/tendermint/tm-db"
|
2018-10-17 10:37:58 -07:00
|
|
|
|
2019-02-05 08:22:56 -08:00
|
|
|
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
2018-10-17 10:37:58 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
|
2018-10-03 08:48:23 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/types"
|
2018-06-28 17:54:47 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
var _ Keybase = dbKeybase{}
|
|
|
|
|
|
|
|
// Language is a language to create the BIP 39 mnemonic in.
|
|
|
|
// Currently, only english is supported though.
|
|
|
|
// Find a list of all supported languages in the BIP 39 spec (word lists).
|
|
|
|
type Language int
|
|
|
|
|
2019-02-05 08:22:56 -08:00
|
|
|
//noinspection ALL
|
2018-06-28 17:54:47 -07:00
|
|
|
const (
|
|
|
|
// English is the default language to create a mnemonic.
|
|
|
|
// It is the only supported language by this package.
|
|
|
|
English Language = iota + 1
|
|
|
|
// Japanese is currently not supported.
|
|
|
|
Japanese
|
|
|
|
// Korean is currently not supported.
|
|
|
|
Korean
|
|
|
|
// Spanish is currently not supported.
|
|
|
|
Spanish
|
|
|
|
// ChineseSimplified is currently not supported.
|
|
|
|
ChineseSimplified
|
|
|
|
// ChineseTraditional is currently not supported.
|
|
|
|
ChineseTraditional
|
|
|
|
// French is currently not supported.
|
|
|
|
French
|
|
|
|
// Italian is currently not supported.
|
|
|
|
Italian
|
2018-09-25 13:48:38 -07:00
|
|
|
addressSuffix = "address"
|
|
|
|
infoSuffix = "info"
|
2018-06-28 17:54:47 -07:00
|
|
|
)
|
|
|
|
|
2018-10-17 10:37:58 -07:00
|
|
|
const (
|
|
|
|
// used for deriving seed from mnemonic
|
2019-02-05 08:22:56 -08:00
|
|
|
DefaultBIP39Passphrase = ""
|
2018-10-17 10:37:58 -07:00
|
|
|
|
|
|
|
// bits of entropy to draw when creating a mnemonic
|
|
|
|
defaultEntropySize = 256
|
|
|
|
)
|
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
var (
|
2018-07-13 19:17:53 -07:00
|
|
|
// ErrUnsupportedSigningAlgo is raised when the caller tries to use a
|
|
|
|
// different signing scheme than secp256k1.
|
2020-01-14 07:40:10 -08:00
|
|
|
ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo")
|
2018-07-13 19:17:53 -07:00
|
|
|
|
|
|
|
// ErrUnsupportedLanguage is raised when the caller tries to use a
|
|
|
|
// different language than english for creating a mnemonic sentence.
|
2018-06-28 17:54:47 -07:00
|
|
|
ErrUnsupportedLanguage = errors.New("unsupported language: only english is supported")
|
|
|
|
)
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// dbKeybase combines encryption and storage implementation to provide a
|
|
|
|
// full-featured key manager.
|
|
|
|
//
|
|
|
|
// NOTE: dbKeybase will be deprecated in favor of keyringKeybase.
|
2018-06-28 17:54:47 -07:00
|
|
|
type dbKeybase struct {
|
2019-09-21 09:54:14 -07:00
|
|
|
base baseKeybase
|
2019-10-14 08:43:19 -07:00
|
|
|
db dbm.DB
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// newDBKeybase creates a new dbKeybase instance using the provided DB for
|
|
|
|
// reading and writing keys.
|
2019-12-12 13:52:24 -08:00
|
|
|
func newDBKeybase(db dbm.DB, opts ...KeybaseOption) Keybase {
|
2018-06-28 17:54:47 -07:00
|
|
|
return dbKeybase{
|
2019-12-12 13:52:24 -08:00
|
|
|
base: newBaseKeybase(opts...),
|
2019-10-14 08:43:19 -07:00
|
|
|
db: db,
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-11 17:18:58 -08:00
|
|
|
// NewInMemory creates a transient keybase on top of in-memory storage
|
|
|
|
// instance useful for testing purposes and on-the-fly key generation.
|
2019-12-12 13:52:24 -08:00
|
|
|
// Keybase options can be applied when generating this new Keybase.
|
|
|
|
func NewInMemory(opts ...KeybaseOption) Keybase { return newDBKeybase(dbm.NewMemDB(), opts...) }
|
2019-02-07 14:38:45 -08:00
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
// CreateMnemonic generates a new key and persists it to storage, encrypted
|
2019-09-21 09:54:14 -07:00
|
|
|
// using the provided password. It returns the generated mnemonic and the key Info.
|
|
|
|
// It returns an error if it fails to generate a key for the given key algorithm
|
|
|
|
// type, or if another key is already stored under the same name.
|
|
|
|
func (kb dbKeybase) CreateMnemonic(
|
|
|
|
name string, language Language, passwd string, algo SigningAlgo,
|
|
|
|
) (info Info, mnemonic string, err error) {
|
|
|
|
|
|
|
|
return kb.base.CreateMnemonic(kb, name, language, passwd, algo)
|
|
|
|
}
|
2018-06-28 17:54:47 -07:00
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// CreateAccount converts a mnemonic to a private key and persists it, encrypted
|
|
|
|
// with the given password.
|
|
|
|
func (kb dbKeybase) CreateAccount(
|
2020-01-14 07:40:10 -08:00
|
|
|
name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo,
|
2019-09-21 09:54:14 -07:00
|
|
|
) (Info, error) {
|
2018-10-17 10:37:58 -07:00
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo)
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// CreateLedger creates a new locally-stored reference to a Ledger keypair.
|
|
|
|
// It returns the created key info and an error if the Ledger could not be queried.
|
|
|
|
func (kb dbKeybase) CreateLedger(
|
|
|
|
name string, algo SigningAlgo, hrp string, account, index uint32,
|
|
|
|
) (Info, error) {
|
2019-02-05 08:22:56 -08:00
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
return kb.base.CreateLedger(kb, name, algo, hrp, account, index)
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
|
2019-03-01 13:29:33 -08:00
|
|
|
// CreateOffline creates a new reference to an offline keypair. It returns the
|
|
|
|
// created key info.
|
2020-01-14 07:40:10 -08:00
|
|
|
func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey, algo SigningAlgo) (Info, error) {
|
|
|
|
return kb.base.writeOfflineKey(kb, name, pub, algo), nil
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
|
2019-03-01 13:29:33 -08:00
|
|
|
// CreateMulti creates a new reference to a multisig (offline) keypair. It
|
|
|
|
// returns the created key info.
|
|
|
|
func (kb dbKeybase) CreateMulti(name string, pub tmcrypto.PubKey) (Info, error) {
|
2019-09-21 09:54:14 -07:00
|
|
|
return kb.base.writeMultisigKey(kb, name, pub), nil
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// List returns the keys from storage in alphabetical order.
|
|
|
|
func (kb dbKeybase) List() ([]Info, error) {
|
|
|
|
var res []Info
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2020-01-16 13:46:51 -08:00
|
|
|
iter, err := kb.db.Iterator(nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
defer iter.Close()
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
for ; iter.Valid(); iter.Next() {
|
2018-09-25 13:48:38 -07:00
|
|
|
key := string(iter.Key())
|
|
|
|
|
|
|
|
// need to include only keys in storage that have an info suffix
|
|
|
|
if strings.HasSuffix(key, infoSuffix) {
|
2019-09-21 09:54:14 -07:00
|
|
|
info, err := unmarshalInfo(iter.Value())
|
2018-09-25 13:48:38 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-09-25 13:48:38 -07:00
|
|
|
res = append(res, info)
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
return res, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get returns the public information about one key.
|
|
|
|
func (kb dbKeybase) Get(name string) (Info, error) {
|
2020-01-16 13:46:51 -08:00
|
|
|
bs, err := kb.db.Get(infoKey(name))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-07-05 18:03:41 -07:00
|
|
|
if len(bs) == 0 {
|
2018-10-24 06:19:48 -07:00
|
|
|
return nil, keyerror.NewErrKeyNotFound(name)
|
2018-07-05 18:03:41 -07:00
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
|
|
|
return unmarshalInfo(bs)
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// GetByAddress returns Info based on a provided AccAddress. An error is returned
|
|
|
|
// if the address does not exist.
|
2018-09-25 13:48:38 -07:00
|
|
|
func (kb dbKeybase) GetByAddress(address types.AccAddress) (Info, error) {
|
2020-01-16 13:46:51 -08:00
|
|
|
ik, err := kb.db.Get(addrKey(address))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-09-25 13:48:38 -07:00
|
|
|
if len(ik) == 0 {
|
|
|
|
return nil, fmt.Errorf("key with address %s not found", address)
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2020-01-16 13:46:51 -08:00
|
|
|
bs, err := kb.db.Get(ik)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
return unmarshalInfo(bs)
|
2018-09-25 13:48:38 -07:00
|
|
|
}
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// Sign signs the msg with the named key. It returns an error if the key doesn't
|
|
|
|
// exist or the decryption fails.
|
2018-08-12 00:33:48 -07:00
|
|
|
func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) {
|
2018-06-28 17:54:47 -07:00
|
|
|
info, err := kb.Get(name)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2018-07-13 19:17:53 -07:00
|
|
|
var priv tmcrypto.PrivKey
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2019-08-19 09:06:27 -07:00
|
|
|
switch i := info.(type) {
|
2018-06-28 17:54:47 -07:00
|
|
|
case localInfo:
|
2019-08-19 09:06:27 -07:00
|
|
|
if i.PrivKeyArmor == "" {
|
2018-06-28 17:54:47 -07:00
|
|
|
err = fmt.Errorf("private key not available")
|
|
|
|
return
|
|
|
|
}
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
priv, _, err = mintkey.UnarmorDecryptPrivKey(i.PrivKeyArmor, passphrase)
|
2018-06-28 17:54:47 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
case ledgerInfo:
|
2020-03-01 09:16:22 -08:00
|
|
|
return SignWithLedger(info, msg)
|
2019-03-01 13:29:33 -08:00
|
|
|
|
|
|
|
case offlineInfo, multiInfo:
|
2019-09-21 09:54:14 -07:00
|
|
|
return kb.base.DecodeSignature(info, msg)
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
sig, err = priv.Sign(msg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
return sig, priv.PubKey(), nil
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// ExportPrivateKeyObject returns a PrivKey object given the key name and
|
|
|
|
// passphrase. An error is returned if the key does not exist or if the Info for
|
|
|
|
// the key is invalid.
|
2018-07-13 19:17:53 -07:00
|
|
|
func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcrypto.PrivKey, error) {
|
2018-07-12 15:12:20 -07:00
|
|
|
info, err := kb.Get(name)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2018-07-13 19:17:53 -07:00
|
|
|
var priv tmcrypto.PrivKey
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2019-08-19 09:06:27 -07:00
|
|
|
switch i := info.(type) {
|
2018-07-12 15:12:20 -07:00
|
|
|
case localInfo:
|
2019-08-19 09:06:27 -07:00
|
|
|
linfo := i
|
2018-07-12 15:12:20 -07:00
|
|
|
if linfo.PrivKeyArmor == "" {
|
|
|
|
err = fmt.Errorf("private key not available")
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
priv, _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase)
|
2018-07-12 15:12:20 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-03-01 13:29:33 -08:00
|
|
|
|
|
|
|
case ledgerInfo, offlineInfo, multiInfo:
|
2019-02-11 09:02:47 -08:00
|
|
|
return nil, errors.New("only works on local private keys")
|
2018-07-12 15:12:20 -07:00
|
|
|
}
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2018-07-12 15:12:20 -07:00
|
|
|
return priv, nil
|
|
|
|
}
|
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
func (kb dbKeybase) Export(name string) (armor string, err error) {
|
2020-01-16 13:46:51 -08:00
|
|
|
bz, err := kb.db.Get(infoKey(name))
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
if bz == nil {
|
|
|
|
return "", fmt.Errorf("no key to export with name %s", name)
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-10-17 10:37:58 -07:00
|
|
|
return mintkey.ArmorInfoBytes(bz), nil
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// ExportPubKey returns public keys in ASCII armored format. It retrieves a Info
|
|
|
|
// object by its name and return the public key in a portable format.
|
2018-06-28 17:54:47 -07:00
|
|
|
func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) {
|
2020-01-16 13:46:51 -08:00
|
|
|
bz, err := kb.db.Get(infoKey(name))
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
if bz == nil {
|
|
|
|
return "", fmt.Errorf("no key to export with name %s", name)
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
|
|
|
info, err := unmarshalInfo(bz)
|
2018-06-28 17:54:47 -07:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
return mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), string(info.GetAlgo())), nil
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
|
2019-05-30 08:44:28 -07:00
|
|
|
// ExportPrivKey returns a private key in ASCII armored format.
|
2019-09-21 09:54:14 -07:00
|
|
|
// It returns an error if the key does not exist or a wrong encryption passphrase
|
|
|
|
// is supplied.
|
2019-05-30 08:44:28 -07:00
|
|
|
func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string,
|
|
|
|
encryptPassphrase string) (armor string, err error) {
|
|
|
|
priv, err := kb.ExportPrivateKeyObject(name, decryptPassphrase)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
info, err := kb.Get(name)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil
|
2019-05-30 08:44:28 -07:00
|
|
|
}
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// ImportPrivKey imports a private key in ASCII armor format. It returns an
|
|
|
|
// error if a key with the same name exists or a wrong encryption passphrase is
|
2019-05-30 08:44:28 -07:00
|
|
|
// supplied.
|
|
|
|
func (kb dbKeybase) ImportPrivKey(name string, armor string, passphrase string) error {
|
|
|
|
if _, err := kb.Get(name); err == nil {
|
|
|
|
return errors.New("Cannot overwrite key " + name)
|
|
|
|
}
|
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
privKey, algo, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
2019-05-30 08:44:28 -07:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "couldn't import private key")
|
|
|
|
}
|
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
kb.writeLocalKey(name, privKey, passphrase, SigningAlgo(algo))
|
2019-05-30 08:44:28 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
func (kb dbKeybase) Import(name string, armor string) (err error) {
|
2020-01-16 13:46:51 -08:00
|
|
|
bz, err := kb.db.Get(infoKey(name))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
if len(bz) > 0 {
|
2020-01-16 13:46:51 -08:00
|
|
|
return errors.New("cannot overwrite data for name " + name)
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-10-17 10:37:58 -07:00
|
|
|
infoBytes, err := mintkey.UnarmorInfoBytes(armor)
|
2018-06-28 17:54:47 -07:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
kb.db.Set(infoKey(name), infoBytes)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// ImportPubKey imports ASCII-armored public keys. Store a new Info object holding
|
|
|
|
// a public key only, i.e. it will not be possible to sign with it as it lacks the
|
|
|
|
// secret key.
|
2018-06-28 17:54:47 -07:00
|
|
|
func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) {
|
2020-01-16 13:46:51 -08:00
|
|
|
bz, err := kb.db.Get(infoKey(name))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
if len(bz) > 0 {
|
2020-01-16 13:46:51 -08:00
|
|
|
return errors.New("cannot overwrite data for name " + name)
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor)
|
2018-06-28 17:54:47 -07:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-07-25 13:43:37 -07:00
|
|
|
pubKey, err := cryptoAmino.PubKeyFromBytes(pubBytes)
|
2018-06-28 17:54:47 -07:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
kb.base.writeOfflineKey(kb, name, pubKey, SigningAlgo(algo))
|
2018-06-28 17:54:47 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-09-21 09:54:14 -07:00
|
|
|
// Delete removes key forever, but we must present the proper passphrase before
|
|
|
|
// deleting it (for security). It returns an error if the key doesn't exist or
|
|
|
|
// passphrases don't match. Passphrase is ignored when deleting references to
|
2018-11-29 12:55:23 -08:00
|
|
|
// offline and Ledger / HW wallet keys.
|
2018-11-30 12:36:55 -08:00
|
|
|
func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error {
|
2018-06-28 17:54:47 -07:00
|
|
|
// verify we have the proper password before deleting
|
|
|
|
info, err := kb.Get(name)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-11-30 12:36:55 -08:00
|
|
|
if linfo, ok := info.(localInfo); ok && !skipPass {
|
2020-01-14 07:40:10 -08:00
|
|
|
if _, _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase); err != nil {
|
2018-06-28 17:54:47 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-11-29 12:55:23 -08:00
|
|
|
kb.db.DeleteSync(addrKey(info.GetAddress()))
|
|
|
|
kb.db.DeleteSync(infoKey(name))
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update changes the passphrase with which an already stored key is
|
|
|
|
// encrypted.
|
|
|
|
//
|
|
|
|
// oldpass must be the current passphrase used for encryption,
|
2018-07-10 19:56:09 -07:00
|
|
|
// getNewpass is a function to get the passphrase to permanently replace
|
|
|
|
// the current passphrase
|
|
|
|
func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error {
|
2018-06-28 17:54:47 -07:00
|
|
|
info, err := kb.Get(name)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2019-08-19 09:06:27 -07:00
|
|
|
switch i := info.(type) {
|
2018-06-28 17:54:47 -07:00
|
|
|
case localInfo:
|
2019-08-19 09:06:27 -07:00
|
|
|
linfo := i
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
key, _, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
|
2018-06-28 17:54:47 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-07-10 19:56:09 -07:00
|
|
|
newpass, err := getNewpass()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
kb.writeLocalKey(name, key, newpass, i.GetAlgo())
|
2018-06-28 17:54:47 -07:00
|
|
|
return nil
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
default:
|
2019-02-08 12:45:23 -08:00
|
|
|
return fmt.Errorf("locally stored key required. Received: %v", reflect.TypeOf(info).String())
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-22 14:29:27 -07:00
|
|
|
// CloseDB releases the lock and closes the storage backend.
|
|
|
|
func (kb dbKeybase) CloseDB() {
|
|
|
|
kb.db.Close()
|
|
|
|
}
|
|
|
|
|
2020-01-14 07:40:10 -08:00
|
|
|
// SupportedAlgos returns a list of supported signing algorithms.
|
|
|
|
func (kb dbKeybase) SupportedAlgos() []SigningAlgo {
|
|
|
|
return kb.base.SupportedAlgos()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SupportedAlgosLedger returns a list of supported ledger signing algorithms.
|
|
|
|
func (kb dbKeybase) SupportedAlgosLedger() []SigningAlgo {
|
|
|
|
return kb.base.SupportedAlgosLedger()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (kb dbKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string, algo SigningAlgo) Info {
|
2018-06-28 17:54:47 -07:00
|
|
|
// encrypt private key using passphrase
|
2020-01-14 07:40:10 -08:00
|
|
|
privArmor := mintkey.EncryptArmorPrivKey(priv, passphrase, string(algo))
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
// make Info
|
|
|
|
pub := priv.PubKey()
|
2020-01-14 07:40:10 -08:00
|
|
|
info := newLocalInfo(name, pub, privArmor, algo)
|
2018-06-28 17:54:47 -07:00
|
|
|
|
2019-03-01 13:29:33 -08:00
|
|
|
kb.writeInfo(name, info)
|
|
|
|
return info
|
|
|
|
}
|
|
|
|
|
2019-02-08 12:45:23 -08:00
|
|
|
func (kb dbKeybase) writeInfo(name string, info Info) {
|
2018-06-28 17:54:47 -07:00
|
|
|
// write the info by key
|
2018-09-25 13:48:38 -07:00
|
|
|
key := infoKey(name)
|
2019-09-21 09:54:14 -07:00
|
|
|
serializedInfo := marshalInfo(info)
|
|
|
|
|
2019-02-11 09:02:47 -08:00
|
|
|
kb.db.SetSync(key, serializedInfo)
|
2019-09-21 09:54:14 -07:00
|
|
|
|
2018-09-25 13:48:38 -07:00
|
|
|
// store a pointer to the infokey by address for fast lookup
|
|
|
|
kb.db.SetSync(addrKey(info.GetAddress()), key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func addrKey(address types.AccAddress) []byte {
|
|
|
|
return []byte(fmt.Sprintf("%s.%s", address.String(), addressSuffix))
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func infoKey(name string) []byte {
|
2018-09-25 13:48:38 -07:00
|
|
|
return []byte(fmt.Sprintf("%s.%s", name, infoSuffix))
|
2018-06-28 17:54:47 -07:00
|
|
|
}
|