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 ¶
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 ¶
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 ¶
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