rsecure is a file encryption CLI built on top of AES-256-GCM. Because it handles
sensitive data, the following document describes what it does and does not protect against,
and how to responsibly report a vulnerability.
Only the latest released version receives security fixes. Older versions are unsupported. Check the latest release at https://github.com/containerscrew/rsecure/releases.
| Element | Value |
|---|---|
| Cipher | AES-256-GCM (256-bit key, 128-bit tag) |
| Construction | STREAM (chunked AEAD) via aes_gcm::aead::stream::EncryptorBE32 |
| Chunk size | 131072 bytes (128 KiB), declared per-file in the header |
| Key derivation | HKDF-SHA256(ikm=master_key, salt=random 32 B per file, info="rsecure-v3-aes256gcm-stream") → 32-byte AES-256 subkey |
| STREAM nonce | Fixed all-zero 7-byte salt; uniqueness is provided by the per-file HKDF subkey, with STREAM's 4-byte BE32 counter ensuring uniqueness across chunks within the file |
| File header | RSEC (4 B) + version 0x03 (1 B) + flags (1 B) + chunk_size (u32 LE, 4 B) + HKDF salt (32 B) = 42 bytes; passphrase mode appends Argon2 params (9 B) + Argon2 salt (16 B) for 67 bytes total |
| Header authenticity | The entire on-disk header is passed as AAD on every chunk; any tampering invalidates the first GCM tag and decryption fails before any plaintext is recovered |
| Master key source | Either a 32-byte keyfile (default) or derived once-per-invocation from a passphrase via Argon2id, see below |
flags & 0x01 == 0 (keyfile): the master key is the 32-byte keyfile passed
via -p. This is the strongest default — the master key has 256 bits of OS-RNG
entropy.
flags & 0x01 == 1 (passphrase): the master key is derived via
Argon2id(passphrase, argon2_salt, params) where the salt and parameters live in
the file header. Default parameters: m_cost = 19456 KiB (~19 MiB),
t_cost = 2, p_cost = 1, output length 32 bytes. These defaults can be
overridden per-invocation via --argon2-memory, --argon2-time, and
--argon2-parallelism; the chosen values are recorded in each file's header so
decryption picks them up automatically. Raising the parameters (more memory,
more iterations) strengthens the KDF; lowering them below the defaults weakens
it and is discouraged. The salt is generated once per invocation, so an entire
encrypt batch shares one Argon2 derivation; the decrypter caches by salt to
avoid re-running the KDF on subsequent files of the same batch.
Security in passphrase mode is bounded by the entropy of your passphrase. Argon2id raises the cost-per-attempt enough to make weak passphrases significantly harder to brute-force, but a 6-character dictionary word remains weak regardless of the KDF.
Because the AES-256 subkey is unique per file (derived from a fresh 256-bit
random salt), the (key, nonce) pair is globally unique across all files even
with a fixed STREAM nonce. This eliminates the birthday-bound nonce-collision
concern that would otherwise apply to AES-GCM's 96-bit nonce when many files
are encrypted under the same master key.
On decrypt, a sanity bound (chunk_size ≤ 16 MiB) rejects pathological headers
before any buffer is allocated, so a hostile .enc cannot trigger an unbounded
allocation.
- v1 (rsecure ≤ 0.5.0): AES-256-GCM STREAM with a 7-byte random nonce derived directly from the master key, no HKDF, no magic header.
- v2 (interim, brief release window before v3):
RSEC0x02header, HKDF-derived subkey, AAD-bound — same scheme as v3 keyfile mode but without the flags byte.
rsecure decrypt reads both transparently; the dispatcher picks the right
code path from the magic + version. New encryptions always use v3.
The cryptographic primitives are provided by the aes-gcm,
hkdf, and argon2 crates from RustCrypto,
widely-used, audited, pure-Rust implementations.
rsecure is being developed with the intent of remaining safe against a
large-scale quantum adversary. This is a stated design goal, not a formal
certification — the project is small, evolving, and has not undergone
independent cryptanalytic review. Read this section for what the intent means
in concrete terms and where the honest limits sit.
| Primitive | Classical security | Post-quantum security | Notes |
|---|---|---|---|
| AES-256-GCM | 256-bit key | ~128-bit (Grover) | NIST PQC Category 5; part of NSA CNSA 2.0 symmetric baseline. |
| HKDF-SHA256 | 256-bit preimage | ~128-bit preimage (Grover) | Used for per-file subkey derivation only; not for long-lived signatures. |
| Argon2id | Memory-hard | Memory-hard (√ speedup only) | Symmetric password KDF; unaffected by Shor. See RFC 9106. |
No asymmetric primitives are used anywhere in rsecure. There is no RSA, no
elliptic-curve Diffie–Hellman, no ECDSA, and no X25519 — so Shor's algorithm
has nothing to break in the current design. This is the single biggest
post-quantum risk in tools that rely on public-key primitives for key
agreement or signing, and rsecure sidesteps it by construction.
- No formal PQ certification exists for this implementation. NIST PQC categories apply to the primitives, not to this specific codebase or parameter choices.
- No post-quantum KEM or signature is included. rsecure does not ship ML-KEM (Kyber) or ML-DSA (Dilithium) today because there is no key-exchange or signing surface in scope. If a future feature ever requires asymmetric crypto (e.g., recipient-based encryption), the intention is to reach for NIST PQC standards rather than pre-quantum primitives.
- Legacy formats (v1, v2) inherit the parameters of their era. The post-quantum posture applies to files produced by the current v3 format; re-encrypting long-lived archives is recommended.
- Distributing keys and passphrases still relies on out-of-band channels;
the post-quantum properties of those channels are outside
rsecure's scope and remain the user's responsibility. - Side-channel resistance is best-effort (inherited from
aes-gcm) and is not itself a post-quantum property, but is listed here alongside the other honest caveats.
- NSA CNSA 2.0 (2022) — AES-256 and SHA-384+ as post-quantum symmetric baseline.
- NIST FIPS 203 (ML-KEM), FIPS 204 (ML-DSA), FIPS 205 (SLH-DSA) — standardized post-quantum asymmetric primitives, referenced here for future work only.
- NIST SP 800-208 — stateful hash-based signatures (not used by rsecure).
- Confidentiality of file contents under a chosen-plaintext attacker that does not possess the master key.
- Integrity & authenticity of each chunk — any tampering will be detected on decrypt (GCM authentication tag).
- Resistance to chunk reordering or truncation — STREAM binds chunks via a counter and a final-chunk marker.
- No catastrophic nonce reuse across files — the per-file HKDF subkey makes the
(key, nonce)pair globally unique even with a fixed STREAM nonce. - Best-effort memory hygiene for secrets. Passphrases, master keys, and
derived subkeys are wrapped in
zeroizeguards and cleared on drop. This is best-effort — Rust does not guarantee freedom from compiler-introduced copies or spilled stack slots, and swap / hibernation / core dumps can still leak secrets outside the process — but it narrows the residual-memory attack surface. - Header authenticity (v2 only). Modifying any byte of the on-disk header (magic, version, chunk_size, salt) causes decryption to fail with an auth error on the first chunk, before any plaintext is written. There is no downgrade, rebinding, or wrong-key-via-salt-swap path that produces valid plaintext.
- Post-quantum design intent (symmetric-only). No RSA, ECDH, ECDSA, or X25519 is used, so Shor's algorithm has nothing to break in the current design. AES-256 and SHA-256 are only reduced to ~128-bit security by Grover. See Post-Quantum Considerations for the honest limits — this is a design goal, not a certification.
- Filename and directory structure are not protected. Only the file contents are encrypted; metadata (paths, sizes, timestamps) remain visible.
- Key storage is the user's responsibility. A master key file left on disk in plaintext offers no protection against an attacker with filesystem access. Use full-disk encryption, a hardware token, or a password manager for key custody.
- No forward secrecy / no post-compromise security. If the master key (or passphrase) is compromised, all past and future ciphertext under it is exposed (HKDF subkeys are derived deterministically from the master key and the per-file salt).
- No authenticated key exchange. Distributing the master key to another party is out of scope; use an out-of-band secure channel (Signal, age, GPG, in person).
- No plausible deniability. Encrypted files are clearly identifiable as such (
.encextension and structured header). - Side-channel resistance is best-effort, inherited from
aes-gcm. The crate uses constant-time arithmetic but does not formally guarantee freedom from cache or timing side channels on every target architecture. On CPUs without AES-NI (or equivalent hardware-accelerated AES), software AES is more exposed to cache-timing side channels. - Legacy v1 nonce collisions. Files encrypted by rsecure ≤ 0.5.0 used a 7-byte random nonce (56 bits), which approaches the birthday bound around 2²⁸ files (~268M) and crosses NIST's 2⁻³² safety margin around ~6k files. Re-encrypt long-lived v1 archives with the current version to migrate them to v3.
- Passphrase strength. In passphrase mode, the master key's effective
security is bounded by your passphrase's entropy. Argon2id raises the
per-attempt cost but cannot rescue a weak passphrase from an offline
brute-force attacker who obtains a
.encfile. Use a key file for the strongest guarantee, or a long, high-entropy passphrase (e.g., a diceware phrase of 6+ words).
Do not file public issues for security vulnerabilities.
Please report security issues via one of these channels:
- GitHub Security Advisories (preferred): open a private advisory at https://github.com/containerscrew/rsecure/security/advisories/new
- Email:
info@containerscrew.comwith the subject prefixed by[rsecure-sec].
Please include:
- A description of the issue and its impact.
- A minimal reproduction (file, command, expected vs. actual behavior).
- Your suggested fix, if any.
You can expect an acknowledgement within 7 days and a status update within 30 days. Coordinated disclosure is preferred; please give us a reasonable window to ship a fix before public disclosure.