What is AGE?

AGE (Actually Good Encryption) is a modern file encryption format and a set of interoperable tools/libraries designed to be simpler than classic “email-style” crypto (like GPG) while remaining secure and script-friendly.

  • Official project: https://github.com/FiloSottile/age
  • Format specification (C2SP): https://c2sp.org/age (also published as https://age-encryption.org/v1)

ProxSave uses the AGE format to encrypt backup archives before they are stored and synced.

Why AGE exists

AGE is intentionally “small” in scope:

  • explicit keys (no key servers, no web-of-trust)
  • composable CLI (works well with pipes)
  • modern primitives and a documented file format specification

How AGE works (high level)

An AGE-encrypted file has:

  • a text header that carries the randomly-generated per-file encryption key, wrapped once per recipient (so any recipient can decrypt)
  • a binary payload that is encrypted and authenticated

AGE is designed for streaming: tools can encrypt/decrypt without loading the full file in memory.

Cryptographic overview (format v1)

At a very high level (details in the spec):

  • each file is encrypted with a fresh random file key (128-bit)
  • the payload is encrypted with an AEAD construction (ChaCha20-Poly1305)
  • the header is authenticated (HMAC-SHA-256, with keys derived via HKDF-SHA-256)

Recipients and identities (core concept)

AGE distinguishes between:

  • recipients: public information used to encrypt (safe to store on the server)
  • identities: secret information used to decrypt (must be kept offline/secure)

A file can be encrypted to multiple recipients. Any one matching identity can decrypt it.

Recipient types in the AGE ecosystem

AGE (the tool and format) supports multiple recipient families, for example:

  • X25519 recipients (age1…) generated by age-keygen
  • SSH recipients (ssh-ed25519 …, ssh-rsa …)
  • passphrase encryption (the age –passphrase mode uses a passphrase-derived recipient in the file header)
  • plugins (hardware tokens and other integrations via age-plugin-*)

How ProxSave uses AGE (important differences)

ProxSave uses the Go filippo.io/age library to encrypt the backup archive while it is being written.

Practical implications:

  • when encryption is enabled, ProxSave does not produce an intermediate plaintext “.tar.*” archive file; the archive is written directly as “.tar.*.age”
  • ProxSave still collects data into a working directory before archiving; encryption protects the final archive at rest and in transit, not the collection step

Supported recipient formats in ProxSave

ProxSave currently accepts:

  • AGE X25519 recipients (age1… public keys)
  • SSH recipients (ssh-ed25519 …, ssh-rsa … public keys)

ProxSave does not support AGE plugins or the native age --passphrase (scrypt-recipient) format as configured recipients.

Passphrase option in ProxSave (ProxSave-specific)

When ProxSave offers a “passphrase/password” option during recipient setup, it does not generate a native age1scrypt1… recipient like age –passphrase does.

Instead, ProxSave deterministically derives an X25519 AGE recipient from your passphrase using scrypt, and stores only the resulting public recipient on disk. During –decrypt/–restore, ProxSave can derive the matching identity again from the same passphrase.

This is convenient (no secrets stored on the server), but it also means:

  • you must keep that passphrase safe; there is no recovery
  • decrypting outside ProxSave requires the corresponding AGE identity, which ProxSave does not print by default

Where ProxSave stores recipients

Configuration keys:

  • ENCRYPT_ARCHIVE=true
  • AGE_RECIPIENT=… (can be repeated / list-style in backup.env)
  • AGE_RECIPIENT_FILE=… (one recipient per line)

Default recipient file (when BASE_DIR is set): BASE_DIR/identity/age/recipient.txt.

File extensions you might see

ProxSave appends .age to the selected archive format:

  • .tar.xz.age, .tar.gz.age, .tar.zst.age, .tar.bz2.age, .tar.lzma.age, or .tar.age

Decryption

Inside ProxSave:

  • proxsave --decrypt (extracts a decrypted bundle)
  • proxsave --restore (decrypts if needed, then restores)

ProxSave prompts for either:

  • an AGE X25519 secret key (AGE-SECRET-KEY-…), or
  • the passphrase used for the ProxSave-derived recipient

With the standard age CLI (for X25519 keys):

age --decrypt -i /path/to/key.txt backup.tar.xz.age > backup.tar.xz

Note: ProxSave’s built-in decrypt workflow does not currently accept SSH private keys as identities. If you encrypted using SSH recipients, use the age CLI for decryption.

No recovery without keys

If you lose all identities/passphrases that can decrypt a backup, the encrypted backups cannot be recovered. Keep at least two independent recovery paths (for example two recipients, or a recipient plus a securely stored passphrase), and periodically test decryption.