Skip to content

pqfile v3.0.0

Choose a tag to compare

@github-actions github-actions released this 21 May 02:00
· 140 commits to main since this release

Full Changelog: v2.0.5...v3.0.0

This is a major release. The .pqf file format has two new versions (v3 and v4), which are not backwards-compatible with writers from v2.x. All v2 files remain readable by v3.0.0.


Breaking changes

New default format: v3 (chunked STREAM)

Files encrypted by v3.0.0 use version byte 0x03 by default. The payload is split into 64 KiB chunks. Each chunk carries an independent AEAD tag and a position-binding counter, so truncation, reordering, and payload-swap attacks are detected before any plaintext is returned. v2.x clients cannot decrypt v3 files.

New multi-recipient format: v4

Files encrypted with multiple -r flags use version byte 0x04. v2.x clients cannot read v4 files.


New cryptographic algorithms

ML-KEM-1024 (--level 1024)

A higher security parameter set (NIST category 5, compared to category 3 for ML-KEM-768). Key generation, encryption, decryption, and inspection all support both levels. The level is embedded in the file header so decryption is automatic.

pqfile keygen --out ./keys --level 1024

Hybrid X25519+ML-KEM-768 (--hybrid)

Combines classical X25519 Diffie-Hellman with ML-KEM-768. The session key is derived via HKDF-SHA256(X25519_ss || ML-KEM_ss, info="pqfile-hybrid-v1"). Security holds if either algorithm remains unbroken, covering the transition period where quantum computers may or may not be practical.

pqfile keygen --out ./keys --hybrid

Digital signatures: ML-DSA-65 (NIST FIPS 204)

A new family of subcommands for signing and verification. Signatures are detached PEM files (3309 bytes). Signing keys are stored as a 32-byte seed.

pqfile sign-keygen --out ./keys
pqfile sign -k sign_privkey.pem document.pdf
pqfile verify -k sign_pubkey.pem -s document.pdf.sig document.pdf

New encryption features

Multi-recipient encryption

A single file can be encrypted to any number of public keys in one pass. Each recipient gets their own encapsulated session key; the file payload is encrypted once. Mixed KEM variants (768, 1024, hybrid) are supported within a single file.

pqfile encrypt -r alice/pubkey.pem -r bob/pubkey.pem secret.txt

Recursive directory encryption

Encrypts every file in a directory tree, writing .pqf files alongside the originals. Existing .pqf files are skipped.

pqfile encrypt -r pubkey.pem --recursive /path/to/dir/

Stdin / stdout pipeline support

Pass - as the input file to read from stdin. Omit -o or pass -o - to write to stdout.

cat secret.txt | pqfile encrypt -r pubkey.pem - > out.pqf
cat out.pqf | pqfile decrypt -k privkey.pem - | gpg --encrypt > double.gpg

CLI additions

Structured JSON output (--json)

Every command accepts a global --json flag. Success: {"status":"ok",...}. Errors go to stderr as {"status":"error","message":"..."}. Exit code is always 1 on error.

Shell completions

pqfile completions <shell> prints a ready-to-install script for bash, zsh, fish, PowerShell, or elvish.

pqfile completions bash >> ~/.bash_completion
pqfile completions zsh  >  ~/.zfunc/_pqfile

pqfile keygen --force

Without --force, keygen refuses to overwrite existing key files.


GUI improvements

Algorithm selection (Keygen tab)

Radio buttons for ML-KEM-768, ML-KEM-1024, and Hybrid X25519+ML-KEM-768.

Multi-file batch encrypt

An "Add Files" button and drag-and-drop support. Each file shows per-row status. "Encrypt All (N)" processes all files sequentially with the same recipient list.

Background threading with progress bar

Encrypt and decrypt operations run on a background thread (native). A per-file progress bar is shown during batch encrypt; a spinner is shown during decrypt. The UI stays responsive throughout.

Key management tab

A dedicated Keys tab stores remembered key pairs (label, fingerprint, directory path) across sessions. Quick-load buttons move a key directly into the Encrypt or Decrypt tab.

Passphrase field auto-show

The passphrase field in the Decrypt tab appears only when the loaded private key is passphrase-protected.

Inspect tab: multi-recipient support

Displays recipient count and per-recipient KEM variant for v4 files.


Security improvements

Passphrase protection for all key types

pqfile keygen --passphrase now works for ML-KEM-768, ML-KEM-1024, and hybrid keys. The private key seed is encrypted with AES-256-GCM using a key derived by Argon2id (m=64 MiB, t=3, p=1, 16-byte random salt).

Improved error handling in signing and decryption

Incorrect PEM tags, wrong key lengths, and unsupported version bytes now produce clear, specific errors rather than generic failures. Decryption rejects unknown version bytes before attempting any cryptographic operations.

Zeroize on drop for all new key material

The X25519 scalar, hybrid shared secrets, and ML-DSA signing key seed are all wrapped in Zeroizing<T>.


Performance

Criterion benchmark suite

pqfile/benches/crypto.rs benchmarks encrypt_bytes, decrypt_bytes, encrypt_stream, decrypt_stream, and keygen at 1 KB, 1 MB, and 100 MB. Run with cargo bench -p pqfile. HTML reports land in target/criterion/.

Streaming encryption: constant memory for large files

Peak memory use during encrypt and decrypt is proportional to the 64 KiB chunk size, not the file size.


Bug fixes

  • Decryption now returns UnsupportedVersion for files with unrecognised version bytes, rather than misidentifying them as format errors.
  • sign and sign-keygen correctly reject PEM blobs with the wrong tag and key material of the wrong length.

Upgrading from v2.x

No action is needed to read existing v2 files; v3.0.0 auto-detects the format version. New encryptions use the v3 streaming format by default. Library consumers using encrypt_bytes / decrypt_bytes directly continue to produce v2 output; switch to encrypt_stream / decrypt_stream for v3.

Checksums and the cosign bundle for signature verification are attached to this release. See RELEASING.md for verification instructions.