Quick Start
QSafe Vault runs entirely in your browser — no installation required. To get started:
- Open app.html (or click "Launch Vault" in the nav)
- Click Create New Vault
- Enter a vault name and a strong password (min. 8 characters)
- Click Create Vault + Generate Keys — wait ~2 seconds for key generation
- Drag a file onto the drop zone, or click Add Files
- Your file is encrypted and stored. Click the download button to decrypt it back.
ℹ The vault is stored in your browser's IndexedDB. Use Export Backup regularly to save a copy you can restore later.
Creating a Vault
A vault is a named, password-protected container that holds your encrypted files. When you create one:
- Your password is run through Argon2id (t=3, m=64MB, p=1) to derive a 256-bit vault key
- An ML-KEM-768 key pair is generated for file key encapsulation
- An ML-DSA-65 key pair is generated for container signing
- Both secret keys are encrypted with your vault key and stored in IndexedDB
- Your vault key only ever exists in memory — it's never stored or transmitted
⚠ Your password cannot be recovered. There is no reset mechanism. Write it down and store it safely. If you forget your password, your files are permanently inaccessible.
Encrypting a File
Drag any file into the drop zone (or click Add Files). Before encrypting, you can optionally attach a time-lock policy. Then:
- A random 32-byte file key is generated
- The file is encrypted:
AES-256-GCM(fileKey, plaintext)
- The file key is encapsulated:
ML-KEM.encap(publicKey) → {kemCt, sharedSecret}
- The file key is wrapped:
AES-256-GCM(HKDF(sharedSecret), fileKey)
- The entire container is signed:
ML-DSA.sign(dsakey, containerBytes)
- The QSAFE container is stored in IndexedDB
Decrypting a File
Click the download button next to any file in the vault. The following checks happen before the file is returned:
- Signature check: ML-DSA-65 verifies the container hasn't been modified
- Policy check: If a time-lock exists, the current time must be after the unlock time
- Key decapsulation: ML-KEM.decap recovers the shared secret using your secret key
- Key unwrap: HKDF + AES-GCM recovers the file key
- Decryption: AES-256-GCM decrypts and authenticates the file
If any step fails, decryption stops immediately. The file is downloaded directly to your device.
Time-Lock Policies
When encrypting a file, you can set a time-lock policy:
- Unlock After: The file cannot be decrypted before this date/time
- Expires After: The file can no longer be decrypted after this date/time
Policy fields are embedded inside the QSAFE container and covered by the ML-DSA signature. Modifying the time-lock or removing the policy invalidates the signature, preventing decryption.
You can also create named policies under the Policies tab and attach them to multiple files.
ℹ Time-lock enforcement in the MVP is based on the browser clock. For adversarially strong time-locks in a production deployment, use a server-side key service that controls key release by time.
Export & Import
To back up your vault, click Export Backup in the open vault view. This creates a .vault JSON file containing:
- All encrypted file containers (ciphertext only — not the original files)
- Your ML-KEM and ML-DSA secret keys (encrypted with your vault key)
- All policies and audit log entries
To restore, open the app in any browser, click Import Vault, select the file, and enter your password.
Audit Log
Every significant action is logged to the Audit Log tab:
encrypt — file encrypted and stored
decrypt — file successfully decrypted
policy_denied — decryption blocked by time-lock or expiry
sig_failed — signature verification failed (possible tampering)
export / import — vault backup events
Security Model
QSafe Vault assumes the following threat model by default:
- Attacker has your encrypted vault file — Protected by AES-256-GCM + ML-KEM-768 + Argon2id
- Attacker modifies your encrypted files — Detected by ML-DSA-65 signature check
- Attacker observes the page — Everything is local; no network traffic after page load
- Attacker has a quantum computer — ML-KEM and ML-DSA are quantum-resistant; AES-256 is safe with 128-bit post-Grover security
⚠ QSafe Vault does NOT protect against: malware on your device reading memory, a compromised browser extension, or someone with access to your unlocked device.
QSAFE Container Format
Each encrypted file is stored as a QSAFE binary container with the following structure:
// QSAFE Container v2 binary layout
magic 4 bytes — 0x51534146 ("QSAF")
version 1 byte — 0x02
cipher_suite 1 byte — 0x01=ML-KEM-768, 0x02=ECDH-P256 (fallback)
kem_algo variable — algorithm name string
sig_algo variable — signature algorithm name string
policy_id 16 bytes — zeros if no policy
unlock_time 8 bytes — Unix ms timestamp (0 = no lock)
kem_ciphertext variable — encapsulated file key
nonce 12 bytes — AES-GCM IV
encrypted_file variable — AES-256-GCM ciphertext + tag
signature variable — ML-DSA-65 sig over all preceding bytes
The signature covers every byte before the sig_len field, making it impossible to modify any part of the container — including the policy fields — without breaking verification.
Frequently Asked Questions
Why can't I recover my password?
+
Recovery would require us to store something that can reverse your password — which is either the password itself, or a recoverable key. Either approach creates a vulnerability: whoever holds that data becomes a target. The only secure design is one where nobody but you can ever open your vault. This is a deliberate design choice, not a limitation. Write your password down.
Can I use QSafe offline?
+
Yes. Once the page has loaded, QSafe Vault makes zero network requests. All cryptographic operations are fully local. You can save the HTML files and open them from your hard drive with no internet connection.
What is the maximum file size?
+
There is no hard limit in the code, but practical limits come from browser memory — the entire file must fit in RAM during encryption. Files up to a few hundred MB work well in most browsers. For larger files, consider splitting them or using the Export feature to manage storage.
Is the encryption the same as HTTPS?
+
QSafe uses AES-256-GCM which is the same cipher used by modern HTTPS/TLS. However, HTTPS uses classical key exchange (ECDH) which is quantum-vulnerable. QSafe replaces ECDH with ML-KEM-768, making the key exchange quantum-safe. The file cipher (AES-256-GCM) is shared.
Why does key generation take a few seconds?
+
The delay comes from Argon2id — the password hashing function. It is intentionally slow (64MB of memory + 3 time iterations) to make brute-force attacks impractical. This delay only happens when creating or unlocking a vault, not when encrypting or decrypting files.
Known Limitations
- Browser clock dependence: Time-lock policies rely on the local system clock in the MVP. A user could advance their clock to bypass a time-lock. Production deployments should use a server-side key service.
- In-memory keys: Secret keys are decrypted into JavaScript memory when the vault is unlocked. Memory isolation in browsers is imperfect. Close/lock the vault when not in use.
- No multi-device sync: Vaults are local to one browser. Use Export/Import to move between devices.
- ML-KEM/ML-DSA WASM: If the lattice WASM modules are not loaded, the vault falls back to ECDH-P256/ECDSA-P256 — still real strong encryption, but classically rather than post-quantum secure.
- No file recovery without password: This is by design, not a bug.