crypto

package
v0.0.0-...-1779528 Latest Latest
Warning

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

Go to latest
Published: May 11, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package crypto defines the kernel-level cryptographic interfaces: KeyProvider, KeyHandle, ValueTransformer, and CurrentKeyIDProvider.

This package is the authoritative contract layer. Implementations (LocalAES, VaultTransit) live in runtime/crypto/ or adapters/*/.

runtime/crypto exposes interface type aliases to kernel/crypto so that runtime/crypto implementations (LocalAESKeyProvider, VaultTransitKeyProvider, keyProviderTransformer, NoopTransformer) type-check against the kernel contract. This is NOT a backwards-compatibility shim — kernel/crypto is the authoritative contract and external consumers should import it directly.

Breaking changes from pre-kernel split: AADForConfig helper moved to cells/configcore/internal/crypto; consumers must update imports from kcrypto.AADForConfig to configcrypto.AADForConfig. AAD formatting is configcore business logic (cell:{cellID}/key:{configKey} uses cellID and configKey which are configcore domain concepts), not a generic crypto contract.

kernel/crypto/ must not import runtime/, adapters/, or cells/ — it is the interface-only package for the adapters→kernel-only dependency rule.

ref: kubernetes/kubernetes staging/src/k8s.io/apiserver/pkg/storage/value/transformer.go ref: PR#200 R1a kernel/lifecycle layering pattern

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MatchKeyID

func MatchKeyID(handleID, edkKeyID string) error

MatchKeyID verifies that handleID and edkKeyID refer to the same provider and key version. Returns nil when they match, or a descriptive ErrKeyProviderDecryptFailed error when they do not.

Malformed input (including empty strings, missing version suffix, negative versions, or non-numeric version strings) is forwarded as ErrKeyProviderDecryptFailed from the underlying ParseKeyID call.

Callers SHOULD call MatchKeyID before decryption to prevent silent data corruption from misrouted key versions.

func ParseKeyID

func ParseKeyID(keyID string) (provider string, version int, err error)

ParseKeyID parses a key version identifier of the form "{provider}-v{N}" or "{provider}:v{N}" and returns the provider name and version number.

Both dash-separated (e.g. "local-aes-v1") and colon-separated (e.g. "vault-transit:v3") formats are supported. The provider is everything before the last "-vN" or ":vN" segment.

v0 is a valid version (used by LocalAES "local-aes-v0"). Negative versions (e.g. "local-aes-v-1") are rejected.

Returns ErrKeyProviderDecryptFailed on any parse error, including negative or non-numeric version strings.

Types

type CurrentKeyIDProvider

type CurrentKeyIDProvider interface {
	CurrentKeyID(ctx context.Context) (string, error)
}

CurrentKeyIDProvider is the optional extension interface for ValueTransformer implementations that can report their current key ID. Discovered at runtime via type assertion (`if c, ok := tr.(CurrentKeyIDProvider); ok { ... }`). A nil error with an empty string is reserved for "no key" (e.g. Noop); a non-empty string represents the active key version label used for staleness comparison against per-row stored key IDs.

type EncryptResult

type EncryptResult struct {
	// Ciphertext is the encrypted payload.
	Ciphertext []byte
	// Nonce is the per-encryption AEAD nonce. Crypto-active KeyHandle
	// implementations MUST generate fresh nonce material for every successful
	// Encrypt call.
	Nonce []byte
	// EDK is the encrypted data key or provider-specific wrapped key material.
	EDK []byte
	// KeyID is the encrypt-time key version identifier actually used to protect
	// the payload. Callers MUST persist this value alongside Ciphertext.
	KeyID string
}

EncryptResult is the named output of an encryption operation.

Returning a struct instead of positional values keeps KeyHandle and ValueTransformer aligned and prevents nonce/keyID/EDK tuple swaps at storage boundaries.

type KeyHandle

type KeyHandle interface {
	// ID returns the key version identifier (e.g. "local-aes-v1", "vault-transit:v3").
	ID() string

	// Encrypt encrypts plaintext under this key using the provided aad as
	// Additional Authenticated Data. Callers MUST persist the returned
	// EncryptResult.KeyID rather than reading handle.ID() after the call; this
	// eliminates the race between Current() and key rotation in backends like
	// VaultTransit. Mirrors k8s KMS v2 EncryptResponse.KeyID semantics.
	Encrypt(ctx context.Context, plaintext, aad []byte) (EncryptResult, error)

	// Decrypt decrypts ciphertext encrypted by this key. The aad must match
	// exactly what was provided to Encrypt; mismatched aad returns ErrDecryptFailed.
	//
	// nonce and edk may be nil for backends that embed these within ciphertext.
	Decrypt(ctx context.Context, ciphertext, nonce, edk, aad []byte) (plaintext []byte, err error)
}

KeyHandle is a thin handle for a specific key version. It provides the cryptographic primitives needed by ValueTransformer.

Contract:

  • Encrypt MUST generate a fresh nonce on every call (nonce uniqueness).
  • Decrypt MUST validate the aad; mismatched aad MUST return ErrDecryptFailed.
  • nonce and edk semantics are provider-specific. VaultTransit may return nil/empty slices because key material is managed server-side.
  • KeyID MUST reflect the KEK version actually used to wrap the data/DEK; for LocalAES this equals handle.ID(); for VaultTransit this is parsed from the wrapped DEK prefix "vault:vN:".
  • keyID is "verifiable metadata": callers SHOULD use MatchKeyID() to verify that a stored keyID matches the handle used for decryption. This prevents silent data corruption from misrouted key versions.

ref: hashicorp/vault sdk/helper/keysutil/policy.go@main:L127 (keyID version prefix) ref: kubernetes/kubernetes staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/

envelope/kmsv2/envelope.go@master (EncryptResponse.KeyID)

type KeyProvider

type KeyProvider interface {
	// Current returns the active KeyHandle for encrypting new values.
	// The returned handle's ID() is stored alongside the ciphertext so that
	// the correct key can be looked up during decryption.
	Current(ctx context.Context) (KeyHandle, error)

	// ByID returns the KeyHandle identified by keyID. Callers use this to
	// decrypt values encrypted by a previous key version.
	// Returns ErrKeyNotFound when the key is absent from the keyring.
	ByID(ctx context.Context, keyID string) (KeyHandle, error)

	// Rotate generates or activates a new key version. The previous key
	// remains in the keyring so that existing ciphertexts can still be
	// decrypted. Returns the new key's ID.
	Rotate(ctx context.Context) (newKeyID string, err error)
}

KeyProvider abstracts a KMS backend. Implementations must be safe for concurrent use.

ref: kubernetes/kubernetes staging/.../storage/value/transformer.go@master

type ValueTransformer

type ValueTransformer interface {
	// Encrypt encrypts plaintext under the current key.
	// EncryptResult.KeyID identifies the key version; store it alongside the
	// ciphertext so Decrypt can resolve the correct historical key on read.
	Encrypt(ctx context.Context, plaintext, aad []byte) (EncryptResult, error)

	// Decrypt decrypts ciphertext using the key identified by keyID.
	// Fail-closed: returns an error on any decryption failure; never returns
	// the raw ciphertext or an empty slice as a fallback.
	Decrypt(ctx context.Context, ciphertext []byte, keyID string, nonce, edk, aad []byte) (plaintext []byte, err error)
}

ValueTransformer is the caller-facing encryption interface for sensitive config values. It is a thin wrapper over KeyProvider that:

  • Uses the current key for Encrypt.
  • Uses ByID(keyID) for Decrypt so historical keys remain accessible.
  • Accepts pre-computed AAD so callers can bind ciphertext to the row's identity (preventing ciphertext transplant attacks).

Optional extension interface: implementations MAY also satisfy CurrentKeyIDProvider to expose the current key ID; this is used by the config repository to compute the Stale staleness signal for rotation-driven lazy re-encryption. NoopTransformer deliberately does not implement it (nothing to be stale against).

ref: kubernetes/kubernetes staging/.../storage/value/transformer.go@master

Jump to

Keyboard shortcuts

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