Aller au contenu

Encryption at rest

Ce contenu n’est pas encore disponible dans votre langue.

Encryption at rest on the server is independent of E2EE. E2EE protects user record content from the server itself; encryption at rest protects sensitive material the server does have to handle (like AI provider API keys it proxies on behalf of users) from anyone who can read the disk or a database backup.

The server holds one symmetric master key, used to derive per-user data keys via HKDF. It must be:

  • Exactly 64 hex characters (32 bytes).
  • Configured via the environment in production: Encryption:MasterKey or ENCRYPTION_MASTER_KEY.
  • Backed up offline. If you lose it, ciphertext stored with it becomes permanently unreadable — even if the database survives.

Generate one with:

Terminal window
openssl rand -hex 32

Once set on a running server, don’t change it casually. Rotating the master key requires re-encrypting every blob that was wrapped with it; there is no automated rotation today. Plan a maintenance window if you ever need to rotate.

  • Stored AI provider API keys in ServerProvider rows.
  • Refresh tokens are stored as one-way hashes (PBKDF2), not encrypted — those don’t decrypt back, they’re verified.

E2EE-encrypted record payloads (memory, sessions, todos, etc.) are not wrapped with the master key. They’re already client-side ciphertext when the server receives them.

The server uses AES-256-GCM with a 96-bit nonce and a 128-bit auth tag. Wire format is Base64 of nonce ‖ ciphertext ‖ tag. Per-user data keys are derived via HKDF-SHA256 from the master key.

ElementSize
Nonce96 bits (12 bytes)
Ciphertextvariable
Auth tag128 bits (16 bytes)
EncodingBase64

Unique nonce per record is enforced — never reuse a nonce with the same key.

Beyond the application-level encryption above, you should also:

  • Encrypt the host disk. On Hetzner, the OS volume is not encrypted by default — enable LUKS (or boot from an encrypted image) before storing production data.
  • Encrypt Postgres backups. pg_dump output is plaintext. Pipe through gpg or age and store the encryption key separately.
  • Restrict /opt/pia/.env.prod to chmod 600. The deployment guide already does this; verify it after first boot.
  • A compromised host with root access. Root can read the master key from /proc of the running server process.
  • A backup with the master key included. If you back up the env file alongside the database, an attacker who steals both has everything.
  • A coerced administrator. The server has no defence against an admin who legitimately holds the master key handing it to a third party.