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.

99 lines
2.9 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. blockTypeKeyInfo = "TENDERMINT KEY INFO"
  12. )
  13. func armorInfoBytes(bz []byte) string {
  14. header := map[string]string{
  15. "type": "Info",
  16. "version": "0.0.0",
  17. }
  18. armorStr := crypto.EncodeArmor(blockTypeKeyInfo, header, bz)
  19. return armorStr
  20. }
  21. func unarmorInfoBytes(armorStr string) (bz []byte, err error) {
  22. blockType, header, bz, err := crypto.DecodeArmor(armorStr)
  23. if err != nil {
  24. return
  25. }
  26. if blockType != blockTypeKeyInfo {
  27. err = fmt.Errorf("Unrecognized armor type: %v", blockType)
  28. return
  29. }
  30. if header["version"] != "0.0.0" {
  31. err = fmt.Errorf("Unrecognized version: %v", header["version"])
  32. return
  33. }
  34. return
  35. }
  36. func encryptArmorPrivKey(privKey crypto.PrivKey, passphrase string) string {
  37. saltBytes, encBytes := encryptPrivKey(privKey, passphrase)
  38. header := map[string]string{
  39. "kdf": "bcrypt",
  40. "salt": fmt.Sprintf("%X", saltBytes),
  41. }
  42. armorStr := crypto.EncodeArmor(blockTypePrivKey, header, encBytes)
  43. return armorStr
  44. }
  45. func unarmorDecryptPrivKey(armorStr string, passphrase string) (crypto.PrivKey, error) {
  46. var privKey crypto.PrivKey
  47. blockType, header, encBytes, err := crypto.DecodeArmor(armorStr)
  48. if err != nil {
  49. return privKey, err
  50. }
  51. if blockType != blockTypePrivKey {
  52. return privKey, fmt.Errorf("Unrecognized armor type: %v", blockType)
  53. }
  54. if header["kdf"] != "bcrypt" {
  55. return privKey, fmt.Errorf("Unrecognized KDF type: %v", header["KDF"])
  56. }
  57. if header["salt"] == "" {
  58. return privKey, fmt.Errorf("Missing salt bytes")
  59. }
  60. saltBytes, err := hex.DecodeString(header["salt"])
  61. if err != nil {
  62. return privKey, fmt.Errorf("Error decoding salt: %v", err.Error())
  63. }
  64. privKey, err = decryptPrivKey(saltBytes, encBytes, passphrase)
  65. return privKey, err
  66. }
  67. func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) {
  68. saltBytes = crypto.CRandBytes(16)
  69. key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 12) // TODO parameterize. 12 is good today (2016)
  70. if err != nil {
  71. cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error())
  72. }
  73. key = crypto.Sha256(key) // Get 32 bytes
  74. privKeyBytes := privKey.Bytes()
  75. return saltBytes, crypto.EncryptSymmetric(privKeyBytes, key)
  76. }
  77. func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
  78. key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 12) // TODO parameterize. 12 is good today (2016)
  79. if err != nil {
  80. cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error())
  81. }
  82. key = crypto.Sha256(key) // Get 32 bytes
  83. privKeyBytes, err := crypto.DecryptSymmetric(encBytes, key)
  84. if err != nil {
  85. return privKey, err
  86. }
  87. privKey, err = crypto.PrivKeyFromBytes(privKeyBytes)
  88. return privKey, err
  89. }