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.

73 lines
2.3 KiB

  1. package keys
  2. import (
  3. "encoding/hex"
  4. "fmt"
  5. cmn "github.com/tendermint/tmlibs/common"
  6. "github.com/tendermint/go-crypto"
  7. "github.com/tendermint/go-crypto/keys/bcrypt"
  8. )
  9. const (
  10. blockTypePrivKey = "TENDERMINT PRIVATE KEY"
  11. )
  12. func encryptArmorPrivKey(privKey crypto.PrivKey, passphrase string) string {
  13. saltBytes, encBytes := encryptPrivKey(privKey, passphrase)
  14. header := map[string]string{
  15. "kdf": "bcrypt",
  16. "salt": fmt.Sprintf("%X", saltBytes),
  17. }
  18. armorStr := crypto.EncodeArmor(blockTypePrivKey, header, encBytes)
  19. return armorStr
  20. }
  21. func unarmorDecryptPrivKey(armorStr string, passphrase string) (crypto.PrivKey, error) {
  22. var privKey crypto.PrivKey
  23. blockType, header, encBytes, err := crypto.DecodeArmor(armorStr)
  24. if err != nil {
  25. return privKey, err
  26. }
  27. if blockType != blockTypePrivKey {
  28. return privKey, fmt.Errorf("Unrecognized armor type: %v", blockType)
  29. }
  30. if header["kdf"] != "bcrypt" {
  31. return privKey, fmt.Errorf("Unrecognized KDF type: %v", header["KDF"])
  32. }
  33. if header["salt"] == "" {
  34. return privKey, fmt.Errorf("Missing salt bytes")
  35. }
  36. saltBytes, err := hex.DecodeString(header["salt"])
  37. if err != nil {
  38. return privKey, fmt.Errorf("Error decoding salt: %v", err.Error())
  39. }
  40. privKey, err = decryptPrivKey(saltBytes, encBytes, passphrase)
  41. return privKey, err
  42. }
  43. func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) {
  44. saltBytes = crypto.CRandBytes(16)
  45. key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 12) // TODO parameterize. 12 is good today (2016)
  46. if err != nil {
  47. cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error())
  48. }
  49. key = crypto.Sha256(key) // Get 32 bytes
  50. privKeyBytes := privKey.Bytes()
  51. return saltBytes, crypto.EncryptSymmetric(privKeyBytes, key)
  52. }
  53. func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
  54. key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 12) // TODO parameterize. 12 is good today (2016)
  55. if err != nil {
  56. cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error())
  57. }
  58. key = crypto.Sha256(key) // Get 32 bytes
  59. privKeyBytes, err := crypto.DecryptSymmetric(encBytes, key)
  60. if err != nil {
  61. return privKey, err
  62. }
  63. privKey, err = crypto.PrivKeyFromBytes(privKeyBytes)
  64. return privKey, err
  65. }