# `Macaw.Auth.Native.Seal`
[🔗](https://github.com/dcoai/macaw_auth/blob/v0.4.1/lib/macaw/auth/native/seal.ex#L1)

Sealing at rest: what the native backend stores that must not be read
back from the table (a TOTP secret) is sealed with AES-256-GCM, OTP's
`:crypto`, under a key from the configuration (`sealing_key:`,
`Macaw.Auth.Native.Config`).

- **The key.** `sealing_key` is a binary of at least 32 bytes, or
  `{module, function, args}` returning one, called at each use (so a
  host can keep it in its data directory, or derive it from its
  `secret_key_base`, without this library depending on how). It is
  never logged and never in telemetry; the configuration's `inspect`
  leaves it out. A missing or short key is `Macaw.Auth.Native.SealingKeyError`
  at first use, naming the fault and never the value.
- **Derived, not used as is.** The AES key is HMAC-SHA256 of a fixed
  label under the configured key, so a host may pass a longer secret it
  also uses elsewhere (its `secret_key_base`) and the two uses never
  share a key.
- **Bound to its row.** Each sealed value carries associated data (the
  purpose and the user's id), so a sealed secret copied onto another
  user's row does not unseal there.
- **The format.** `<<1, iv::12 bytes, tag::16 bytes, ciphertext>>`, the
  first byte a version, so a later scheme can be told apart. A fresh
  random IV for every seal.

`unseal/3` returns `{:error, :wrong_key}` for anything that fails to
authenticate: a different key, a tampered value, another row's value.

# `key_source`

```elixir
@type key_source() :: binary() | {module(), atom(), list()} | nil
```

# `key!`

```elixir
@spec key!(key_source()) :: binary()
```

The AES key from the configured `sealing_key`; raises
`Macaw.Auth.Native.SealingKeyError` when it is missing, short, or its
function returns something that isn't a key.

# `min_bytes`

```elixir
@spec min_bytes() :: pos_integer()
```

The smallest key accepted, in bytes.

# `seal`

```elixir
@spec seal(binary(), binary(), binary()) :: binary()
```

Seals `plaintext` under `key` (from `key!/1`), bound to `aad`.

# `unseal`

```elixir
@spec unseal(binary(), binary(), binary()) :: {:ok, binary()} | {:error, :wrong_key}
```

Unseals: `{:ok, plaintext}`, or `{:error, :wrong_key}` when it doesn't authenticate.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
