AwsEncryptionSdk.Cmm.Caching (AWS Encryption SDK v1.0.0)

View Source

Caching Cryptographic Materials Manager implementation.

The Caching CMM wraps another CMM and caches cryptographic materials to reduce expensive calls to key providers. It provides:

  • Performance: Caches generated data keys and EDKs
  • Security: Enforces key rotation via TTL and usage limits
  • Sharing: Multiple Caching CMMs can share cache via Partition IDs

Example

# Create cache
{:ok, cache} = LocalCache.start_link([])

# Create caching CMM with keyring
{:ok, keyring} = RawAes.new("ns", "key", key_bytes, :aes_256_gcm)
cmm = Caching.new_with_keyring(keyring, cache, max_age: 300)

# Or wrap an existing CMM
default_cmm = Default.new(keyring)
cmm = Caching.new(default_cmm, cache, max_age: 300)

Usage limits

Each cache entry tracks how many messages and plaintext bytes it has served. An entry is refreshed (fresh materials fetched and cached) rather than reused when serving the request would exceed max_messages or push the entry's cumulative bytes past max_bytes, so no entry ever serves more than max_bytes bytes. The one exception is a single request larger than max_bytes on its own: it is served once with fresh materials by design, and the entry is refreshed on the next request.

The byte limit is enforced against the request's :max_plaintext_length. AwsEncryptionSdk.Client.encrypt/3 sets it automatically from the plaintext size. Streaming callers must pass :plaintext_length to AwsEncryptionSdk.Stream.encrypt/3 when they know the total size; when a request carries no length, the byte limit cannot be enforced, so this CMM bypasses the cache entirely for that request (the underlying CMM is called and the result is not cached). Decryption is unaffected - usage limits are encrypt-only per the spec.

Spec Reference

https://github.com/awslabs/aws-encryption-sdk-specification/blob/master/framework/caching-cmm.md

Summary

Functions

Creates a new Caching CMM wrapping an existing CMM.

Creates a new Caching CMM from a keyring.

Types

cache()

t()

@type t() :: %AwsEncryptionSdk.Cmm.Caching{
  cache: cache(),
  max_age: pos_integer(),
  max_bytes: non_neg_integer(),
  max_messages: non_neg_integer(),
  partition_id: binary(),
  underlying_cmm: AwsEncryptionSdk.Cmm.Behaviour.t()
}

Functions

new(underlying_cmm, cache, opts)

Creates a new Caching CMM wrapping an existing CMM.

Parameters

  • underlying_cmm - The CMM to wrap (Default, RequiredEncryptionContext, etc.)
  • cache - A CMC implementation (e.g., LocalCache pid)
  • opts - Options:
    • :max_age - Required. TTL in seconds (must be > 0)
    • :partition_id - Optional. UUID for cache partitioning (auto-generated if omitted)
    • :max_bytes - Optional. Maximum bytes to encrypt per entry (default: 2^63-1)
    • :max_messages - Optional. Maximum messages per entry (default: 2^32)

Examples

iex> key = :crypto.strong_rand_bytes(32)
iex> {:ok, keyring} = AwsEncryptionSdk.Keyring.RawAes.new("ns", "key", key, :aes_256_gcm)
iex> default_cmm = AwsEncryptionSdk.Cmm.Default.new(keyring)
iex> {:ok, cache} = AwsEncryptionSdk.Cache.LocalCache.start_link([])
iex> cmm = AwsEncryptionSdk.Cmm.Caching.new(default_cmm, cache, max_age: 300)
iex> is_struct(cmm, AwsEncryptionSdk.Cmm.Caching)
true

new_with_keyring(keyring, cache, opts)

@spec new_with_keyring(AwsEncryptionSdk.Cmm.Default.keyring(), cache(), keyword()) ::
  t()

Creates a new Caching CMM from a keyring.

The keyring is automatically wrapped in a Default CMM.

Parameters

  • keyring - A keyring struct
  • cache - A CMC implementation
  • opts - Same as new/3

Examples

iex> key = :crypto.strong_rand_bytes(32)
iex> {:ok, keyring} = AwsEncryptionSdk.Keyring.RawAes.new("ns", "key", key, :aes_256_gcm)
iex> {:ok, cache} = AwsEncryptionSdk.Cache.LocalCache.start_link([])
iex> cmm = AwsEncryptionSdk.Cmm.Caching.new_with_keyring(keyring, cache, max_age: 300)
iex> is_struct(cmm, AwsEncryptionSdk.Cmm.Caching)
true