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.

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