OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / tendermint / go-crypto / keys / cryptostore / holder.go
1 package cryptostore
2
3 import (
4         "strings"
5
6         crypto "github.com/tendermint/go-crypto"
7         keys "github.com/tendermint/go-crypto/keys"
8 )
9
10 // Manager combines encyption and storage implementation to provide
11 // a full-featured key manager
12 type Manager struct {
13         es    encryptedStorage
14         codec keys.Codec
15 }
16
17 func New(coder Encoder, store keys.Storage, codec keys.Codec) Manager {
18         return Manager{
19                 es: encryptedStorage{
20                         coder: coder,
21                         store: store,
22                 },
23                 codec: codec,
24         }
25 }
26
27 // assert Manager satisfies keys.Signer and keys.Manager interfaces
28 var _ keys.Signer = Manager{}
29 var _ keys.Manager = Manager{}
30
31 // Create adds a new key to the storage engine, returning error if
32 // another key already stored under this name
33 //
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)
39
40         key, err := gen.Generate(secret)
41         if err != nil {
42                 return keys.Info{}, "", err
43         }
44
45         err = s.es.Put(name, passphrase, key)
46         if err != nil {
47                 return keys.Info{}, "", err
48         }
49
50         // we append the type byte to the serialized secret to help with recovery
51         // ie [secret] = [secret] + [type]
52         typ := key.Bytes()[0]
53         secret = append(secret, typ)
54
55         seed, err := s.codec.BytesToWords(secret)
56         phrase := strings.Join(seed, " ")
57         return info(name, key), phrase, err
58 }
59
60 // Recover takes a seed phrase and tries to recover the private key.
61 //
62 // If the seed phrase is valid, it will create the private key and store
63 // it under name, protected by passphrase.
64 //
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)
69         if err != nil {
70                 return keys.Info{}, err
71         }
72
73         // secret is comprised of the actual secret with the type appended
74         // ie [secret] = [secret] + [type]
75         l := len(secret)
76         secret, typ := secret[:l-1], secret[l-1]
77
78         gen := getGeneratorByType(typ)
79         key, err := gen.Generate(secret)
80         if err != nil {
81                 return keys.Info{}, err
82         }
83
84         // d00d, it worked!  create the bugger....
85         err = s.es.Put(name, passphrase, key)
86         return info(name, key), err
87 }
88
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()
92         res.Sort()
93         return res, err
94 }
95
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)
99         return info, err
100 }
101
102 // Sign will modify the Signable in order to attach a valid signature with
103 // this public key
104 //
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)
108         if err != nil {
109                 return err
110         }
111         sig := key.Sign(tx.SignBytes())
112         pubkey := key.PubKey()
113         return tx.Sign(pubkey, sig)
114 }
115
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
119 //
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)
124         if err != nil {
125                 return nil, err
126         }
127
128         res, err := s.es.coder.Encrypt(key, transferpass)
129         return res, err
130 }
131
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
134 // new passphrase.
135 func (s Manager) Import(name, newpass, transferpass string, data []byte) error {
136         key, err := s.es.coder.Decrypt(data, transferpass)
137         if err != nil {
138                 return err
139         }
140
141         return s.es.Put(name, newpass, key)
142 }
143
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)
149         if err != nil {
150                 return err
151         }
152         return s.es.Delete(name)
153 }
154
155 // Update changes the passphrase with which a already stored key is encoded.
156 //
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)
161         if err != nil {
162                 return err
163         }
164
165         // we must delete first, as Putting over an existing name returns an error
166         s.Delete(name, oldpass)
167
168         return s.es.Put(name, newpass, key)
169 }