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.

166 lines
4.5 KiB

  1. package cryptostore
  2. import (
  3. "strings"
  4. crypto "github.com/tendermint/go-crypto"
  5. keys "github.com/tendermint/go-crypto/keys"
  6. )
  7. // Manager combines encyption and storage implementation to provide
  8. // a full-featured key manager
  9. type Manager struct {
  10. es encryptedStorage
  11. codec keys.Codec
  12. }
  13. func New(coder Encoder, store keys.Storage, codec keys.Codec) Manager {
  14. return Manager{
  15. es: encryptedStorage{
  16. coder: coder,
  17. store: store,
  18. },
  19. codec: codec,
  20. }
  21. }
  22. // exists just to make sure we fulfill the Signer interface
  23. func (s Manager) assertSigner() keys.Signer {
  24. return s
  25. }
  26. // exists just to make sure we fulfill the Manager interface
  27. func (s Manager) assertKeyManager() keys.Manager {
  28. return s
  29. }
  30. // Create adds a new key to the storage engine, returning error if
  31. // another key already stored under this name
  32. //
  33. // algo must be a supported go-crypto algorithm: ed25519, secp256k1
  34. func (s Manager) Create(name, passphrase, algo string) (keys.Info, string, error) {
  35. gen, err := getGenerator(algo)
  36. if err != nil {
  37. return keys.Info{}, "", err
  38. }
  39. // 128-bits the the all the randomness we can make use of
  40. secret := crypto.CRandBytes(16)
  41. key := gen.Generate(secret)
  42. err = s.es.Put(name, passphrase, key)
  43. if err != nil {
  44. return keys.Info{}, "", err
  45. }
  46. seed, err := s.codec.BytesToWords(secret)
  47. phrase := strings.Join(seed, " ")
  48. return info(name, key), phrase, err
  49. }
  50. // Recover takes a seed phrase and tries to recover the private key.
  51. //
  52. // If the seed phrase is valid, it will create the private key and store
  53. // it under name, protected by passphrase.
  54. //
  55. // Result similar to New(), except it doesn't return the seed again...
  56. func (s Manager) Recover(name, passphrase, seedphrase string) (keys.Info, error) {
  57. words := strings.Split(strings.TrimSpace(seedphrase), " ")
  58. secret, err := s.codec.WordsToBytes(words)
  59. if err != nil {
  60. return keys.Info{}, err
  61. }
  62. // TODO: flag this???
  63. gen := GenEd25519
  64. // gen, err := getGenerator(algo)
  65. // if err != nil {
  66. // return keys.Info{}, "", err
  67. // }
  68. key := gen.Generate(secret)
  69. // d00d, it worked! create the bugger....
  70. err = s.es.Put(name, passphrase, key)
  71. return info(name, key), err
  72. }
  73. // List loads the keys from the storage and enforces alphabetical order
  74. func (s Manager) List() (keys.Infos, error) {
  75. res, err := s.es.List()
  76. res.Sort()
  77. return res, err
  78. }
  79. // Get returns the public information about one key
  80. func (s Manager) Get(name string) (keys.Info, error) {
  81. _, info, err := s.es.store.Get(name)
  82. return info, err
  83. }
  84. // Sign will modify the Signable in order to attach a valid signature with
  85. // this public key
  86. //
  87. // If no key for this name, or the passphrase doesn't match, returns an error
  88. func (s Manager) Sign(name, passphrase string, tx keys.Signable) error {
  89. key, _, err := s.es.Get(name, passphrase)
  90. if err != nil {
  91. return err
  92. }
  93. sig := key.Sign(tx.SignBytes())
  94. pubkey := key.PubKey()
  95. return tx.Sign(pubkey, sig)
  96. }
  97. // Export decodes the private key with the current password, encodes
  98. // it with a secure one-time password and generates a sequence that can be
  99. // Imported by another Manager
  100. //
  101. // This is designed to copy from one device to another, or provide backups
  102. // during version updates.
  103. func (s Manager) Export(name, oldpass, transferpass string) ([]byte, error) {
  104. key, _, err := s.es.Get(name, oldpass)
  105. if err != nil {
  106. return nil, err
  107. }
  108. res, err := s.es.coder.Encrypt(key, transferpass)
  109. return res, err
  110. }
  111. // Import accepts bytes generated by Export along with the same transferpass
  112. // If they are valid, it stores the password under the given name with the
  113. // new passphrase.
  114. func (s Manager) Import(name, newpass, transferpass string, data []byte) error {
  115. key, err := s.es.coder.Decrypt(data, transferpass)
  116. if err != nil {
  117. return err
  118. }
  119. return s.es.Put(name, newpass, key)
  120. }
  121. // Delete removes key forever, but we must present the
  122. // proper passphrase before deleting it (for security)
  123. func (s Manager) Delete(name, passphrase string) error {
  124. // verify we have the proper password before deleting
  125. _, _, err := s.es.Get(name, passphrase)
  126. if err != nil {
  127. return err
  128. }
  129. return s.es.Delete(name)
  130. }
  131. // Update changes the passphrase with which a already stored key is encoded.
  132. //
  133. // oldpass must be the current passphrase used for encoding, newpass will be
  134. // the only valid passphrase from this time forward
  135. func (s Manager) Update(name, oldpass, newpass string) error {
  136. key, _, err := s.es.Get(name, oldpass)
  137. if err != nil {
  138. return err
  139. }
  140. // we must delete first, as Putting over an existing name returns an error
  141. s.Delete(name, oldpass)
  142. return s.es.Put(name, newpass, key)
  143. }