Andrew Mercer
on this page

Encrypting Archives

Always compress first, then encrypt. Encrypted output looks random and won't compress, so compressing afterwards just burns CPU.

Choosing a method

Method Use when Notes
age Encrypting files and backups for yourself or your systems Modern, simple, authenticated; passphrase or public keys (including SSH keys)
GnuPG You already use a keyring, or need signatures Ubiquitous; more complex
7z AES-256 + -mhe=on Sending a password-protected archive to a person Hides filenames; recipients need 7-Zip or a compatible tool
zip AES-256 Recipient only has built-in OS tools Filenames visible
OpenSSL enc Nothing else is installed No authentication; easy to misuse
zip -e (ZipCrypto) Never for anything sensitive Broken

age

# Passphrase
tar cf - secrets/ | zstd -T0 | age -p > secrets.tar.zst.age
age -d secrets.tar.zst.age | zstd -d | tar xf -

# Key pair: no prompt when encrypting, only the private key can decrypt
age-keygen -o key.txt                                  # prints the public key
tar cf - secrets/ | zstd -T0 | age -r age1... > secrets.tar.zst.age
age -d -i key.txt secrets.tar.zst.age | zstd -d | tar xf -

# Multiple recipients, or a recipients file
age -r age1aaa... -r age1bbb... -o file.age file
age -R recipients.txt -o file.age file

# Encrypt to an SSH public key; decrypt with the private key
age -R ~/.ssh/id_ed25519.pub -o file.age file
age -d -i ~/.ssh/id_ed25519 file.age > file

Public-key mode is ideal for unattended backups: the backup host only holds the public key, so a compromised host can't decrypt old backups.

GnuPG

# Symmetric (passphrase)
gpg -c --cipher-algo AES256 archive.tar.zst            # -> archive.tar.zst.gpg
gpg -d archive.tar.zst.gpg > archive.tar.zst

# Asymmetric
gpg -e -r [email protected] archive.tar.zst
gpg -d archive.tar.zst.gpg > archive.tar.zst

# Streamed, skipping GPG's own compression of already-compressed data
tar cf - dir/ | zstd -T0 | gpg -c --cipher-algo AES256 --compress-algo none -o dir.tar.zst.gpg
gpg -d dir.tar.zst.gpg | zstd -d | tar xf -

OpenSSL

openssl enc is available almost everywhere, but it has no authentication (tampering isn't detected) and older usage patterns derive keys weakly. If you use it, specify a modern cipher and -pbkdf2 with a high iteration count:

# Encrypt
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 600000 \
  -in archive.tar.gz -out archive.tar.gz.enc

# Decrypt (same cipher, -pbkdf2 and -iter)
openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 \
  -in archive.tar.gz.enc -out archive.tar.gz

# Streamed
tar czf - dir/ | openssl enc -aes-256-cbc -salt -pbkdf2 -iter 600000 -out dir.tar.gz.enc
openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 -in dir.tar.gz.enc | tar xzf -

Avoid openssl des3. Triple-DES is deprecated and slow, and without -pbkdf2 the key comes from a single round of a weak hash, which makes passwords easy to brute-force.

Archive-native encryption

Format Cipher Filenames hidden? Create with
zip -e ZipCrypto (broken) No zip -e
zip AES AES-256 No 7z a -tzip -p -mem=AES256
7z AES-256 With -mhe=on 7z a -p -mhe=on
RAR5 AES-256 With -hp rar a -hp

See zip, 7-Zip and RAR.

Password hygiene

  • Prefer prompts (-p with no value, age -p) over passwords on the command line, which end up in shell history and ps output.
  • For scripts, use key-based encryption (age recipients, GPG public keys) rather than embedding passphrases.
  • Store passphrases and private keys in a password manager or pass, not next to the backups.

See also