Skip to content

Binary File Format

José Carrillo edited this page Jun 13, 2026 · 2 revisions

Binary File Format

A .zefer file is a compact binary container. There are two current formats — ZEFB3 (single key) and ZEFR3 (with a reveal key) — plus legacy formats kept for backward-compatible decryption. All multi-byte lengths are big-endian. Files are byte-for-byte compatible across the web app, the CLI, and the Library.

ZEFB3 — single key (primary format)

ZEFB3                     5 bytes: 0x5A 0x45 0x46 0x42 0x33
header_length             4 bytes, big-endian
header_json               header_length bytes (the public header, see below)
salt                      32 bytes
base_iv                   12 bytes
encrypted_chunks          repeated: [4-byte length prefix (BE)] + [AES-256-GCM ciphertext]

ZEFR3 — with reveal key

ZEFR3                     5 bytes: 0x5A 0x45 0x46 0x52 0x33
header_length             4 bytes, big-endian
header_json               header_length bytes
main_block_size           4 bytes, big-endian
main_salt (32B) + main_iv (12B) + main_chunks
reveal_salt (32B) + reveal_iv (12B) + reveal_chunks

The same content is sealed twice: once under the main passphrase and once under the reveal key, each as its own salt/IV/chunks block. A recipient with only the reveal key can decrypt the reveal block and never sees the main passphrase.

Public header (JSON)

The only cleartext metadata. Everything security-relevant is not here — it is inside the encrypted payload.

{ "iterations": 600000, "compression": "none", "hint": null, "note": null, "mode": "text" }
Field Meaning
iterations PBKDF2-SHA256 iteration count used for this file
compression none | gzip | deflate (applied before encryption)
hint optional public hint string (you choose to include it)
note optional public note string
mode text | file

Encrypted payload

Inside the AES-256-GCM ciphertext, the plaintext is packed as:

4-byte metadata length (big-endian) + metadata JSON + raw content bytes

Metadata JSON (sealed, never in the public header):

{
  "v": 3,
  "fileName": "report.pdf",
  "fileType": "application/pdf",
  "fileSize": 0,
  "expiresAt": 0,
  "createdAt": 0,
  "answerHash": null,
  "allowedIps": [],
  "question": null,
  "maxAttempts": 0
}
Field Meaning
v payload version (3)
fileName / fileType / fileSize restored on decryption (file mode)
createdAt / expiresAt UTC timestamps in milliseconds (expiresAt: 0 = never)
answerHash PBKDF2-SHA256 hash of the secret-question answer (or null)
allowedIps array of allowed IPv4/IPv6 addresses (empty = no restriction)
question the secret question text (or null)
maxAttempts failed-attempt limit (0 = unlimited)

Chunk framing

After the salt and IV, the body is a sequence of chunks. Each chunk is:

[ 4-byte length (BE) ][ AES-256-GCM ciphertext + 16-byte tag ]

Chunks correspond to ≤16 MB slices of the payload. Each uses a unique IV (base_iv XOR the unsigned 32-bit chunk index), so no IV is reused under the same key.

Legacy formats (decrypt-only)

  • ZEFER3 — older text format (base64 lines).
  • ZEFER2 — older JSON payload format.

These are supported for backward-compatible decryption only. New files are always written as ZEFB3 or ZEFR3.

Inspecting a file

You can examine a .zefer file's public header and structure without the passphrase using the .zefer File Analyzer (web) or zefer info (CLI). Security metadata remains invisible because it is encrypted.

Clone this wiki locally