You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

369 lines
9.2 KiB

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