131 lines
3.5 KiB
Go
131 lines
3.5 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package seal
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
metrics "github.com/armon/go-metrics"
|
|
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
|
)
|
|
|
|
type StoredKeysSupport int
|
|
|
|
const (
|
|
// The 0 value of StoredKeysSupport is an invalid option
|
|
StoredKeysInvalid StoredKeysSupport = iota
|
|
StoredKeysNotSupported
|
|
StoredKeysSupportedGeneric
|
|
StoredKeysSupportedShamirRoot
|
|
)
|
|
|
|
func (s StoredKeysSupport) String() string {
|
|
switch s {
|
|
case StoredKeysNotSupported:
|
|
return "Old-style Shamir"
|
|
case StoredKeysSupportedGeneric:
|
|
return "AutoUnseal"
|
|
case StoredKeysSupportedShamirRoot:
|
|
return "New-style Shamir"
|
|
default:
|
|
return "Invalid StoredKeys type"
|
|
}
|
|
}
|
|
|
|
// Access is the embedded implementation of autoSeal that contains logic
|
|
// specific to encrypting and decrypting data, or in this case keys.
|
|
type Access interface {
|
|
wrapping.Wrapper
|
|
wrapping.InitFinalizer
|
|
|
|
GetWrapper() wrapping.Wrapper
|
|
}
|
|
|
|
type access struct {
|
|
w wrapping.Wrapper
|
|
}
|
|
|
|
var _ Access = (*access)(nil)
|
|
|
|
func NewAccess(w wrapping.Wrapper) Access {
|
|
return &access{
|
|
w: w,
|
|
}
|
|
}
|
|
|
|
func (a *access) KeyId(ctx context.Context) (string, error) {
|
|
return a.w.KeyId(ctx)
|
|
}
|
|
|
|
func (a *access) SetConfig(ctx context.Context, options ...wrapping.Option) (*wrapping.WrapperConfig, error) {
|
|
return a.w.SetConfig(ctx, options...)
|
|
}
|
|
|
|
func (a *access) GetWrapper() wrapping.Wrapper {
|
|
return a.w
|
|
}
|
|
|
|
func (a *access) Init(ctx context.Context, options ...wrapping.Option) error {
|
|
if initWrapper, ok := a.w.(wrapping.InitFinalizer); ok {
|
|
return initWrapper.Init(ctx, options...)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (a *access) Type(ctx context.Context) (wrapping.WrapperType, error) {
|
|
return a.w.Type(ctx)
|
|
}
|
|
|
|
// Encrypt uses the underlying seal to encrypt the plaintext and returns it.
|
|
func (a *access) Encrypt(ctx context.Context, plaintext []byte, options ...wrapping.Option) (blob *wrapping.BlobInfo, err error) {
|
|
wTyp, err := a.w.Type(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer func(now time.Time) {
|
|
metrics.MeasureSince([]string{"seal", "encrypt", "time"}, now)
|
|
metrics.MeasureSince([]string{"seal", wTyp.String(), "encrypt", "time"}, now)
|
|
|
|
if err != nil {
|
|
metrics.IncrCounter([]string{"seal", "encrypt", "error"}, 1)
|
|
metrics.IncrCounter([]string{"seal", wTyp.String(), "encrypt", "error"}, 1)
|
|
}
|
|
}(time.Now())
|
|
|
|
metrics.IncrCounter([]string{"seal", "encrypt"}, 1)
|
|
metrics.IncrCounter([]string{"seal", wTyp.String(), "encrypt"}, 1)
|
|
|
|
return a.w.Encrypt(ctx, plaintext, options...)
|
|
}
|
|
|
|
// Decrypt uses the underlying seal to decrypt the cryptotext and returns it.
|
|
// Note that it is possible depending on the wrapper used that both pt and err
|
|
// are populated.
|
|
func (a *access) Decrypt(ctx context.Context, data *wrapping.BlobInfo, options ...wrapping.Option) (pt []byte, err error) {
|
|
wTyp, err := a.w.Type(ctx)
|
|
defer func(now time.Time) {
|
|
metrics.MeasureSince([]string{"seal", "decrypt", "time"}, now)
|
|
metrics.MeasureSince([]string{"seal", wTyp.String(), "decrypt", "time"}, now)
|
|
|
|
if err != nil {
|
|
metrics.IncrCounter([]string{"seal", "decrypt", "error"}, 1)
|
|
metrics.IncrCounter([]string{"seal", wTyp.String(), "decrypt", "error"}, 1)
|
|
}
|
|
}(time.Now())
|
|
|
|
metrics.IncrCounter([]string{"seal", "decrypt"}, 1)
|
|
metrics.IncrCounter([]string{"seal", wTyp.String(), "decrypt"}, 1)
|
|
|
|
return a.w.Decrypt(ctx, data, options...)
|
|
}
|
|
|
|
func (a *access) Finalize(ctx context.Context, options ...wrapping.Option) error {
|
|
if finalizeWrapper, ok := a.w.(wrapping.InitFinalizer); ok {
|
|
return finalizeWrapper.Finalize(ctx, options...)
|
|
}
|
|
return nil
|
|
}
|