|
@ -1,6 +1,7 @@ |
|
|
package keys |
|
|
package keys |
|
|
|
|
|
|
|
|
import ( |
|
|
import ( |
|
|
|
|
|
"sort" |
|
|
"strings" |
|
|
"strings" |
|
|
|
|
|
|
|
|
"github.com/pkg/errors" |
|
|
"github.com/pkg/errors" |
|
@ -23,10 +24,7 @@ type dbKeybase struct { |
|
|
|
|
|
|
|
|
func New(db dbm.DB, codec Codec) dbKeybase { |
|
|
func New(db dbm.DB, codec Codec) dbKeybase { |
|
|
return dbKeybase{ |
|
|
return dbKeybase{ |
|
|
es: encryptedStorage{ |
|
|
|
|
|
db: db, |
|
|
|
|
|
coder: coder, |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
db: db, |
|
|
codec: codec, |
|
|
codec: codec, |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -66,7 +64,7 @@ func (kb dbKeybase) Create(name, passphrase, algo string) (Info, string, error) |
|
|
// it under name, protected by passphrase.
|
|
|
// it under name, protected by passphrase.
|
|
|
//
|
|
|
//
|
|
|
// Result similar to New(), except it doesn't return the seed again...
|
|
|
// Result similar to New(), except it doesn't return the seed again...
|
|
|
func (s dbKeybase) Recover(name, passphrase, seedphrase string) (Info, error) { |
|
|
|
|
|
|
|
|
func (kb dbKeybase) Recover(name, passphrase, seedphrase string) (Info, error) { |
|
|
words := strings.Split(strings.TrimSpace(seedphrase), " ") |
|
|
words := strings.Split(strings.TrimSpace(seedphrase), " ") |
|
|
secret, err := kb.codec.WordsToBytes(words) |
|
|
secret, err := kb.codec.WordsToBytes(words) |
|
|
if err != nil { |
|
|
if err != nil { |
|
@ -89,14 +87,14 @@ func (s dbKeybase) Recover(name, passphrase, seedphrase string) (Info, error) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// List loads the keys from the storage and enforces alphabetical order
|
|
|
// List loads the keys from the storage and enforces alphabetical order
|
|
|
func (s dbKeybase) List() ([]Info, error) { |
|
|
|
|
|
res, err := s.es.List() |
|
|
|
|
|
sort.SortSlice(res) |
|
|
|
|
|
|
|
|
func (kb dbKeybase) List() ([]Info, error) { |
|
|
|
|
|
res, err := kb.es.List() |
|
|
|
|
|
sort.Slice(res, func(a, b int) bool { return res[a].Name < res[b].Name }) |
|
|
return res, err |
|
|
return res, err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Get returns the public information about one key
|
|
|
// Get returns the public information about one key
|
|
|
func (s dbKeybase) Get(name string) (Info, error) { |
|
|
|
|
|
|
|
|
func (kb dbKeybase) Get(name string) (Info, error) { |
|
|
_, info, err := kb.es.store.Get(name) |
|
|
_, info, err := kb.es.store.Get(name) |
|
|
return info, err |
|
|
return info, err |
|
|
} |
|
|
} |
|
@ -105,14 +103,15 @@ func (s dbKeybase) Get(name string) (Info, error) { |
|
|
// this public key
|
|
|
// this public key
|
|
|
//
|
|
|
//
|
|
|
// If no key for this name, or the passphrase doesn't match, returns an error
|
|
|
// If no key for this name, or the passphrase doesn't match, returns an error
|
|
|
func (s dbKeybase) Sign(name, passphrase string, msg []byte) (crypto.Signature, crypto.PubKey, error) { |
|
|
|
|
|
key, _, err := kb.es.Get(name, passphrase) |
|
|
|
|
|
|
|
|
func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig crypto.Signature, pk crypto.PubKey, err error) { |
|
|
|
|
|
var key crypto.PrivKey |
|
|
|
|
|
key, _, err = kb.es.Get(name, passphrase) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return err |
|
|
|
|
|
|
|
|
return |
|
|
} |
|
|
} |
|
|
sig := key.Sign(tx.SignBytes()) |
|
|
|
|
|
pubkey := key.PubKey() |
|
|
|
|
|
return tx.Sign(pubkey, sig) |
|
|
|
|
|
|
|
|
sig = key.Sign(msg) |
|
|
|
|
|
pk = key.PubKey() |
|
|
|
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Export decodes the private key with the current password, encodes
|
|
|
// Export decodes the private key with the current password, encodes
|
|
@ -121,7 +120,7 @@ func (s dbKeybase) Sign(name, passphrase string, msg []byte) (crypto.Signature, |
|
|
//
|
|
|
//
|
|
|
// 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 dbKeybase) Export(name, oldpass, transferpass string) ([]byte, error) { |
|
|
|
|
|
|
|
|
func (kb dbKeybase) Export(name, oldpass, transferpass string) ([]byte, error) { |
|
|
key, _, err := kb.es.Get(name, oldpass) |
|
|
key, _, err := kb.es.Get(name, oldpass) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return nil, err |
|
|
return nil, err |
|
@ -134,7 +133,7 @@ func (s dbKeybase) Export(name, oldpass, transferpass string) ([]byte, error) { |
|
|
// 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 password under the given name with the
|
|
|
// new passphrase.
|
|
|
// new passphrase.
|
|
|
func (s dbKeybase) Import(name, newpass, transferpass string, data []byte) error { |
|
|
|
|
|
|
|
|
func (kb dbKeybase) Import(name, newpass, transferpass string, data []byte) error { |
|
|
key, err := kb.es.coder.Decrypt(data, transferpass) |
|
|
key, err := kb.es.coder.Decrypt(data, transferpass) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return err |
|
|
return err |
|
@ -145,7 +144,7 @@ func (s dbKeybase) Import(name, newpass, transferpass string, data []byte) error |
|
|
|
|
|
|
|
|
// Delete removes key forever, but we must present the
|
|
|
// Delete removes key forever, but we must present the
|
|
|
// proper passphrase before deleting it (for security)
|
|
|
// proper passphrase before deleting it (for security)
|
|
|
func (s dbKeybase) Delete(name, passphrase string) error { |
|
|
|
|
|
|
|
|
func (kb dbKeybase) Delete(name, passphrase string) error { |
|
|
// verify we have the proper password before deleting
|
|
|
// verify we have the proper password before deleting
|
|
|
_, _, err := kb.es.Get(name, passphrase) |
|
|
_, _, err := kb.es.Get(name, passphrase) |
|
|
if err != nil { |
|
|
if err != nil { |
|
@ -158,7 +157,7 @@ func (s dbKeybase) Delete(name, passphrase string) error { |
|
|
//
|
|
|
//
|
|
|
// oldpass must be the current passphrase used for encoding, newpass will be
|
|
|
// oldpass must be the current passphrase used for encoding, newpass will be
|
|
|
// the only valid passphrase from this time forward
|
|
|
// the only valid passphrase from this time forward
|
|
|
func (s dbKeybase) Update(name, oldpass, newpass string) error { |
|
|
|
|
|
|
|
|
func (kb dbKeybase) Update(name, oldpass, newpass string) error { |
|
|
key, _, err := kb.es.Get(name, oldpass) |
|
|
key, _, err := kb.es.Get(name, oldpass) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return err |
|
|
return err |
|
@ -197,3 +196,25 @@ func generateByType(typ byte, secret []byte) (crypto.PrivKey, error) { |
|
|
return crypto.PrivKey{}, err |
|
|
return crypto.PrivKey{}, err |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func encrypt(key crypto.PrivKey, pass string) ([]byte, error) { |
|
|
|
|
|
if pass == "" { |
|
|
|
|
|
return key.Bytes(), nil |
|
|
|
|
|
} |
|
|
|
|
|
s := secret(pass) |
|
|
|
|
|
cipher := crypto.EncryptSymmetric(key.Bytes(), s) |
|
|
|
|
|
return cipher, nil |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func 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") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
key, err = crypto.PrivKeyFromBytes(private) |
|
|
|
|
|
return key, errors.Wrap(err, "Invalid Passphrase") |
|
|
|
|
|
} |