open-vault/vault/seal/envelope.go

73 lines
1.5 KiB
Go

package seal
import (
"crypto/aes"
"crypto/cipher"
"errors"
"time"
metrics "github.com/armon/go-metrics"
"github.com/hashicorp/errwrap"
uuid "github.com/hashicorp/go-uuid"
)
type Envelope struct{}
type EnvelopeInfo struct {
Ciphertext []byte
Key []byte
IV []byte
}
func NewEnvelope() *Envelope {
return &Envelope{}
}
func (e *Envelope) Encrypt(plaintext []byte) (*EnvelopeInfo, error) {
defer metrics.MeasureSince([]string{"seal", "envelope", "encrypt"}, time.Now())
// Generate DEK
key, err := uuid.GenerateRandomBytes(32)
if err != nil {
return nil, err
}
iv, err := uuid.GenerateRandomBytes(12)
if err != nil {
return nil, err
}
aead, err := e.aeadEncrypter(key)
if err != nil {
return nil, err
}
return &EnvelopeInfo{
Ciphertext: aead.Seal(nil, iv, plaintext, nil),
Key: key,
IV: iv,
}, nil
}
func (e *Envelope) Decrypt(data *EnvelopeInfo) ([]byte, error) {
defer metrics.MeasureSince([]string{"seal", "envelope", "decrypt"}, time.Now())
aead, err := e.aeadEncrypter(data.Key)
if err != nil {
return nil, err
}
return aead.Open(nil, data.IV, data.Ciphertext, nil)
}
func (e *Envelope) aeadEncrypter(key []byte) (cipher.AEAD, error) {
aesCipher, err := aes.NewCipher(key)
if err != nil {
return nil, errwrap.Wrapf("failed to create cipher: {{err}}", err)
}
// Create the GCM mode AEAD
gcm, err := cipher.NewGCM(aesCipher)
if err != nil {
return nil, errors.New("failed to initialize GCM mode")
}
return gcm, nil
}