crypto

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package crypto implements envelope encryption.

Data is encrypted with a Data Encryption Key (DEK) using AES-256-GCM. Each DEK is in turn encrypted ("wrapped") by a Key Encryption Key (KEK), typically customer-managed and backed by a cloud KMS. The wrapped DEK and the ID of the KEK that wrapped it are carried together as DEKMaterial, allowing the DEK to be recovered and the data decrypted later.

A KEKRegistry manages the set of available KEKs, selecting the appropriate key by namespace for encryption and by key ID for decryption.

Index

Constants

This section is empty.

Variables

View Source
var ErrMalformedCipherText = errors.New("invalid ciphertext, not encrypted with a DEK")

ErrMalformedCipherText indicates that the ciphertext was not created by a call to Encrypt, or that it was otherwise tampered with.

Functions

This section is empty.

Types

type CacheEvent

type CacheEvent struct {
	// Size is the number of entries in the DEK cache after the access.
	Size int
}

CacheEvent describes a DEK cache access. Fields may be added over time without breaking implementers, so callers accept the struct by value.

type DEK

type DEK struct {
	// contains filtered or unexported fields
}

DEK defines a Data Encryption Key used to encrypt/decrypt payloads.

func NewDEK

func NewDEK() (*DEK, error)

NewDEK generates a new random 256-bit Data Encryption Key.

func (*DEK) Decrypt

func (d *DEK) Decrypt(ctx context.Context, ct []byte) ([]byte, error)

Decrypt decrypts the ciphertext ct using AES-256-GCM. The ciphertext must be prefixed with the nonce, as produced by DEK.Encrypt.

func (*DEK) Encrypt

func (d *DEK) Encrypt(ctx context.Context, pt []byte) ([]byte, error)

Encrypt encrypts the plaintext pt using AES-256-GCM. The returned ciphertext is prefixed with the randomly generated nonce.

type DEKMaterial

type DEKMaterial struct {
	Version      byte
	KEKID        string // The ID/URI of the KEK the encrypted the DEK.
	EncryptedDEK string // The base64-encoded encrypted DEK.
}

DEKMaterial defines the material needed in order to decrypt a payload.

type KEK

type KEK interface {
	io.Closer

	// ID returns a unique ID for this KEK, e.g. a KMS ARN.
	ID() string
	// Encrypt encrypts a DEK, returning the ciphertext.
	Encrypt(context.Context, []byte) ([]byte, error)
	// Decrypt decrypts a DEK previously produced by Encrypt.
	Decrypt(context.Context, []byte) ([]byte, error)
}

KEK defines an interface for a Key Encryption Keys. These keys are used to encrypt/decrypt DEKs and are customer-managed (e.g. via AWS/GCP KMS).

type KEKRegistry

type KEKRegistry struct {
	// contains filtered or unexported fields
}

KEKRegistry holds the set of KEKs available for encrypting and decrypting DEKs. It is keyed by namespace (for encryption) and by key ID (for decryption). Close must be called when the registry is no longer needed to release KEK resources.

func NewKEKRegistry

func NewKEKRegistry(opts ...KEKRegistryOption) (*KEKRegistry, error)

NewKEKRegistry constructs a KEKRegistry, applying opts in order. A default key is required (see WithDefaultKey); construction fails if one is not provided. The key-ID index used by Decrypt is built after all options are applied.

func (*KEKRegistry) Close

func (r *KEKRegistry) Close() error

Close closes all registered KEKs and releases their resources. Subsequent calls return the same error as the first call.

func (*KEKRegistry) Decrypt

func (r *KEKRegistry) Decrypt(ctx context.Context, m *DEKMaterial) (*DEK, error)

Decrypt decrypts the DEK described by m using the KEK identified by m.KEKID.

func (*KEKRegistry) Encrypt

func (r *KEKRegistry) Encrypt(ctx context.Context, ns string, dek *DEK) (*DEKMaterial, error)

Encrypt encrypts the given DEK using the KEK registered for the specified namespace. It returns DEKMaterial containing the KEK ID and the base64-encoded ciphertext.

type KEKRegistryOption

type KEKRegistryOption interface {
	// contains filtered or unexported methods
}

KEKRegistryOption configures a KEKRegistry during construction.

func WithDecryptOnlyKey

func WithDecryptOnlyKey(k KEK) KEKRegistryOption

WithDecryptOnlyKey registers k for decryption only. It is added to the key-ID index so that DEKs encrypted with k can still be opened, but k is never selected for new DEK encryption. This is typically used for keys that have been rotated out of active use.

func WithDefaultKey

func WithDefaultKey(k KEK) KEKRegistryOption

WithDefaultKey sets the fallback KEK used when no namespace-specific key is registered. A default key is required: NewKEKRegistry returns an error if one is not provided.

func WithKeyForNamespace

func WithKeyForNamespace(ns string, k KEK) KEKRegistryOption

