Skip to content

Encrypted exports (.qenc)

Some backups belong on a USB stick or a laptop that travels. Quay’s .qenc format is for that: the same FK-aware SQL dump, sealed inside an authenticated-encryption envelope.

.qenc protects against:

  • Lost / stolen storage — a .qenc file on a misplaced USB stick is meaningless without the passphrase. AES-256-GCM ciphertext + Argon2id-derived key.
  • Tampering — flipping a single byte invalidates the GCM tag; the import fails fast with a clear error rather than producing a subtly broken DB.
  • Brute-force passphrases on weak hardware — Argon2id (memory-hard KDF) makes off-the-shelf GPU brute force expensive even for short passphrases.

It does not protect against:

  • A passphrase you wrote on a sticky note next to the USB stick
  • A keylogger on the box that creates the .qenc
  • Someone shoulder-surfing while you type

A .qenc file is a single binary blob:

[ magic "QENC\0\0\0\0" 8B ]
[ version u8 ]
[ Argon2id params: m_cost u32, t_cost u32, lanes u32 ]
[ salt 16B ]
[ nonce 12B ]
[ ciphertext (AES-256-GCM of the .sql payload) ]
[ tag 16B ]

No external metadata leaks. The original filename, table count, size hints — all are inside the encrypted payload.

When you export to .qenc, the export dialog suggests a strong random passphrase (Diceware-style 6-word string with a “Copy” button). You can override, but the suggestion is meant to be the default — most users forget passphrases they pick themselves (including the maintainer; this was a locked decision after one too many “where did I put that backup password” support tickets).

The suggested format:

forge-quartz-meadow-spectrum-tundra-ribbon

77 bits of entropy. Long enough that Argon2id-cost-amplified brute-force is unfeasible, short enough to type once.

key = Argon2id(
passphrase,
salt,
m_cost = 64 MiB,
t_cost = 3,
lanes = 4,
out = 32 bytes
)

64 MiB memory cost is the recommended value for an interactive “file unlock” use case. Higher costs would push restore latency on low-RAM machines into the multi-minute range; lower costs would weaken offline brute-force resistance. The per-file salt is fresh random — re-encrypting the same file produces a different salt, nonce, and ciphertext.

The Argon2id derivation runs to completion before the GCM check; that’s intentional — a “wrong passphrase” check that returns in 50ms gives an attacker a fast oracle to grind against. Wrong passphrase fails the GCM tag verification, surfaces as “passphrase incorrect or file tampered” with no information about which.

.qenc files round-trip on any platform Quay supports — file format is byte-identical across macOS, Windows, Linux. There’s no Quay-on-the-mainframe restore path (or anywhere else); the file is intentionally not a portable archive format.

  • Production backups behind a VPN / private bucket: .sql.gz is fine and 10× cheaper to restore. The transport is the protection.
  • CI fixtures: plaintext .sql is faster + the test runner doesn’t need passphrase juggling.
  • Tiny dumps (< 1 MB) that you’re handing to a colleague over Slack: 1Password / Keybase shares are simpler.

.qenc is for files at rest in lossy environments — laptops, USB sticks, S3 buckets you don’t fully trust, archive drives you plan to outlast in your own employment.