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.

281 lines
7.6 KiB

  1. package cryptostore_test
  2. import (
  3. "testing"
  4. "github.com/stretchr/testify/assert"
  5. "github.com/stretchr/testify/require"
  6. crypto "github.com/tendermint/go-crypto"
  7. "github.com/tendermint/go-crypto/keys"
  8. "github.com/tendermint/go-crypto/keys/cryptostore"
  9. "github.com/tendermint/go-crypto/keys/storage/memstorage"
  10. )
  11. // TestKeyManagement makes sure we can manipulate these keys well
  12. func TestKeyManagement(t *testing.T) {
  13. assert, require := assert.New(t), require.New(t)
  14. // make the storage with reasonable defaults
  15. cstore := cryptostore.New(
  16. cryptostore.SecretBox,
  17. memstorage.New(),
  18. keys.MustLoadCodec("english"),
  19. )
  20. algo := crypto.NameEd25519
  21. n1, n2, n3 := "personal", "business", "other"
  22. p1, p2 := "1234", "really-secure!@#$"
  23. // Check empty state
  24. l, err := cstore.List()
  25. require.Nil(err)
  26. assert.Empty(l)
  27. // create some keys
  28. _, err = cstore.Get(n1)
  29. assert.NotNil(err)
  30. i, _, err := cstore.Create(n1, p1, algo)
  31. require.Equal(n1, i.Name)
  32. require.Nil(err)
  33. _, _, err = cstore.Create(n2, p2, algo)
  34. require.Nil(err)
  35. // we can get these keys
  36. i2, err := cstore.Get(n2)
  37. assert.Nil(err)
  38. _, err = cstore.Get(n3)
  39. assert.NotNil(err)
  40. // list shows them in order
  41. keys, err := cstore.List()
  42. require.Nil(err)
  43. require.Equal(2, len(keys))
  44. // note these are in alphabetical order
  45. assert.Equal(n2, keys[0].Name)
  46. assert.Equal(n1, keys[1].Name)
  47. assert.Equal(i2.PubKey, keys[0].PubKey)
  48. // deleting a key removes it
  49. err = cstore.Delete("bad name", "foo")
  50. require.NotNil(err)
  51. err = cstore.Delete(n1, p1)
  52. require.Nil(err)
  53. keys, err = cstore.List()
  54. require.Nil(err)
  55. assert.Equal(1, len(keys))
  56. _, err = cstore.Get(n1)
  57. assert.NotNil(err)
  58. // make sure that it only signs with the right password
  59. // tx := mock.NewSig([]byte("mytransactiondata"))
  60. // err = cstore.Sign(n2, p1, tx)
  61. // assert.NotNil(err)
  62. // err = cstore.Sign(n2, p2, tx)
  63. // assert.Nil(err, "%+v", err)
  64. // sigs, err := tx.Signers()
  65. // assert.Nil(err, "%+v", err)
  66. // if assert.Equal(1, len(sigs)) {
  67. // assert.Equal(i2.PubKey, sigs[0])
  68. // }
  69. }
  70. // TestSignVerify does some detailed checks on how we sign and validate
  71. // signatures
  72. // func TestSignVerify(t *testing.T) {
  73. // assert, require := assert.New(t), require.New(t)
  74. // // make the storage with reasonable defaults
  75. // cstore := cryptostore.New(
  76. // cryptostore.GenSecp256k1,
  77. // cryptostore.SecretBox,
  78. // memstorage.New(),
  79. // )
  80. // n1, n2 := "some dude", "a dudette"
  81. // p1, p2 := "1234", "foobar"
  82. // // create two users and get their info
  83. // err := cstore.Create(n1, p1)
  84. // require.Nil(err)
  85. // i1, err := cstore.Get(n1)
  86. // require.Nil(err)
  87. // err = cstore.Create(n2, p2)
  88. // require.Nil(err)
  89. // i2, err := cstore.Get(n2)
  90. // require.Nil(err)
  91. // // let's try to sign some messages
  92. // d1 := []byte("my first message")
  93. // d2 := []byte("some other important info!")
  94. // // try signing both data with both keys...
  95. // s11, err := cstore.Signature(n1, p1, d1)
  96. // require.Nil(err)
  97. // s12, err := cstore.Signature(n1, p1, d2)
  98. // require.Nil(err)
  99. // s21, err := cstore.Signature(n2, p2, d1)
  100. // require.Nil(err)
  101. // s22, err := cstore.Signature(n2, p2, d2)
  102. // require.Nil(err)
  103. // // let's try to validate and make sure it only works when everything is proper
  104. // keys := [][]byte{i1.PubKey, i2.PubKey}
  105. // data := [][]byte{d1, d2}
  106. // sigs := [][]byte{s11, s12, s21, s22}
  107. // // loop over keys and data
  108. // for k := 0; k < 2; k++ {
  109. // for d := 0; d < 2; d++ {
  110. // // make sure only the proper sig works
  111. // good := 2*k + d
  112. // for s := 0; s < 4; s++ {
  113. // err = cstore.Verify(data[d], sigs[s], keys[k])
  114. // if s == good {
  115. // assert.Nil(err, "%+v", err)
  116. // } else {
  117. // assert.NotNil(err)
  118. // }
  119. // }
  120. // }
  121. // }
  122. // }
  123. func assertPassword(assert *assert.Assertions, cstore cryptostore.Manager, name, pass, badpass string) {
  124. err := cstore.Update(name, badpass, pass)
  125. assert.NotNil(err)
  126. err = cstore.Update(name, pass, pass)
  127. assert.Nil(err, "%+v", err)
  128. }
  129. // TestAdvancedKeyManagement verifies update, import, export functionality
  130. func TestAdvancedKeyManagement(t *testing.T) {
  131. assert, require := assert.New(t), require.New(t)
  132. // make the storage with reasonable defaults
  133. cstore := cryptostore.New(
  134. cryptostore.SecretBox,
  135. memstorage.New(),
  136. keys.MustLoadCodec("english"),
  137. )
  138. algo := crypto.NameSecp256k1
  139. n1, n2 := "old-name", "new name"
  140. p1, p2, p3, pt := "1234", "foobar", "ding booms!", "really-secure!@#$"
  141. // make sure key works with initial password
  142. _, _, err := cstore.Create(n1, p1, algo)
  143. require.Nil(err, "%+v", err)
  144. assertPassword(assert, cstore, n1, p1, p2)
  145. // update password requires the existing password
  146. err = cstore.Update(n1, "jkkgkg", p2)
  147. assert.NotNil(err)
  148. assertPassword(assert, cstore, n1, p1, p2)
  149. // then it changes the password when correct
  150. err = cstore.Update(n1, p1, p2)
  151. assert.Nil(err)
  152. // p2 is now the proper one!
  153. assertPassword(assert, cstore, n1, p2, p1)
  154. // exporting requires the proper name and passphrase
  155. _, err = cstore.Export(n2, p2, pt)
  156. assert.NotNil(err)
  157. _, err = cstore.Export(n1, p1, pt)
  158. assert.NotNil(err)
  159. exported, err := cstore.Export(n1, p2, pt)
  160. require.Nil(err, "%+v", err)
  161. // import fails on bad transfer pass
  162. err = cstore.Import(n2, p3, p2, exported)
  163. assert.NotNil(err)
  164. // import cannot overwrite existing keys
  165. err = cstore.Import(n1, p3, pt, exported)
  166. assert.NotNil(err)
  167. // we can now import under another name
  168. err = cstore.Import(n2, p3, pt, exported)
  169. require.Nil(err, "%+v", err)
  170. // make sure both passwords are now properly set (not to the transfer pass)
  171. assertPassword(assert, cstore, n1, p2, pt)
  172. assertPassword(assert, cstore, n2, p3, pt)
  173. }
  174. // TestSeedPhrase verifies restoring from a seed phrase
  175. func TestSeedPhrase(t *testing.T) {
  176. assert, require := assert.New(t), require.New(t)
  177. // make the storage with reasonable defaults
  178. cstore := cryptostore.New(
  179. cryptostore.SecretBox,
  180. memstorage.New(),
  181. keys.MustLoadCodec("english"),
  182. )
  183. algo := crypto.NameEd25519
  184. n1, n2 := "lost-key", "found-again"
  185. p1, p2 := "1234", "foobar"
  186. // make sure key works with initial password
  187. info, seed, err := cstore.Create(n1, p1, algo)
  188. require.Nil(err, "%+v", err)
  189. assert.Equal(n1, info.Name)
  190. assert.NotEmpty(seed)
  191. // now, let us delete this key
  192. err = cstore.Delete(n1, p1)
  193. require.Nil(err, "%+v", err)
  194. _, err = cstore.Get(n1)
  195. require.NotNil(err)
  196. // let us re-create it from the seed-phrase
  197. newInfo, err := cstore.Recover(n2, p2, seed)
  198. require.Nil(err, "%+v", err)
  199. assert.Equal(n2, newInfo.Name)
  200. assert.Equal(info.Address, newInfo.Address)
  201. assert.Equal(info.PubKey, newInfo.PubKey)
  202. }
  203. // func ExampleStore() {
  204. // // Select the encryption and storage for your cryptostore
  205. // cstore := cryptostore.New(
  206. // cryptostore.GenEd25519,
  207. // cryptostore.SecretBox,
  208. // // Note: use filestorage.New(dir) for real data
  209. // memstorage.New(),
  210. // )
  211. // // Add keys and see they return in alphabetical order
  212. // cstore.Create("Bob", "friend")
  213. // cstore.Create("Alice", "secret")
  214. // cstore.Create("Carl", "mitm")
  215. // info, _ := cstore.List()
  216. // for _, i := range info {
  217. // fmt.Println(i.Name)
  218. // }
  219. // // We need to use passphrase to generate a signature
  220. // tx := mock.NewSig([]byte("deadbeef"))
  221. // err := cstore.Sign("Bob", "friend", tx)
  222. // if err != nil {
  223. // fmt.Println("don't accept real passphrase")
  224. // }
  225. // // and we can validate the signature with publically available info
  226. // binfo, _ := cstore.Get("Bob")
  227. // sigs, err := tx.Signers()
  228. // if err != nil {
  229. // fmt.Println("badly signed")
  230. // } else if bytes.Equal(sigs[0].Bytes(), binfo.PubKey.Bytes()) {
  231. // fmt.Println("signed by Bob")
  232. // } else {
  233. // fmt.Println("signed by someone else")
  234. // }
  235. // // Output:
  236. // // Alice
  237. // // Bob
  238. // // Carl
  239. // // signed by Bob
  240. // }