Releases: dangel34/PQ-File-Encryption
pqfile v3.2.0
Full Changelog: v3.1.0...v3.2.0
- Key revocation:
pqfile revoke --key pubkey.pem --reason "..."creates apubkey.pem.revokedJSON sidecar containing the key fingerprint and reason.pqfile encryptchecks for a.revokedsidecar alongside each recipient public key and aborts with a clear error if one is found. The sidecar is a plain JSON file checked at encrypt time (not signed; signed revocation is a future roadmap item). - Compress-then-encrypt (
--compress,--compress-level):pqfile encrypt --compress -r pubkey.pem filecompresses plaintext with zstd before encryption, producing a v6.pqffile.--compress-level <1-19>(default 3) trades speed for ratio. Decompression is automatic on decrypt. Only supported with a single recipient (incompatible with multi-recipient v4 format). Not available in WASM builds (zstd requires C FFI). New format constants:VERSION_V6 = 0x06,COMPRESSION_NONE = 0x00,COMPRESSION_ZSTD = 0x01. - Rekey without payload re-encryption:
pqfile rekey --key old_privkey.pem --recipient new_pubkey.pem -o out.pqf in.pqfdecapsulates the session key with the old private key, re-encapsulates it under the new public key, and rewrites only the header. Payload ciphertext bytes are streamed through unchanged. Produces a valid v4.pqffile. Supported for v3 and v5 files with the default 64 KiB chunk size. PqfReader<R: Read>: a streaming decryptor that wraps anyR: Readsource and implementsRead, yielding decrypted plaintext bytes incrementally. Supports v2, v3, v4, and v5 files. Exposes a.info()method returningPqfInfo(version, KEM variant, original size, chunk size). Each AEAD chunk is verified before plaintext bytes are yielded; a tampered chunk returns an I/O error. Available as a public library type inpqfile::reader.- GUI compress checkbox (native only): an "compress before encrypting" checkbox on the Encrypt tab, enabled only when a single recipient is selected. A level slider (1–19) appears when compression is active.
- cargo-vet exemptions for
zstd 0.13.3,zstd-safe 7.2.4, andzstd-sys 2.0.16+zstd.1.5.7.
pqfile v3.1.0
Full Changelog: v3.0.1...v3.1.0
New features
ML-KEM-512 support
A third key size is now available alongside the existing ML-KEM-768 (default) and ML-KEM-1024 variants. Use --level 512 with keygen to generate a 512-bit key pair. All commands (encrypt, decrypt, inspect) handle 512-bit keys transparently. Passphrase-protected 512-bit keys are also supported.
Configurable chunk size (--chunk-size)
encrypt accepts a new --chunk-size BYTES flag (range 1–268,435,456) to control the streaming chunk size. Files encrypted with a non-default chunk size are written in the new v5 format, which embeds the chunk size in the header so decryption is automatic. The default (65,536 bytes) continues to produce v3 files, keeping full backward compatibility.
Performance
Zero-allocation streaming hot path
The encrypt and decrypt streaming paths now use in-place AEAD (encrypt_in_place_detached / decrypt_in_place_detached) instead of allocating a new Vec per chunk. For large files the heap pressure is essentially eliminated on the critical path.
Security & supply chain
OSS-Fuzz integration
pqfile is now integrated with Google OSS-Fuzz for continuous fuzzing. Three fuzz targets run nightly in CI - fuzz_header_read, fuzz_decrypt_bytes, and fuzz_pem_parsing — and crash artifacts are uploaded automatically on failure.
Nightly CI fuzz workflow
A new .github/workflows/fuzz.yml runs all fuzz targets for 120 seconds each on every nightly schedule, independent of OSS-Fuzz, so regressions surface within 24 hours.
CI & developer experience
Benchmark regression detection
Every push and pull request now runs cargo bench against the crypto benchmark suite and stores results on the gh-pages branch via benchmark-action/github-action-benchmark. PRs that regress any benchmark by more than 10% will be flagged with a comment and a failed check.
All GitHub Actions pinned to exact commit SHAs
Every uses: entry in all workflows is now pinned to a specific commit digest rather than a mutable tag, closing a class of supply-chain attack vectors.
Breaking changes
encrypt_stream gains a chunk_size: usize parameter as the third argument. Callers that previously passed (ek_pem, original_size, reader, writer) must now pass (ek_pem, original_size, pqfile::format::CHUNK_SIZE, reader, writer) to preserve the default behaviour.
Checksums
SHA-256 checksums for all release artifacts are in checksums.txt, signed with cosign keyless signing and verifiable against the Sigstore transparency log via checksums.txt.bundle.
pqfile v3.0.1
Full Changelog: v3.0.0...v3.0.1
Security
Supply-chain vetting with cargo-vet - Every third-party Rust crate dependency is now audited via cargo-vet. Audit entries and exemptions are tracked in supply-chain/. CI runs cargo vet on every push and pull request to main, blocking unreviewed new dependencies.
CI / Deployment
Unified release + deploy workflow - The separate deploy.yml workflow has been removed. Deployment of the WASM web app is now triggered automatically as part of the release workflow when a version tag is pushed via bump-version.ps1. The release workflow downloads the WASM artifact and rsyncs it to the server.
Cargo dependency caching - CI now caches Cargo registry and build artifacts, reducing CI build times.
Bug Fixes
WASM build fixes - Resolved conditional-import issues in the GUI that caused the WASM target to fail to compile. Arc<Mutex<_>>, PathBuf, and several color/widget imports are now properly gated behind #[cfg(not(target_arch = "wasm32"))].
Chores
Removed stale Homebrew formula version update from bump-version.ps1.
Updated NGINX_DEPLOYMENT.md, QUICKSTART.md, and RELEASING.md to reflect the new tag-driven release process.
pqfile v3.0.0
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
UnsupportedVersionfor files with unrecognised version bytes, rather than misidentifying them as format errors. signandsign-keygencorrectly 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.
pqfile v2.0.5
Full Changelog: v2.0.4...v2.0.5
What's New in v2.0.5
GUI Enhancements
Multi-file encryption — select and encrypt multiple files at once from the Encrypt tab, with a file list and drag-and-drop support
KEM ciphertext fingerprint — the Inspect tab now shows the SHA3-256 fingerprint of the KEM ciphertext for verification
Overwrite protection — the GUI keygen flow now prompts for confirmation before overwriting existing keys
CLI Refactor
Extracted run_keygen, run_encrypt, and run_decrypt into dedicated functions in main.rs for cleaner command handling
Installation
Homebrew (macOS): brew install dangel34/pqfile/pqfile
winget (Windows): winget install dangel34.pqfile
Release workflow now automatically updates the Homebrew tap and generates winget manifests on each release
CI / Release Pipeline
Fixed checksum extraction in the release workflow
Fixed Homebrew tap update to handle idempotent re-runs without failing
pqfile v2.0.4
Full Changelog: v2.0.3...v2.0.4