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.

300 lines
7.9 KiB

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