Skip to content
Sysadmin

Building Secure File Encryption with XChaCha20-Poly1305

I built SwatCrypt because I wanted to encrypt files and I didn’t trust myself to wire crypto correctly on top of something else. A file goes in, a .swc container comes out, and without the passphrase or keyfile it’s unrecoverable. Every choice — cipher, KDF, key combination — had a non-obvious wrong answer waiting.

Why not AES-GCM

AES-GCM is the obvious starting point. Hardware-accelerated everywhere, NIST standard, used in TLS. The problem is the nonce.

GCM uses a 96-bit nonce. Generate them randomly and the birthday bound gives you meaningful collision probability after about 2³² operations. That’s four billion, which sounds like a lot until you consider that a tool encrypting files generates a new nonce per chunk, and chunks are 64 KB. The math gets uncomfortable fast.

XChaCha20-Poly1305 uses a 192-bit nonce. Generate it randomly for every operation and the collision probability over the tool’s entire lifetime is negligible. That removes a whole category of risk I’d otherwise have to actively manage.

Key derivation with Argon2id

A password has maybe 40 bits of entropy. AES-256 needs 256. The KDF bridges that gap, and the choice matters.

SwatCrypt uses Argon2id — the hybrid variant from RFC 9106. It’s memory-hard (expensive to parallelise on GPUs) and time-hard (can’t be shortcut with ASICs). Default parameters: 64 MiB memory, 3 iterations, single thread. That’s the OWASP minimum recommendation, and it’s enough to make offline brute-force genuinely painful while keeping the UX acceptable — the KDF takes a visible but non-annoying fraction of a second.

The parameters and salt are stored in the file header, so future versions can increase them without breaking old files.

Keyfile support

Passwords can be guessed or stolen by keyloggers. Keyfiles add a second factor that’s orthogonal to the passphrase — you need both to decrypt. SwatCrypt generates keyfiles up to 4096 bytes of cryptographically random data, combined with the passphrase at the KDF step. Losing the keyfile means losing the data. That’s intentional, and the UI says so clearly.

No unsafe code

The entire SwatCrypt codebase has #![forbid(unsafe_code)] at the crate root. Any unsafe block anywhere fails to compile. The crypto is handled by audited upstream crates — chacha20poly1305, argon2 — that have their own unsafe budgets. The application code has none.

The zeroize crate zeroes sensitive data (passphrases, derived keys, key material) when it goes out of scope. This is enforced by types implementing Zeroize, not by manual cleanup calls that could get missed.

Context menu without admin rights

SwatCrypt installs its Explorer context menu entry into HKCU\Software\Classes — the per-user hive, not HKLM. No elevation required at install time. It only shows up for the current user, which is fine for a personal encryption tool. The entry adds “Decrypt with SwatCrypt” to the .swc file type — encryption goes through the GUI or CLI, decryption is the one you want a quick right-click for.

The tool is on GitHub, MIT licensed.

← All articles