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.

71 lines
2.4 KiB

  1. package cryptostore
  2. import (
  3. "github.com/pkg/errors"
  4. crypto "github.com/tendermint/go-crypto"
  5. "github.com/tendermint/go-crypto/bcrypt"
  6. )
  7. var (
  8. // SecretBox uses the algorithm from NaCL to store secrets securely
  9. SecretBox Encoder = secretbox{}
  10. // Noop doesn't do any encryption, should only be used in test code
  11. Noop Encoder = noop{}
  12. )
  13. // Encoder is used to encrypt any key with a passphrase for storage.
  14. //
  15. // This should use a well-designed symetric encryption algorithm
  16. type Encoder interface {
  17. Encrypt(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error)
  18. Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error)
  19. }
  20. type secretbox struct{}
  21. func (e secretbox) Encrypt(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error) {
  22. if passphrase == "" {
  23. return nil, privKey.Bytes(), nil
  24. }
  25. saltBytes = crypto.CRandBytes(16)
  26. key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 14) // TODO parameterize. 14 is good today (2016)
  27. if err != nil {
  28. return nil, nil, errors.Wrap(err, "Couldn't generate bcrypt key from passphrase.")
  29. }
  30. key = crypto.Sha256(key) // Get 32 bytes
  31. privKeyBytes := privKey.Bytes()
  32. return saltBytes, crypto.EncryptSymmetric(privKeyBytes, key), nil
  33. }
  34. func (e secretbox) Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
  35. privKeyBytes := encBytes
  36. // NOTE: Some keys weren't encrypted with a passphrase and hence we have the conditional
  37. if passphrase != "" {
  38. key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 14) // TODO parameterize. 14 is good today (2016)
  39. if err != nil {
  40. return crypto.PrivKey{}, errors.Wrap(err, "Invalid Passphrase")
  41. }
  42. key = crypto.Sha256(key) // Get 32 bytes
  43. privKeyBytes, err = crypto.DecryptSymmetric(encBytes, key)
  44. if err != nil {
  45. return crypto.PrivKey{}, errors.Wrap(err, "Invalid Passphrase")
  46. }
  47. }
  48. privKey, err = crypto.PrivKeyFromBytes(privKeyBytes)
  49. if err != nil {
  50. return crypto.PrivKey{}, errors.Wrap(err, "Couldn't get privKey from bytes")
  51. }
  52. return privKey, nil
  53. }
  54. type noop struct{}
  55. func (n noop) Encrypt(key crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error) {
  56. return []byte{}, key.Bytes(), nil
  57. }
  58. func (n noop) Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
  59. return crypto.PrivKeyFromBytes(encBytes)
  60. }