6 crypto "github.com/tendermint/go-crypto"
7 keys "github.com/tendermint/go-crypto/keys"
10 // Manager combines encyption and storage implementation to provide
11 // a full-featured key manager
17 func New(coder Encoder, store keys.Storage, codec keys.Codec) Manager {
27 // assert Manager satisfies keys.Signer and keys.Manager interfaces
28 var _ keys.Signer = Manager{}
29 var _ keys.Manager = Manager{}
31 // Create adds a new key to the storage engine, returning error if
32 // another key already stored under this name
34 // algo must be a supported go-crypto algorithm: ed25519, secp256k1
35 func (s Manager) Create(name, passphrase, algo string) (keys.Info, string, error) {
36 // 128-bits are the all the randomness we can make use of
37 secret := crypto.CRandBytes(16)
38 gen := getGenerator(algo)
40 key, err := gen.Generate(secret)
42 return keys.Info{}, "", err
45 err = s.es.Put(name, passphrase, key)
47 return keys.Info{}, "", err
50 // we append the type byte to the serialized secret to help with recovery
51 // ie [secret] = [secret] + [type]
53 secret = append(secret, typ)
55 seed, err := s.codec.BytesToWords(secret)
56 phrase := strings.Join(seed, " ")
57 return info(name, key), phrase, err
60 // Recover takes a seed phrase and tries to recover the private key.
62 // If the seed phrase is valid, it will create the private key and store
63 // it under name, protected by passphrase.
65 // Result similar to New(), except it doesn't return the seed again...
66 func (s Manager) Recover(name, passphrase, seedphrase string) (keys.Info, error) {
67 words := strings.Split(strings.TrimSpace(seedphrase), " ")
68 secret, err := s.codec.WordsToBytes(words)
70 return keys.Info{}, err
73 // secret is comprised of the actual secret with the type appended
74 // ie [secret] = [secret] + [type]
76 secret, typ := secret[:l-1], secret[l-1]
78 gen := getGeneratorByType(typ)
79 key, err := gen.Generate(secret)
81 return keys.Info{}, err
84 // d00d, it worked! create the bugger....
85 err = s.es.Put(name, passphrase, key)
86 return info(name, key), err
89 // List loads the keys from the storage and enforces alphabetical order
90 func (s Manager) List() (keys.Infos, error) {
91 res, err := s.es.List()
96 // Get returns the public information about one key
97 func (s Manager) Get(name string) (keys.Info, error) {
98 _, info, err := s.es.store.Get(name)
102 // Sign will modify the Signable in order to attach a valid signature with
105 // If no key for this name, or the passphrase doesn't match, returns an error
106 func (s Manager) Sign(name, passphrase string, tx keys.Signable) error {
107 key, _, err := s.es.Get(name, passphrase)
111 sig := key.Sign(tx.SignBytes())
112 pubkey := key.PubKey()
113 return tx.Sign(pubkey, sig)
116 // Export decodes the private key with the current password, encodes
117 // it with a secure one-time password and generates a sequence that can be
118 // Imported by another Manager
120 // This is designed to copy from one device to another, or provide backups
121 // during version updates.
122 func (s Manager) Export(name, oldpass, transferpass string) ([]byte, error) {
123 key, _, err := s.es.Get(name, oldpass)
128 res, err := s.es.coder.Encrypt(key, transferpass)
132 // Import accepts bytes generated by Export along with the same transferpass
133 // If they are valid, it stores the password under the given name with the
135 func (s Manager) Import(name, newpass, transferpass string, data []byte) error {
136 key, err := s.es.coder.Decrypt(data, transferpass)
141 return s.es.Put(name, newpass, key)
144 // Delete removes key forever, but we must present the
145 // proper passphrase before deleting it (for security)
146 func (s Manager) Delete(name, passphrase string) error {
147 // verify we have the proper password before deleting
148 _, _, err := s.es.Get(name, passphrase)
152 return s.es.Delete(name)
155 // Update changes the passphrase with which a already stored key is encoded.
157 // oldpass must be the current passphrase used for encoding, newpass will be
158 // the only valid passphrase from this time forward
159 func (s Manager) Update(name, oldpass, newpass string) error {
160 key, _, err := s.es.Get(name, oldpass)
165 // we must delete first, as Putting over an existing name returns an error
166 s.Delete(name, oldpass)
168 return s.es.Put(name, newpass, key)