Table of Contents
RustCrypto Backend
rustpg uses RustCrypto — a community-maintained collection of pure-Rust cryptographic primitives. No OpenSSL, no C FFI, no system library dependency. Every algorithm is implemented in safe Rust and audited by the crate maintainers.
This matters for the project in two concrete ways: Windows binaries cross-compile cleanly from Linux (no OpenSSL linking headaches), and the entire crypto stack is readable and auditable in the same language as the rest of the codebase.
Crates in use
aes-gcm 0.10
What it is: AES-256-GCM authenticated encryption (AEAD).
What it does here: Every byte encrypted by rustpg goes through this crate. GCM provides both confidentiality (AES-CTR) and integrity (GHASH tag). The 16-byte tag covers both the ciphertext and the additional authenticated data (AAD) — in RPGS that is the 39-byte header; in RPGA the 50-byte header. Tampering with any bit in the header or ciphertext causes a MAC failure.
Why AES-256: 256-bit keys provide a substantial margin against future cryptanalysis. AES hardware acceleration (AES-NI on x86, ARMv8 crypto extensions) is transparent — the crate uses it automatically when available.
argon2 0.5
What it is: Argon2id password hashing / key derivation function (KDF). Winner of the Password Hashing Competition (2015). Specified in RFC 9106.
What it does here: Derives the 32-byte AES key from a user passphrase for RPGS symmetric encryption. Parameters used: 64 MiB memory, 3 iterations, 1 lane (RFC 9106 second recommended profile). A 16-byte random salt is generated per file and stored in the RPGS header, so every file has an independent key even with the same passphrase.
Why Argon2id: Memory-hardness makes GPU and ASIC attacks expensive. The id variant combines data-dependent (Argon2d) and data-independent (Argon2i) passes, resisting both time-memory trade-off attacks and side-channel attacks. Parameters are stored in the file header — if defaults change, existing files are still decryptable.
x25519-dalek 2
What it is: X25519 Elliptic Curve Diffie-Hellman key exchange on Curve25519.
What it does here: The asymmetric encryption path (RPGA). A fresh ephemeral X25519 keypair is generated per encryption operation. The ECDH shared secret between the ephemeral private key and the recipient's long-term X25519 public key is then fed into HKDF to derive the AES key. The ephemeral public key is stored in the RPGA header (bytes 6–37) so the recipient can reproduce the shared secret.
Why X25519: Fast, constant-time, small keys (32 bytes). No cofactor issues. The Curve25519 field prime was chosen to resist known discrete-log attacks. EphemeralSecret in the crate is consumed on use — the private key cannot be accidentally reused.
ed25519-dalek 2
What it is: Ed25519 digital signatures on Curve25519.
What it does here: All signing and verification — binary, clearsign, and detached modes. Signatures are 64 bytes. Verification requires only the signer's 32-byte public key. The signing key is loaded from the encrypted keyring and zeroized on drop.
Why Ed25519: Deterministic (no per-signature randomness required, no Sony PS3-style k-reuse vulnerability). Fast: ~50 000 verifications/second on a laptop. Compact: 32-byte keys, 64-byte signatures.
sha2 0.10
What it is: SHA-2 family hash functions (SHA-224, SHA-256, SHA-384, SHA-512).
What it does here: SHA-256 is used as the underlying hash in HKDF for asymmetric key derivation. SHA-512 is used internally by ed25519-dalek for signing (Ed25519 is defined over SHA-512).
hkdf 0.12
What it is: HMAC-based Key Derivation Function (RFC 5869).
What it does here: Derives the 32-byte AES key from the X25519 shared secret in the RPGA path. HKDF-SHA256(salt=nonce, ikm=shared_secret, info="rustpg-v1-enc"). Using the nonce as the HKDF salt binds the derived key to this specific ciphertext instance — two encryptions to the same recipient with the same key produce different AES keys.
rand 0.8
What it is: Random number generation. OsRng delegates to the operating system entropy source (getrandom syscall on Linux, BCryptGenRandom on Windows).
What it does here: Generates all random material: Argon2 salts (16 bytes), AES-GCM nonces (12 bytes), and ephemeral X25519 keypairs. Every value is generated fresh per operation — no reuse, no seeding from clocks or PIDs.
zeroize (via zeroize crate)
What it is: Guaranteed zeroing of memory on drop, resistant to compiler optimization.
What it does here: Wraps all sensitive values in Zeroizing<T>: derived AES keys, Ed25519 private keys loaded from the keyring, X25519 private keys, and passphrases held in GUI modal state. Without explicit zeroing, the compiler may optimize out memset calls on values it can prove are never read again — zeroize inserts a volatile write that cannot be elided.
What RustCrypto can offer in the future
The crates below are part of the RustCrypto organization and integrate with the same traits (aead::Aead, digest::Digest, etc.) as the crates already in use. Adding any of them is a matter of a Cargo.toml line and a new variant byte.
chacha20poly1305
ChaCha20-Poly1305 AEAD. Slot: RPGS variant 0x02. Preferred over AES-GCM on hardware without AES-NI acceleration (embedded, older ARM). Same interface as aes-gcm — a one-line swap in the encrypt/decrypt path.
ml-kem (FIPS 203 — ML-KEM / Kyber)
Post-quantum key encapsulation mechanism. Slot: RPGA variant 0x02. Can replace or augment X25519 in the RPGA key exchange step. A hybrid X25519+ML-KEM construction (concatenate shared secrets before HKDF) provides both classical and post-quantum security with no new wire format version needed — only a new variant byte.
ml-dsa (FIPS 204 — ML-DSA / Dilithium)
Post-quantum digital signatures. Can replace or augment Ed25519. Signatures are larger (2–4 KB depending on security level) but the signing and verification interface is the same. A new binary magic byte or variant byte in the signature header would distinguish PQ signatures from Ed25519 ones.
p256 / p384
NIST elliptic curves. Useful if interoperability with systems that require NIST curves becomes a requirement. The ECIES construction would be the same as X25519 — only the key exchange primitive changes.
blake3 (or blake2)
BLAKE3 is significantly faster than SHA-256 on software implementations and has a simpler security proof. Could replace SHA-256 in HKDF with a new RPGA version byte. Not yet in the RustCrypto org proper but the blake3 crate implements the same digest::Digest trait.