WithKeyForNamespace registers k for ns, used when encrypting or decrypting DEKs for that namespace.

type KeyConfig

type KeyConfig struct {
	// Duration is how long a DEK is valid before it must be rotated.
	Duration time.Duration
	// RenewBefore causes a DEK to be treated as expired this long before
	// Duration elapses, so it can be rotated ahead of its actual expiry.
	RenewBefore time.Duration
}

KeyConfig controls the lifetime of a namespace's DEK.

type Message

type Message struct {
	Ciphertext  []byte
	KeyMaterial *DEKMaterial
}

Message is the result of sealing plaintext: the AES-256-GCM ciphertext together with the wrapped DEK (DEKMaterial) required to open it.

type NamespacedVault

type NamespacedVault struct {
	// contains filtered or unexported fields
}

NamespacedVault is a Vault bound to a single namespace so callers can Seal and Open without passing the namespace on every call. Obtain one via Vault.ForNamespace.

func (*NamespacedVault) Open

func (v *NamespacedVault) Open(ctx context.Context, msg *Message) ([]byte, error)

Open decrypts msg within the bound namespace. See Vault.Open.

func (*NamespacedVault) Seal

func (v *NamespacedVault) Seal(ctx context.Context, data []byte) (*Message, error)

Seal encrypts data within the bound namespace. See Vault.Seal.

type Observer

type Observer interface {
	CacheHit(CacheEvent)
	CacheMiss(CacheEvent)
}

Observer receives notifications about Vault-internal events for telemetry. Implementations must be safe for concurrent use and must not block: a Vault calls these on the Open path. A nil Observer is never used; the Vault substitutes a no-op (see WithObserver).

type Vault

type Vault struct {
	// contains filtered or unexported fields
}

Vault provides envelope encryption scoped by namespace. It keeps a sliding Data Encryption Key (DEK) per namespace, wrapping each DEK with the KEK selected for that namespace by a KEKRegistry. DEKs are rotated on a sliding schedule (see KeyConfig) and decrypted DEKs are cached to avoid repeated KMS calls on Open. A Vault is safe for concurrent use.

func NewVault

func NewVault(r *KEKRegistry, opts ...VaultOption) (*Vault, error)

NewVault constructs a Vault backed by r, applying opts in order. A DEK is pre-generated for every namespace registered via WithKeyConfig. NewVault returns an error if any option is invalid (for example, a duplicate namespace config) or if key/cache setup fails.

func (*Vault) ForNamespace

func (v *Vault) ForNamespace(ns string) *NamespacedVault

ForNamespace returns a NamespacedVault that seals and opens within ns.

func (*Vault) Open

func (v *Vault) Open(ctx context.Context, msg *Message) ([]byte, error)

Open decrypts msg, which must have been produced by Vault.Seal (or NamespacedVault.Seal). The wrapped DEK is unwrapped via the KEKRegistry using the KEK identified by the material carried in msg, served from the decrypted-DEK cache when it is enabled.

func (*Vault) Refresh

func (v *Vault) Refresh() error

Refresh rotates every namespace DEK that has reached its renewal threshold. It is meant to be called periodically. Seal also rotates an expired DEK on demand, so Refresh is an optimization that keeps rotation off the request path rather than a correctness requirement.

func (*Vault) Seal

func (v *Vault) Seal(ctx context.Context, ns string, data []byte) (*Message, error)

Seal encrypts data for ns, returning the ciphertext together with the wrapped DEK required to Open it. The active DEK for ns is created or rotated on demand. Concurrent first-time seals holding the same DEK are coalesced into a single KEK (KMS) call.

type VaultOption

type VaultOption func(*vaultOptions)

VaultOption configures a Vault during construction.

func WithCacheSize

func WithCacheSize(n int) VaultOption

WithCacheSize sets the maximum number of decrypted DEKs retained in the Open cache. A value of zero or less disables the cache, so every Open unwraps its DEK via the KEKRegistry.

func WithDefaultKeyConfig

func WithDefaultKeyConfig(cfg KeyConfig) VaultOption

WithDefaultKeyConfig sets the KeyConfig used for namespaces that have no explicit WithKeyConfig. Without a default, sealing an unconfigured namespace fails; with one, a DEK is created for such namespaces on first use.

func WithKeyConfig

func WithKeyConfig(ns string, cfg KeyConfig) VaultOption

WithKeyConfig sets the KeyConfig for a specific namespace. Registering the same namespace more than once is an error surfaced by NewVault.

func WithNowFunc

func WithNowFunc(fn func() time.Time) VaultOption

WithNowFunc overrides the clock used to evaluate DEK expiry. It is primarily useful in tests. A nil function is rejected by NewVault.

func WithObserver

func WithObserver(o Observer) VaultOption

WithObserver sets the Observer notified of Vault-internal events such as DEK cache hits and misses. A nil Observer is replaced with a no-op, so Open never needs to nil-check. Without this option no events are emitted.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL