# Crypto and secrets

Encrypt and sign data with one key service, and read named credentials from env or Vault.

`crypto` encrypts and signs payloads and fields at rest or in transit; `secrets` looks up named credentials (API keys, connection strings). They resolve independently; passwords are not encrypted ([Password hashing](https://zenta-dev.github.io/zever/guides/security/password-hashing/)).

## Quick start

`config.Default()` ships a deterministic dev key so tests run real encryption; that key is public, so anything encrypted under it is recoverable. The local adapter accepts it only when explicitly allowed — set `allow_dev_key: true` (development only) or run with `ZEVER_ENV=dev|test|development`. Any other environment must set a real key.

```sh
CRYPTO_ADAPTER=local
CRYPTO_KEY=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=
CRYPTO_ALLOW_DEV_KEY=true
SECRETS_ADAPTER=env
SECRETS_PREFIX=ZEVER
```

```sh
CRYPTO_KEY=prod-base64-key-here
export ZEVER_STRIPE_KEY=sk_test_example
```

```go title="main.go"
cr, err := c.Crypto()   // key missing, malformed, or dev key without allow
sec, err := c.Secrets() // prefix invalid
```

`sign_key` (optional) must decode to 64 bytes. `STRIPE_KEY` resolves to the exported `ZEVER_STRIPE_KEY`; without env, `config.Default()` still resolves but uses the dev key (allowed only via `allow_dev_key` or a dev `ZEVER_ENV`). See the [crypto](https://zenta-dev.github.io/zever/reference/config/#crypto) and [secrets](https://zenta-dev.github.io/zever/reference/config/#secrets) reference.

## Pick an adapter

`crypto`: `local` (default, AES-256-GCM) or `kms` (envelope encryption via `key_id`, `key_ids`, `region`, `endpoint`, `use_envelope`; needs a real client through `NewWithClient`). `secrets`: `env` (default, `_`, `prefix` defaults to `ZEVER`) or `vault` (KV v2, [Secrets](https://zenta-dev.github.io/zever/guides/security/secrets/)). `key_ids` holds prior IDs so rotation decrypts old values while new writes use `key_id`.

## Rotate the crypto key for stored fields

1. Generate a CSPRNG key and inject it through env.
2. Dual-read: decrypt old, re-encrypt new, persist.
3. Track old-key rows to zero.
4. Remove the old key and verify decrypts.

Name the encrypted fields and their key generation in one place, such as the migration runbook.

## Production checklist

- Real key from a CSPRNG, in env or a mounted file, kept in a secret manager.
- `allow_dev_key` unset (or false) and `ZEVER_ENV` not dev/test/development — otherwise `Open` fails with `DevKeyError`.
- Resolve and audit both `crypto` and `secrets`.
- Never log raw option maps; use `cfg.RedactedServices()` or `config.Redact`. Errors name services and fields, never values.

## Troubleshooting

<details>
<summary>Production resolves but old rows decrypt to garbage</summary>

Rows encrypted under a different key, often the dev key. Re-encrypt them during migration.
</details>

<details>
<summary>Secrets lookup misses</summary>

The env name lacks the prefix or its boundary underscore (`STRIPE_KEY` vs `ZEVER_STRIPE_KEY`).
</details>

<details>
<summary>`Open` rejects the secrets prefix</summary>

Empty, or contains a slash, `..`, or spaces. Use a plain prefix such as `ZEVER`.
</details>

<details>
<summary>`Open` rejects the dev key with DevKeyError</summary>

The deterministic public key was supplied without an explicit allow. Set a real `crypto.options.key`, or set `allow_dev_key: true` / `ZEVER_ENV=dev|test|development` for local development.
</details>

<details>
<summary>Key material appears in logs</summary>

Some path logs raw options. Route all display through `cfg.RedactedServices()` or `config.Redact`.
</details>

## Related

[Secrets](https://zenta-dev.github.io/zever/guides/security/secrets/) · [Authentication](https://zenta-dev.github.io/zever/guides/security/auth/) · [Configuration](https://zenta-dev.github.io/zever/guides/operate/configuration/)
