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.

247 lines
7.2 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. package keys
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/pkg/errors"
  6. crypto "github.com/tendermint/go-crypto"
  7. dbm "github.com/tendermint/tmlibs/db"
  8. "github.com/tendermint/go-crypto/keys/words"
  9. "github.com/tendermint/go-crypto/nano"
  10. )
  11. // XXX Lets use go-crypto/bcrypt and ascii encoding directly in here without
  12. // further wrappers around a store or DB.
  13. // Copy functions from: https://github.com/tendermint/mintkey/blob/master/cmd/mintkey/common.go
  14. //
  15. // dbKeybase combines encyption and storage implementation to provide
  16. // a full-featured key manager
  17. type dbKeybase struct {
  18. db dbm.DB
  19. codec words.Codec
  20. }
  21. func New(db dbm.DB, codec words.Codec) dbKeybase {
  22. return dbKeybase{
  23. db: db,
  24. codec: codec,
  25. }
  26. }
  27. var _ Keybase = dbKeybase{}
  28. // Create generates a new key and persists it storage, encrypted using the passphrase.
  29. // It returns the generated seedphrase (mnemonic) and the key Info.
  30. // It returns an error if it fails to generate a key for the given algo type,
  31. // or if another key is already stored under the same name.
  32. func (kb dbKeybase) Create(name, passphrase, algo string) (string, Info, error) {
  33. // NOTE: secret is SHA256 hashed by secp256k1 and ed25519.
  34. // 16 byte secret corresponds to 12 BIP39 words.
  35. // XXX: Ledgers use 24 words now - should we ?
  36. secret := crypto.CRandBytes(16)
  37. key, err := generate(algo, secret)
  38. if err != nil {
  39. return "", Info{}, err
  40. }
  41. // encrypt and persist the key
  42. public := kb.writeKey(key, name, passphrase)
  43. // return the mnemonic phrase
  44. words, err := kb.codec.BytesToWords(secret)
  45. seedphrase := strings.Join(words, " ")
  46. return seedphrase, public, err
  47. }
  48. // Recover converts a seedphrase to a private key and persists it, encrypted with the given passphrase.
  49. // Functions like Create, but seedphrase is input not output.
  50. func (kb dbKeybase) Recover(name, passphrase, algo string, seedphrase string) (Info, error) {
  51. key, err := kb.SeedToPrivKey(algo, seedphrase)
  52. if err != nil {
  53. return Info{}, err
  54. }
  55. // Valid seedphrase. Encrypt key and persist to disk.
  56. public := kb.writeKey(key, name, passphrase)
  57. return public, nil
  58. }
  59. // SeedToPrivKey returns the private key corresponding to a seedphrase
  60. // without persisting the private key.
  61. // TODO: enable the keybase to just hold these in memory so we can sign without persisting (?)
  62. func (kb dbKeybase) SeedToPrivKey(algo, seedphrase string) (crypto.PrivKey, error) {
  63. words := strings.Split(strings.TrimSpace(seedphrase), " ")
  64. secret, err := kb.codec.WordsToBytes(words)
  65. if err != nil {
  66. return crypto.PrivKey{}, err
  67. }
  68. key, err := generate(algo, secret)
  69. if err != nil {
  70. return crypto.PrivKey{}, err
  71. }
  72. return key, nil
  73. }
  74. // List returns the keys from storage in alphabetical order.
  75. func (kb dbKeybase) List() ([]Info, error) {
  76. var res []Info
  77. iter := kb.db.Iterator(nil, nil)
  78. defer iter.Close()
  79. for ; iter.Valid(); iter.Next() {
  80. key := iter.Key()
  81. if isPub(key) {
  82. info, err := readInfo(iter.Value())
  83. if err != nil {
  84. return nil, err
  85. }
  86. res = append(res, info)
  87. }
  88. }
  89. return res, nil
  90. }
  91. // Get returns the public information about one key.
  92. func (kb dbKeybase) Get(name string) (Info, error) {
  93. bs := kb.db.Get(pubName(name))
  94. return readInfo(bs)
  95. }
  96. // Sign signs the msg with the named key.
  97. // It returns an error if the key doesn't exist or the decryption fails.
  98. // TODO: what if leddger fails ?
  99. func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig crypto.Signature, pk crypto.PubKey, err error) {
  100. var key crypto.PrivKey
  101. armorStr := kb.db.Get(privName(name))
  102. key, err = unarmorDecryptPrivKey(string(armorStr), passphrase)
  103. if err != nil {
  104. return
  105. }
  106. sig = key.Sign(msg)
  107. pk = key.PubKey()
  108. return
  109. }
  110. // Export decodes the private key with the current password, encrypts
  111. // it with a secure one-time password and generates an armored private key
  112. // that can be Imported by another dbKeybase.
  113. //
  114. // This is designed to copy from one device to another, or provide backups
  115. // during version updates.
  116. func (kb dbKeybase) Export(name, oldpass, transferpass string) ([]byte, error) {
  117. armorStr := kb.db.Get(privName(name))
  118. key, err := unarmorDecryptPrivKey(string(armorStr), oldpass)
  119. if err != nil {
  120. return nil, err
  121. }
  122. if transferpass == "" {
  123. return key.Bytes(), nil
  124. }
  125. armorBytes := encryptArmorPrivKey(key, transferpass)
  126. return []byte(armorBytes), nil
  127. }
  128. // Import accepts bytes generated by Export along with the same transferpass.
  129. // If they are valid, it stores the password under the given name with the
  130. // new passphrase.
  131. func (kb dbKeybase) Import(name, newpass, transferpass string, data []byte) (err error) {
  132. var key crypto.PrivKey
  133. if transferpass == "" {
  134. key, err = crypto.PrivKeyFromBytes(data)
  135. } else {
  136. key, err = unarmorDecryptPrivKey(string(data), transferpass)
  137. }
  138. if err != nil {
  139. return err
  140. }
  141. kb.writeKey(key, name, newpass)
  142. return nil
  143. }
  144. // Delete removes key forever, but we must present the
  145. // proper passphrase before deleting it (for security).
  146. func (kb dbKeybase) Delete(name, passphrase string) error {
  147. // verify we have the proper password before deleting
  148. bs := kb.db.Get(privName(name))
  149. _, err := unarmorDecryptPrivKey(string(bs), passphrase)
  150. if err != nil {
  151. return err
  152. }
  153. kb.db.DeleteSync(pubName(name))
  154. kb.db.DeleteSync(privName(name))
  155. return nil
  156. }
  157. // Update changes the passphrase with which an already stored key is encrypted.
  158. //
  159. // oldpass must be the current passphrase used for encryption, newpass will be
  160. // the only valid passphrase from this time forward.
  161. func (kb dbKeybase) Update(name, oldpass, newpass string) error {
  162. bs := kb.db.Get(privName(name))
  163. key, err := unarmorDecryptPrivKey(string(bs), oldpass)
  164. if err != nil {
  165. return err
  166. }
  167. // Generate the public bytes and the encrypted privkey
  168. public := info(name, key)
  169. private := encryptArmorPrivKey(key, newpass)
  170. // We must delete first, as Putting over an existing name returns an error.
  171. // Must be done atomically with the write or we could lose the key.
  172. batch := kb.db.NewBatch()
  173. batch.Delete(pubName(name))
  174. batch.Delete(privName(name))
  175. batch.Set(pubName(name), public.bytes())
  176. batch.Set(privName(name), []byte(private))
  177. batch.Write()
  178. return nil
  179. }
  180. //---------------------------------------------------------------------------------------
  181. func (kb dbKeybase) writeKey(priv crypto.PrivKey, name, passphrase string) Info {
  182. // Generate the public bytes and the encrypted privkey
  183. public := info(name, priv)
  184. private := encryptArmorPrivKey(priv, passphrase)
  185. // Write them both
  186. kb.db.SetSync(pubName(name), public.bytes())
  187. kb.db.SetSync(privName(name), []byte(private))
  188. return public
  189. }
  190. // TODO: use a `type TypeKeyAlgo string` (?)
  191. func generate(algo string, secret []byte) (crypto.PrivKey, error) {
  192. switch algo {
  193. case crypto.NameEd25519:
  194. return crypto.GenPrivKeyEd25519FromSecret(secret).Wrap(), nil
  195. case crypto.NameSecp256k1:
  196. return crypto.GenPrivKeySecp256k1FromSecret(secret).Wrap(), nil
  197. case nano.NameLedgerEd25519:
  198. return nano.NewPrivKeyLedgerEd25519()
  199. default:
  200. err := errors.Errorf("Cannot generate keys for algorithm: %s", algo)
  201. return crypto.PrivKey{}, err
  202. }
  203. }
  204. func pubName(name string) []byte {
  205. return []byte(fmt.Sprintf("%s.pub", name))
  206. }
  207. func privName(name string) []byte {
  208. return []byte(fmt.Sprintf("%s.priv", name))
  209. }
  210. func isPub(name []byte) bool {
  211. return strings.HasSuffix(string(name), ".pub")
  212. }