|
package cryptostore
|
|
|
|
import (
|
|
"github.com/pkg/errors"
|
|
|
|
crypto "github.com/tendermint/go-crypto"
|
|
"github.com/tendermint/go-crypto/bcrypt"
|
|
)
|
|
|
|
var (
|
|
// SecretBox uses the algorithm from NaCL to store secrets securely
|
|
SecretBox Encoder = secretbox{}
|
|
// Noop doesn't do any encryption, should only be used in test code
|
|
Noop Encoder = noop{}
|
|
)
|
|
|
|
// Encoder is used to encrypt any key with a passphrase for storage.
|
|
//
|
|
// This should use a well-designed symetric encryption algorithm
|
|
type Encoder interface {
|
|
Encrypt(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error)
|
|
Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error)
|
|
}
|
|
|
|
type secretbox struct{}
|
|
|
|
func (e secretbox) Encrypt(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error) {
|
|
if passphrase == "" {
|
|
return nil, privKey.Bytes(), nil
|
|
}
|
|
|
|
saltBytes = crypto.CRandBytes(16)
|
|
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 14) // TODO parameterize. 14 is good today (2016)
|
|
if err != nil {
|
|
return nil, nil, errors.Wrap(err, "Couldn't generate bcrypt key from passphrase.")
|
|
}
|
|
key = crypto.Sha256(key) // Get 32 bytes
|
|
privKeyBytes := privKey.Bytes()
|
|
return saltBytes, crypto.EncryptSymmetric(privKeyBytes, key), nil
|
|
}
|
|
|
|
func (e secretbox) Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
|
|
privKeyBytes := encBytes
|
|
// NOTE: Some keys weren't encrypted with a passphrase and hence we have the conditional
|
|
if passphrase != "" {
|
|
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 14) // TODO parameterize. 14 is good today (2016)
|
|
if err != nil {
|
|
return crypto.PrivKey{}, errors.Wrap(err, "Invalid Passphrase")
|
|
}
|
|
key = crypto.Sha256(key) // Get 32 bytes
|
|
privKeyBytes, err = crypto.DecryptSymmetric(encBytes, key)
|
|
if err != nil {
|
|
return crypto.PrivKey{}, errors.Wrap(err, "Invalid Passphrase")
|
|
}
|
|
}
|
|
privKey, err = crypto.PrivKeyFromBytes(privKeyBytes)
|
|
if err != nil {
|
|
return crypto.PrivKey{}, errors.Wrap(err, "Couldn't get privKey from bytes")
|
|
}
|
|
return privKey, nil
|
|
}
|
|
|
|
type noop struct{}
|
|
|
|
func (n noop) Encrypt(key crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte, err error) {
|
|
return []byte{}, key.Bytes(), nil
|
|
}
|
|
|
|
func (n noop) Decrypt(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
|
|
return crypto.PrivKeyFromBytes(encBytes)
|
|
}
|