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.

324 lines
8.8 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. "bufio"
  4. "fmt"
  5. "os"
  6. "strings"
  7. "github.com/pkg/errors"
  8. crypto "github.com/tendermint/go-crypto"
  9. "github.com/tendermint/go-crypto/keys/words"
  10. dbm "github.com/tendermint/tmlibs/db"
  11. )
  12. // dbKeybase combines encyption and storage implementation to provide
  13. // a full-featured key manager
  14. type dbKeybase struct {
  15. db dbm.DB
  16. codec words.Codec
  17. }
  18. func New(db dbm.DB, codec words.Codec) dbKeybase {
  19. return dbKeybase{
  20. db: db,
  21. codec: codec,
  22. }
  23. }
  24. var _ Keybase = dbKeybase{}
  25. // CreateMnemonic generates a new key and persists it to storage, encrypted
  26. // using the passphrase. It returns the generated seedphrase
  27. // (mnemonic) and the key Info. It returns an error if it fails to
  28. // generate a key for the given algo type, or if another key is
  29. // already stored under the same name.
  30. func (kb dbKeybase) CreateMnemonic(name, passphrase string, algo SignAlgo) (Info, string, error) {
  31. // NOTE: secret is SHA256 hashed by secp256k1 and ed25519.
  32. // 16 byte secret corresponds to 12 BIP39 words.
  33. // XXX: Ledgers use 24 words now - should we ?
  34. secret := crypto.CRandBytes(16)
  35. priv, err := generate(algo, secret)
  36. if err != nil {
  37. return nil, "", err
  38. }
  39. // encrypt and persist the key
  40. info := kb.writeLocalKey(priv, name, passphrase)
  41. // we append the type byte to the serialized secret to help with
  42. // recovery
  43. // ie [secret] = [type] + [secret]
  44. typ := cryptoAlgoToByte(algo)
  45. secret = append([]byte{typ}, secret...)
  46. // return the mnemonic phrase
  47. words, err := kb.codec.BytesToWords(secret)
  48. seed := strings.Join(words, " ")
  49. return info, seed, err
  50. }
  51. // CreateLedger creates a new locally-stored reference to a Ledger keypair
  52. // It returns the created key info and an error if the Ledger could not be queried
  53. func (kb dbKeybase) CreateLedger(name string, path crypto.DerivationPath, algo SignAlgo) (Info, error) {
  54. if algo != AlgoSecp256k1 {
  55. return nil, fmt.Errorf("Only secp256k1 is supported for Ledger devices")
  56. }
  57. priv, err := crypto.NewPrivKeyLedgerSecp256k1(path)
  58. if err != nil {
  59. return nil, err
  60. }
  61. pub := priv.PubKey()
  62. return kb.writeLedgerKey(pub, path, name), nil
  63. }
  64. // CreateOffline creates a new reference to an offline keypair
  65. // It returns the created key info
  66. func (kb dbKeybase) CreateOffline(name string, pub crypto.PubKey) (Info, error) {
  67. return kb.writeOfflineKey(pub, name), nil
  68. }
  69. // Recover converts a seedphrase to a private key and persists it,
  70. // encrypted with the given passphrase. Functions like Create, but
  71. // seedphrase is input not output.
  72. func (kb dbKeybase) Recover(name, passphrase, seedphrase string) (Info, error) {
  73. words := strings.Split(strings.TrimSpace(seedphrase), " ")
  74. secret, err := kb.codec.WordsToBytes(words)
  75. if err != nil {
  76. return nil, err
  77. }
  78. // secret is comprised of the actual secret with the type
  79. // appended.
  80. // ie [secret] = [type] + [secret]
  81. typ, secret := secret[0], secret[1:]
  82. algo := byteToSignAlgo(typ)
  83. priv, err := generate(algo, secret)
  84. if err != nil {
  85. return nil, err
  86. }
  87. // encrypt and persist key.
  88. public := kb.writeLocalKey(priv, name, passphrase)
  89. return public, nil
  90. }
  91. // List returns the keys from storage in alphabetical order.
  92. func (kb dbKeybase) List() ([]Info, error) {
  93. var res []Info
  94. iter := kb.db.Iterator(nil, nil)
  95. defer iter.Close()
  96. for ; iter.Valid(); iter.Next() {
  97. info, err := readInfo(iter.Value())
  98. if err != nil {
  99. return nil, err
  100. }
  101. res = append(res, info)
  102. }
  103. return res, nil
  104. }
  105. // Get returns the public information about one key.
  106. func (kb dbKeybase) Get(name string) (Info, error) {
  107. bs := kb.db.Get(infoKey(name))
  108. return readInfo(bs)
  109. }
  110. // Sign signs the msg with the named key.
  111. // It returns an error if the key doesn't exist or the decryption fails.
  112. func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig crypto.Signature, pub crypto.PubKey, err error) {
  113. info, err := kb.Get(name)
  114. if err != nil {
  115. return
  116. }
  117. var priv crypto.PrivKey
  118. switch info.(type) {
  119. case localInfo:
  120. linfo := info.(localInfo)
  121. if linfo.PrivKeyArmor == "" {
  122. err = fmt.Errorf("private key not available")
  123. return
  124. }
  125. priv, err = unarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase)
  126. if err != nil {
  127. return nil, nil, err
  128. }
  129. case ledgerInfo:
  130. linfo := info.(ledgerInfo)
  131. priv, err = crypto.NewPrivKeyLedgerSecp256k1(linfo.Path)
  132. if err != nil {
  133. return
  134. }
  135. case offlineInfo:
  136. linfo := info.(offlineInfo)
  137. fmt.Printf("Bytes to sign:\n%s", msg)
  138. buf := bufio.NewReader(os.Stdin)
  139. fmt.Printf("\nEnter Amino-encoded signature:\n")
  140. // Will block until user inputs the signature
  141. signed, err := buf.ReadString('\n')
  142. if err != nil {
  143. return nil, nil, err
  144. }
  145. cdc.MustUnmarshalBinary([]byte(signed), sig)
  146. return sig, linfo.GetPubKey(), nil
  147. }
  148. sig, err = priv.Sign(msg)
  149. if err != nil {
  150. return nil, nil, err
  151. }
  152. pub = priv.PubKey()
  153. return sig, pub, nil
  154. }
  155. func (kb dbKeybase) Export(name string) (armor string, err error) {
  156. bz := kb.db.Get(infoKey(name))
  157. if bz == nil {
  158. return "", errors.New("No key to export with name " + name)
  159. }
  160. return armorInfoBytes(bz), nil
  161. }
  162. // ExportPubKey returns public keys in ASCII armored format.
  163. // Retrieve a Info object by its name and return the public key in
  164. // a portable format.
  165. func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) {
  166. bz := kb.db.Get(infoKey(name))
  167. if bz == nil {
  168. return "", errors.New("No key to export with name " + name)
  169. }
  170. info, err := readInfo(bz)
  171. if err != nil {
  172. return
  173. }
  174. return armorPubKeyBytes(info.GetPubKey().Bytes()), nil
  175. }
  176. func (kb dbKeybase) Import(name string, armor string) (err error) {
  177. bz := kb.db.Get(infoKey(name))
  178. if len(bz) > 0 {
  179. return errors.New("Cannot overwrite data for name " + name)
  180. }
  181. infoBytes, err := unarmorInfoBytes(armor)
  182. if err != nil {
  183. return
  184. }
  185. kb.db.Set(infoKey(name), infoBytes)
  186. return nil
  187. }
  188. // ImportPubKey imports ASCII-armored public keys.
  189. // Store a new Info object holding a public key only, i.e. it will
  190. // not be possible to sign with it as it lacks the secret key.
  191. func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) {
  192. bz := kb.db.Get(infoKey(name))
  193. if len(bz) > 0 {
  194. return errors.New("Cannot overwrite data for name " + name)
  195. }
  196. pubBytes, err := unarmorPubKeyBytes(armor)
  197. if err != nil {
  198. return
  199. }
  200. pubKey, err := crypto.PubKeyFromBytes(pubBytes)
  201. if err != nil {
  202. return
  203. }
  204. kb.writeOfflineKey(pubKey, name)
  205. return
  206. }
  207. // Delete removes key forever, but we must present the
  208. // proper passphrase before deleting it (for security).
  209. // A passphrase of 'yes' is used to delete stored
  210. // references to offline and Ledger / HW wallet keys
  211. func (kb dbKeybase) Delete(name, passphrase string) error {
  212. // verify we have the proper password before deleting
  213. info, err := kb.Get(name)
  214. if err != nil {
  215. return err
  216. }
  217. switch info.(type) {
  218. case localInfo:
  219. linfo := info.(localInfo)
  220. _, err = unarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase)
  221. if err != nil {
  222. return err
  223. }
  224. kb.db.DeleteSync(infoKey(name))
  225. return nil
  226. case ledgerInfo:
  227. case offlineInfo:
  228. if passphrase != "yes" {
  229. return fmt.Errorf("enter exactly 'yes' to delete the key")
  230. }
  231. kb.db.DeleteSync(infoKey(name))
  232. return nil
  233. }
  234. return nil
  235. }
  236. // Update changes the passphrase with which an already stored key is
  237. // encrypted.
  238. //
  239. // oldpass must be the current passphrase used for encryption,
  240. // newpass will be the only valid passphrase from this time forward.
  241. func (kb dbKeybase) Update(name, oldpass, newpass string) error {
  242. info, err := kb.Get(name)
  243. if err != nil {
  244. return err
  245. }
  246. switch info.(type) {
  247. case localInfo:
  248. linfo := info.(localInfo)
  249. key, err := unarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
  250. if err != nil {
  251. return err
  252. }
  253. kb.writeLocalKey(key, name, newpass)
  254. return nil
  255. default:
  256. return fmt.Errorf("Locally stored key required")
  257. }
  258. }
  259. func (kb dbKeybase) writeLocalKey(priv crypto.PrivKey, name, passphrase string) Info {
  260. // encrypt private key using passphrase
  261. privArmor := encryptArmorPrivKey(priv, passphrase)
  262. // make Info
  263. pub := priv.PubKey()
  264. info := newLocalInfo(name, pub, privArmor)
  265. kb.writeInfo(info, name)
  266. return info
  267. }
  268. func (kb dbKeybase) writeLedgerKey(pub crypto.PubKey, path crypto.DerivationPath, name string) Info {
  269. info := newLedgerInfo(name, pub, path)
  270. kb.writeInfo(info, name)
  271. return info
  272. }
  273. func (kb dbKeybase) writeOfflineKey(pub crypto.PubKey, name string) Info {
  274. info := newOfflineInfo(name, pub)
  275. kb.writeInfo(info, name)
  276. return info
  277. }
  278. func (kb dbKeybase) writeInfo(info Info, name string) {
  279. // write the info by key
  280. kb.db.SetSync(infoKey(name), writeInfo(info))
  281. }
  282. func generate(algo SignAlgo, secret []byte) (crypto.PrivKey, error) {
  283. switch algo {
  284. case AlgoEd25519:
  285. return crypto.GenPrivKeyEd25519FromSecret(secret), nil
  286. case AlgoSecp256k1:
  287. return crypto.GenPrivKeySecp256k1FromSecret(secret), nil
  288. default:
  289. err := errors.Errorf("Cannot generate keys for algorithm: %s", algo)
  290. return nil, err
  291. }
  292. }
  293. func infoKey(name string) []byte {
  294. return []byte(fmt.Sprintf("%s.info", name))
  295. }