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.

251 lines
6.6 KiB

7 years ago
7 years ago
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. "github.com/tendermint/go-crypto/keys/words"
  8. dbm "github.com/tendermint/tmlibs/db"
  9. )
  10. // dbKeybase combines encyption and storage implementation to provide
  11. // a full-featured key manager
  12. type dbKeybase struct {
  13. db dbm.DB
  14. codec words.Codec
  15. }
  16. func New(db dbm.DB, codec words.Codec) dbKeybase {
  17. return dbKeybase{
  18. db: db,
  19. codec: codec,
  20. }
  21. }
  22. var _ Keybase = dbKeybase{}
  23. // Create generates a new key and persists it to storage, encrypted
  24. // using the passphrase. It returns the generated seedphrase
  25. // (mnemonic) and the key Info. It returns an error if it fails to
  26. // generate a key for the given algo type, or if another key is
  27. // already stored under the same name.
  28. func (kb dbKeybase) Create(name, passphrase string, algo CryptoAlgo) (Info, string, error) {
  29. // NOTE: secret is SHA256 hashed by secp256k1 and ed25519.
  30. // 16 byte secret corresponds to 12 BIP39 words.
  31. // XXX: Ledgers use 24 words now - should we ?
  32. secret := crypto.CRandBytes(16)
  33. priv, err := generate(algo, secret)
  34. if err != nil {
  35. return Info{}, "", err
  36. }
  37. // encrypt and persist the key
  38. info := kb.writeKey(priv, name, passphrase)
  39. // we append the type byte to the serialized secret to help with
  40. // recovery
  41. // ie [secret] = [type] + [secret]
  42. typ := cryptoAlgoToByte(algo)
  43. secret = append([]byte{typ}, secret...)
  44. // return the mnemonic phrase
  45. words, err := kb.codec.BytesToWords(secret)
  46. seed := strings.Join(words, " ")
  47. return info, seed, err
  48. }
  49. // Recover converts a seedphrase to a private key and persists it,
  50. // encrypted with the given passphrase. Functions like Create, but
  51. // seedphrase is input not output.
  52. func (kb dbKeybase) Recover(name, passphrase, seedphrase string) (Info, error) {
  53. words := strings.Split(strings.TrimSpace(seedphrase), " ")
  54. secret, err := kb.codec.WordsToBytes(words)
  55. if err != nil {
  56. return Info{}, err
  57. }
  58. // secret is comprised of the actual secret with the type
  59. // appended.
  60. // ie [secret] = [type] + [secret]
  61. typ, secret := secret[0], secret[1:]
  62. algo := byteToCryptoAlgo(typ)
  63. priv, err := generate(algo, secret)
  64. if err != nil {
  65. return Info{}, err
  66. }
  67. // encrypt and persist key.
  68. public := kb.writeKey(priv, name, passphrase)
  69. return public, err
  70. }
  71. // List returns the keys from storage in alphabetical order.
  72. func (kb dbKeybase) List() ([]Info, error) {
  73. var res []Info
  74. iter := kb.db.Iterator(nil, nil)
  75. defer iter.Close()
  76. for ; iter.Valid(); iter.Next() {
  77. // key := iter.Key()
  78. info, err := readInfo(iter.Value())
  79. if err != nil {
  80. return nil, err
  81. }
  82. res = append(res, info)
  83. }
  84. return res, nil
  85. }
  86. // Get returns the public information about one key.
  87. func (kb dbKeybase) Get(name string) (Info, error) {
  88. bs := kb.db.Get(infoKey(name))
  89. return readInfo(bs)
  90. }
  91. // Sign signs the msg with the named key.
  92. // It returns an error if the key doesn't exist or the decryption fails.
  93. func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig crypto.Signature, pub crypto.PubKey, err error) {
  94. info, err := kb.Get(name)
  95. if err != nil {
  96. return
  97. }
  98. if info.PrivKeyArmor == "" {
  99. err = fmt.Errorf("private key not available")
  100. return
  101. }
  102. priv, err := unarmorDecryptPrivKey(info.PrivKeyArmor, passphrase)
  103. if err != nil {
  104. return
  105. }
  106. sig = priv.Sign(msg)
  107. pub = priv.PubKey()
  108. return
  109. }
  110. func (kb dbKeybase) Export(name string) (armor string, err error) {
  111. bz := kb.db.Get(infoKey(name))
  112. if bz == nil {
  113. return "", errors.New("No key to export with name " + name)
  114. }
  115. return armorInfoBytes(bz), nil
  116. }
  117. // ExportPubKey returns public keys in ASCII armored format.
  118. // Retrieve a Info object by its name and return the public key in
  119. // a portable format.
  120. func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) {
  121. bz := kb.db.Get(infoKey(name))
  122. if bz == nil {
  123. return "", errors.New("No key to export with name " + name)
  124. }
  125. info, err := readInfo(bz)
  126. if err != nil {
  127. return
  128. }
  129. return armorPubKeyBytes(info.PubKey.Bytes()), nil
  130. }
  131. func (kb dbKeybase) Import(name string, armor string) (err error) {
  132. bz := kb.db.Get(infoKey(name))
  133. if len(bz) > 0 {
  134. return errors.New("Cannot overwrite data for name " + name)
  135. }
  136. infoBytes, err := unarmorInfoBytes(armor)
  137. if err != nil {
  138. return
  139. }
  140. kb.db.Set(infoKey(name), infoBytes)
  141. return nil
  142. }
  143. // ImportPubKey imports ASCII-armored public keys.
  144. // Store a new Info object holding a public key only, i.e. it will
  145. // not be possible to sign with it as it lacks the secret key.
  146. func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) {
  147. bz := kb.db.Get(infoKey(name))
  148. if len(bz) > 0 {
  149. return errors.New("Cannot overwrite data for name " + name)
  150. }
  151. pubBytes, err := unarmorPubKeyBytes(armor)
  152. if err != nil {
  153. return
  154. }
  155. pubKey, err := crypto.PubKeyFromBytes(pubBytes)
  156. if err != nil {
  157. return
  158. }
  159. kb.writePubKey(pubKey, name)
  160. return
  161. }
  162. // Delete removes key forever, but we must present the
  163. // proper passphrase before deleting it (for security).
  164. func (kb dbKeybase) Delete(name, passphrase string) error {
  165. // verify we have the proper password before deleting
  166. info, err := kb.Get(name)
  167. if err != nil {
  168. return err
  169. }
  170. _, err = unarmorDecryptPrivKey(info.PrivKeyArmor, passphrase)
  171. if err != nil {
  172. return err
  173. }
  174. kb.db.DeleteSync(infoKey(name))
  175. return nil
  176. }
  177. // Update changes the passphrase with which an already stored key is
  178. // encrypted.
  179. //
  180. // oldpass must be the current passphrase used for encryption,
  181. // newpass will be the only valid passphrase from this time forward.
  182. func (kb dbKeybase) Update(name, oldpass, newpass string) error {
  183. info, err := kb.Get(name)
  184. if err != nil {
  185. return err
  186. }
  187. key, err := unarmorDecryptPrivKey(info.PrivKeyArmor, oldpass)
  188. if err != nil {
  189. return err
  190. }
  191. kb.writeKey(key, name, newpass)
  192. return nil
  193. }
  194. func (kb dbKeybase) writePubKey(pub crypto.PubKey, name string) Info {
  195. // make Info
  196. info := newInfo(name, pub, "")
  197. // write them both
  198. kb.db.SetSync(infoKey(name), info.bytes())
  199. return info
  200. }
  201. func (kb dbKeybase) writeKey(priv crypto.PrivKey, name, passphrase string) Info {
  202. // generate the encrypted privkey
  203. privArmor := encryptArmorPrivKey(priv, passphrase)
  204. // make Info
  205. info := newInfo(name, priv.PubKey(), privArmor)
  206. // write them both
  207. kb.db.SetSync(infoKey(name), info.bytes())
  208. return info
  209. }
  210. func generate(algo CryptoAlgo, secret []byte) (crypto.PrivKey, error) {
  211. switch algo {
  212. case AlgoEd25519:
  213. return crypto.GenPrivKeyEd25519FromSecret(secret), nil
  214. case AlgoSecp256k1:
  215. return crypto.GenPrivKeySecp256k1FromSecret(secret), nil
  216. default:
  217. err := errors.Errorf("Cannot generate keys for algorithm: %s", algo)
  218. return nil, err
  219. }
  220. }
  221. func infoKey(name string) []byte {
  222. return []byte(fmt.Sprintf("%s.info", name))
  223. }