OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / tendermint / go-crypto / keys / cryptostore / holder_test.go
1 package cryptostore_test
2
3 import (
4         "bytes"
5         "fmt"
6         "os"
7         "testing"
8
9         "github.com/stretchr/testify/assert"
10         "github.com/stretchr/testify/require"
11
12         cmn "github.com/tendermint/tmlibs/common"
13
14         crypto "github.com/tendermint/go-crypto"
15         "github.com/tendermint/go-crypto/keys"
16         "github.com/tendermint/go-crypto/keys/cryptostore"
17         "github.com/tendermint/go-crypto/keys/storage/memstorage"
18         "github.com/tendermint/go-crypto/nano"
19 )
20
21 // TestKeyManagement makes sure we can manipulate these keys well
22 func TestKeyManagement(t *testing.T) {
23         assert, require := assert.New(t), require.New(t)
24
25         // make the storage with reasonable defaults
26         cstore := cryptostore.New(
27                 cryptostore.SecretBox,
28                 memstorage.New(),
29                 keys.MustLoadCodec("english"),
30         )
31
32         algo := crypto.NameEd25519
33         n1, n2, n3 := "personal", "business", "other"
34         p1, p2 := "1234", "really-secure!@#$"
35
36         // Check empty state
37         l, err := cstore.List()
38         require.Nil(err)
39         assert.Empty(l)
40
41         // create some keys
42         _, err = cstore.Get(n1)
43         assert.NotNil(err)
44         i, _, err := cstore.Create(n1, p1, algo)
45         require.Equal(n1, i.Name)
46         require.Nil(err)
47         _, _, err = cstore.Create(n2, p2, algo)
48         require.Nil(err)
49
50         // we can get these keys
51         i2, err := cstore.Get(n2)
52         assert.Nil(err)
53         _, err = cstore.Get(n3)
54         assert.NotNil(err)
55
56         // list shows them in order
57         keyS, err := cstore.List()
58         require.Nil(err)
59         require.Equal(2, len(keyS))
60         // note these are in alphabetical order
61         assert.Equal(n2, keyS[0].Name)
62         assert.Equal(n1, keyS[1].Name)
63         assert.Equal(i2.PubKey, keyS[0].PubKey)
64
65         // deleting a key removes it
66         err = cstore.Delete("bad name", "foo")
67         require.NotNil(err)
68         err = cstore.Delete(n1, p1)
69         require.Nil(err)
70         keyS, err = cstore.List()
71         require.Nil(err)
72         assert.Equal(1, len(keyS))
73         _, err = cstore.Get(n1)
74         assert.NotNil(err)
75
76         // make sure that it only signs with the right password
77         // tx := mock.NewSig([]byte("mytransactiondata"))
78         // err = cstore.Sign(n2, p1, tx)
79         // assert.NotNil(err)
80         // err = cstore.Sign(n2, p2, tx)
81         // assert.Nil(err, "%+v", err)
82         // sigs, err := tx.Signers()
83         // assert.Nil(err, "%+v", err)
84         // if assert.Equal(1, len(sigs)) {
85         //      assert.Equal(i2.PubKey, sigs[0])
86         // }
87 }
88
89 // TestSignVerify does some detailed checks on how we sign and validate
90 // signatures
91 func TestSignVerify(t *testing.T) {
92         assert, require := assert.New(t), require.New(t)
93
94         // make the storage with reasonable defaults
95         cstore := cryptostore.New(
96                 cryptostore.SecretBox,
97                 memstorage.New(),
98                 keys.MustLoadCodec("english"),
99         )
100         algo := crypto.NameSecp256k1
101
102         n1, n2 := "some dude", "a dudette"
103         p1, p2 := "1234", "foobar"
104
105         // create two users and get their info
106         i1, _, err := cstore.Create(n1, p1, algo)
107         require.Nil(err)
108
109         i2, _, err := cstore.Create(n2, p2, algo)
110         require.Nil(err)
111
112         // let's try to sign some messages
113         d1 := []byte("my first message")
114         d2 := []byte("some other important info!")
115
116         // try signing both data with both keys...
117         s11 := keys.NewMockSignable(d1)
118         err = cstore.Sign(n1, p1, s11)
119         require.Nil(err)
120         s12 := keys.NewMockSignable(d2)
121         err = cstore.Sign(n1, p1, s12)
122         require.Nil(err)
123         s21 := keys.NewMockSignable(d1)
124         err = cstore.Sign(n2, p2, s21)
125         require.Nil(err)
126         s22 := keys.NewMockSignable(d2)
127         err = cstore.Sign(n2, p2, s22)
128         require.Nil(err)
129
130         // let's try to validate and make sure it only works when everything is proper
131         cases := []struct {
132                 key   crypto.PubKey
133                 data  []byte
134                 sig   crypto.Signature
135                 valid bool
136         }{
137                 // proper matches
138                 {i1.PubKey, d1, s11.Signature, true},
139                 // change data, pubkey, or signature leads to fail
140                 {i1.PubKey, d2, s11.Signature, false},
141                 {i2.PubKey, d1, s11.Signature, false},
142                 {i1.PubKey, d1, s21.Signature, false},
143                 // make sure other successes
144                 {i1.PubKey, d2, s12.Signature, true},
145                 {i2.PubKey, d1, s21.Signature, true},
146                 {i2.PubKey, d2, s22.Signature, true},
147         }
148
149         for i, tc := range cases {
150                 valid := tc.key.VerifyBytes(tc.data, tc.sig)
151                 assert.Equal(tc.valid, valid, "%d", i)
152         }
153 }
154
155 // TestSignWithLedger makes sure we have ledger compatibility with
156 // the crypto store.
157 //
158 // This test will only succeed with a ledger attached to the computer
159 // and the cosmos app open
160 func TestSignWithLedger(t *testing.T) {
161         assert, require := assert.New(t), require.New(t)
162         if os.Getenv("WITH_LEDGER") == "" {
163                 t.Skip("Set WITH_LEDGER to run code on real ledger")
164         }
165
166         // make the storage with reasonable defaults
167         cstore := cryptostore.New(
168                 cryptostore.SecretBox,
169                 memstorage.New(),
170                 keys.MustLoadCodec("english"),
171         )
172         n := "nano-s"
173         p := "hard2hack"
174
175         // create a nano user
176         c, _, err := cstore.Create(n, p, nano.NameLedgerEd25519)
177         require.Nil(err, "%+v", err)
178         assert.Equal(c.Name, n)
179         _, ok := c.PubKey.Unwrap().(nano.PubKeyLedgerEd25519)
180         require.True(ok)
181
182         // make sure we can get it back
183         info, err := cstore.Get(n)
184         require.Nil(err, "%+v", err)
185         assert.Equal(info.Name, n)
186         key := info.PubKey
187         require.False(key.Empty())
188         require.True(key.Equals(c.PubKey))
189
190         // let's try to sign some messages
191         d1 := []byte("welcome to cosmos")
192         d2 := []byte("please turn on the app")
193
194         // try signing both data with the ledger...
195         s1 := keys.NewMockSignable(d1)
196         err = cstore.Sign(n, p, s1)
197         require.Nil(err)
198         s2 := keys.NewMockSignable(d2)
199         err = cstore.Sign(n, p, s2)
200         require.Nil(err)
201
202         // now, let's check those signatures work
203         assert.True(key.VerifyBytes(d1, s1.Signature))
204         assert.True(key.VerifyBytes(d2, s2.Signature))
205         // and mismatched signatures don't
206         assert.False(key.VerifyBytes(d1, s2.Signature))
207 }
208
209 func assertPassword(assert *assert.Assertions, cstore cryptostore.Manager, name, pass, badpass string) {
210         err := cstore.Update(name, badpass, pass)
211         assert.NotNil(err)
212         err = cstore.Update(name, pass, pass)
213         assert.Nil(err, "%+v", err)
214 }
215
216 // TestImportUnencrypted tests accepting raw priv keys bytes as input
217 func TestImportUnencrypted(t *testing.T) {
218         require := require.New(t)
219
220         // make the storage with reasonable defaults
221         cstore := cryptostore.New(
222                 cryptostore.SecretBox,
223                 memstorage.New(),
224                 keys.MustLoadCodec("english"),
225         )
226
227         key, err := cryptostore.GenEd25519.Generate(cmn.RandBytes(16))
228         require.NoError(err)
229
230         addr := key.PubKey().Address()
231         name := "john"
232         pass := "top-secret"
233
234         // import raw bytes
235         err = cstore.Import(name, pass, "", key.Bytes())
236         require.Nil(err, "%+v", err)
237
238         // make sure the address matches
239         info, err := cstore.Get(name)
240         require.Nil(err, "%+v", err)
241         require.EqualValues(addr, info.Address)
242 }
243
244 // TestAdvancedKeyManagement verifies update, import, export functionality
245 func TestAdvancedKeyManagement(t *testing.T) {
246         assert, require := assert.New(t), require.New(t)
247
248         // make the storage with reasonable defaults
249         cstore := cryptostore.New(
250                 cryptostore.SecretBox,
251                 memstorage.New(),
252                 keys.MustLoadCodec("english"),
253         )
254
255         algo := crypto.NameSecp256k1
256         n1, n2 := "old-name", "new name"
257         p1, p2, p3, pt := "1234", "foobar", "ding booms!", "really-secure!@#$"
258
259         // make sure key works with initial password
260         _, _, err := cstore.Create(n1, p1, algo)
261         require.Nil(err, "%+v", err)
262         assertPassword(assert, cstore, n1, p1, p2)
263
264         // update password requires the existing password
265         err = cstore.Update(n1, "jkkgkg", p2)
266         assert.NotNil(err)
267         assertPassword(assert, cstore, n1, p1, p2)
268
269         // then it changes the password when correct
270         err = cstore.Update(n1, p1, p2)
271         assert.Nil(err)
272         // p2 is now the proper one!
273         assertPassword(assert, cstore, n1, p2, p1)
274
275         // exporting requires the proper name and passphrase
276         _, err = cstore.Export(n2, p2, pt)
277         assert.NotNil(err)
278         _, err = cstore.Export(n1, p1, pt)
279         assert.NotNil(err)
280         exported, err := cstore.Export(n1, p2, pt)
281         require.Nil(err, "%+v", err)
282
283         // import fails on bad transfer pass
284         err = cstore.Import(n2, p3, p2, exported)
285         assert.NotNil(err)
286 }
287
288 // TestSeedPhrase verifies restoring from a seed phrase
289 func TestSeedPhrase(t *testing.T) {
290         assert, require := assert.New(t), require.New(t)
291
292         // make the storage with reasonable defaults
293         cstore := cryptostore.New(
294                 cryptostore.SecretBox,
295                 memstorage.New(),
296                 keys.MustLoadCodec("english"),
297         )
298
299         algo := crypto.NameEd25519
300         n1, n2 := "lost-key", "found-again"
301         p1, p2 := "1234", "foobar"
302
303         // make sure key works with initial password
304         info, seed, err := cstore.Create(n1, p1, algo)
305         require.Nil(err, "%+v", err)
306         assert.Equal(n1, info.Name)
307         assert.NotEmpty(seed)
308
309         // now, let us delete this key
310         err = cstore.Delete(n1, p1)
311         require.Nil(err, "%+v", err)
312         _, err = cstore.Get(n1)
313         require.NotNil(err)
314
315         // let us re-create it from the seed-phrase
316         newInfo, err := cstore.Recover(n2, p2, seed)
317         require.Nil(err, "%+v", err)
318         assert.Equal(n2, newInfo.Name)
319         assert.Equal(info.Address, newInfo.Address)
320         assert.Equal(info.PubKey, newInfo.PubKey)
321 }
322
323 func ExampleNew() {
324         // Select the encryption and storage for your cryptostore
325         cstore := cryptostore.New(
326                 cryptostore.SecretBox,
327                 // Note: use filestorage.New(dir) for real data
328                 memstorage.New(),
329                 keys.MustLoadCodec("english"),
330         )
331         ed := crypto.NameEd25519
332         sec := crypto.NameSecp256k1
333
334         // Add keys and see they return in alphabetical order
335         bob, _, err := cstore.Create("Bob", "friend", ed)
336         if err != nil {
337                 // this should never happen
338                 fmt.Println(err)
339         } else {
340                 // return info here just like in List
341                 fmt.Println(bob.Name)
342         }
343         cstore.Create("Alice", "secret", sec)
344         cstore.Create("Carl", "mitm", ed)
345         info, _ := cstore.List()
346         for _, i := range info {
347                 fmt.Println(i.Name)
348         }
349
350         // We need to use passphrase to generate a signature
351         tx := keys.NewMockSignable([]byte("deadbeef"))
352         err = cstore.Sign("Bob", "friend", tx)
353         if err != nil {
354                 fmt.Println("don't accept real passphrase")
355         }
356
357         // and we can validate the signature with publically available info
358         binfo, _ := cstore.Get("Bob")
359         if !binfo.PubKey.Equals(bob.PubKey) {
360                 fmt.Println("Get and Create return different keys")
361         }
362
363         sigs, err := tx.Signers()
364         if err != nil {
365                 fmt.Println("badly signed")
366         } else if bytes.Equal(sigs[0].Bytes(), binfo.PubKey.Bytes()) {
367                 fmt.Println("signed by Bob")
368         } else {
369                 fmt.Println("signed by someone else")
370         }
371
372         // Output:
373         // Bob
374         // Alice
375         // Bob
376         // Carl
377         // signed by Bob
378 }