Authenticated, non-deterministic encryption for binary Ecto fields.
Each field uses AES-256-GCM with a fresh 96-bit IV. The authentication data
binds each ciphertext to its table and storage column. Moving a ciphertext to
another table or column therefore causes Encrypted.Error during
load.
Declare the type directly and make an explicit redaction decision. The secure
choice is redact: true:
field :email, Encrypted, redact: trueConfigure a runtime key ring and one active write key:
config :ecto_encrypted,
keys: %{
1 => {:system, "FIELD_ENCRYPTION_KEY_V1"},
2 => {:system, "FIELD_ENCRYPTION_KEY_V2"}
},
active_key_id: 2Encryption always uses the active key ID. Decryption selects a configured key
by the ID stored in the envelope. nil passes through unchanged.
This package does not make encrypted values queryable. Store an
ecto_blind_search index beside the encrypted field when the application
needs equality or bounded-prefix queries.
Schema compilation fails when a field omits :redact. An application can
set redact: false to allow plaintext in Ecto's derived Inspect output.
This option does not control logs that inspect or interpolate plaintext
directly.
Summary
Functions
Derives the raw 32-byte key for one table and storage column.
Generates a cryptographically random 32-byte master key as 64 lowercase hexadecimal digits.
Types
@type option() :: {:keys, %{optional(byte()) => key_source()}} | {:active_key_id, byte()} | {:key_context, {String.Chars.t(), String.Chars.t()}} | {:redact, boolean()}
Functions
@spec derive_key(binary(), String.Chars.t(), String.Chars.t()) :: binary()
Derives the raw 32-byte key for one table and storage column.
Applications normally let the Ecto type derive this key. This function exists for format verification and controlled migrations.
Example
iex> master_key = String.duplicate("00", 32)
iex> field_key = Encrypted.derive_key(master_key, "users", "email")
iex> byte_size(field_key)
32
@spec generate_key() :: binary()
Generates a cryptographically random 32-byte master key as 64 lowercase hexadecimal digits.
Example
iex> key = Encrypted.generate_key()
iex> byte_size(key)
64
iex> key =~ ~r/\A[0-9a-f]{64}\z/
true