Skip to content

Security: containerscrew/rsecure

Security

SECURITY.md

Security Policy

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.

Supported Versions

Only the latest released version receives security fixes. Older versions are unsupported. Check the latest release at https://github.com/containerscrew/rsecure/releases.

Cryptographic Design

File format v3 (current)

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

Master key sources

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. 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.

File formats v1 and v2 (legacy, decrypt-only)

  • 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): RSEC 0x02 header, 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.

Threat Model

What rsecure guarantees

  • 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.
  • 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.

What rsecure does NOT guarantee

  • 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 (.enc extension 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 .enc file. Use a key file for the strongest guarantee, or a long, high-entropy passphrase (e.g., a diceware phrase of 6+ words).

Reporting a Vulnerability

Do not file public issues for security vulnerabilities.

Please report security issues via one of these channels:

  1. GitHub Security Advisories (preferred): open a private advisory at https://github.com/containerscrew/rsecure/security/advisories/new
  2. Email: info@containerscrew.com with 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.

There aren't any published security advisories