1c98152fa0
Shamir seals now come in two varieties: legacy and new-style. Legacy Shamir is automatically converted to new-style when a rekey operation is performed. All new Vault initializations using Shamir are new-style. New-style Shamir writes an encrypted master key to storage, just like AutoUnseal. The stored master key is encrypted using the shared key that is split via Shamir's algorithm. Thus when unsealing, we take the key fragments given, combine them into a Key-Encryption-Key, and use that to decrypt the master key on disk. Then the master key is used to read the keyring that decrypts the barrier.
115 lines
2.5 KiB
Go
115 lines
2.5 KiB
Go
package shamir
|
|
|
|
import (
|
|
"context"
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"errors"
|
|
"fmt"
|
|
|
|
log "github.com/hashicorp/go-hclog"
|
|
"github.com/hashicorp/go-uuid"
|
|
"github.com/hashicorp/vault/sdk/physical"
|
|
"github.com/hashicorp/vault/vault/seal"
|
|
)
|
|
|
|
// ShamirSeal implements the seal.Access interface for Shamir unseal
|
|
type ShamirSeal struct {
|
|
logger log.Logger
|
|
key []byte
|
|
aead cipher.AEAD
|
|
}
|
|
|
|
// Ensure that we are implementing AutoSealAccess
|
|
var _ seal.Access = (*ShamirSeal)(nil)
|
|
|
|
// NewSeal creates a new ShamirSeal with the provided logger
|
|
func NewSeal(logger log.Logger) *ShamirSeal {
|
|
seal := &ShamirSeal{
|
|
logger: logger,
|
|
}
|
|
return seal
|
|
}
|
|
|
|
func (s *ShamirSeal) GetKey() []byte {
|
|
return s.key
|
|
}
|
|
|
|
func (s *ShamirSeal) SetKey(key []byte) error {
|
|
aesCipher, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
aead, err := cipher.NewGCM(aesCipher)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
s.key = key
|
|
s.aead = aead
|
|
return nil
|
|
}
|
|
|
|
// Init is called during core.Initialize. No-op at the moment.
|
|
func (s *ShamirSeal) Init(_ context.Context) error {
|
|
return nil
|
|
}
|
|
|
|
// Finalize is called during shutdown. This is a no-op since
|
|
// ShamirSeal doesn't require any cleanup.
|
|
func (s *ShamirSeal) Finalize(_ context.Context) error {
|
|
return nil
|
|
}
|
|
|
|
// SealType returns the seal type for this particular seal implementation.
|
|
func (s *ShamirSeal) SealType() string {
|
|
return seal.Shamir
|
|
}
|
|
|
|
// KeyID returns the last known key id.
|
|
func (s *ShamirSeal) KeyID() string {
|
|
return ""
|
|
}
|
|
|
|
// Encrypt is used to encrypt the plaintext using the aead held by the seal.
|
|
func (s *ShamirSeal) Encrypt(_ context.Context, plaintext []byte) (*physical.EncryptedBlobInfo, error) {
|
|
if plaintext == nil {
|
|
return nil, fmt.Errorf("given plaintext for encryption is nil")
|
|
}
|
|
|
|
if s.aead == nil {
|
|
return nil, errors.New("aead is not configured in the seal")
|
|
}
|
|
|
|
iv, err := uuid.GenerateRandomBytes(12)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ciphertext := s.aead.Seal(nil, iv, plaintext, nil)
|
|
|
|
return &physical.EncryptedBlobInfo{
|
|
Ciphertext: append(iv, ciphertext...),
|
|
}, nil
|
|
}
|
|
|
|
func (s *ShamirSeal) Decrypt(_ context.Context, in *physical.EncryptedBlobInfo) ([]byte, error) {
|
|
if in == nil {
|
|
return nil, fmt.Errorf("given plaintext for encryption is nil")
|
|
}
|
|
|
|
if s.aead == nil {
|
|
return nil, errors.New("aead is not configured in the seal")
|
|
}
|
|
|
|
iv, ciphertext := in.Ciphertext[:12], in.Ciphertext[12:]
|
|
|
|
plaintext, err := s.aead.Open(nil, iv, ciphertext, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return plaintext, nil
|
|
}
|