Metadata-Version: 2.4
Name: quantumvault-core
Version: 0.1.2
Summary: QuantumVault: zero-knowledge encrypted messaging, files, and deniable vault with hybrid post-quantum key exchange
Author: QuantumVault contributors
License-Expression: MIT
Project-URL: Homepage, https://github.com/grisuno/QuantumVault
Keywords: cryptography,srp6a,kyber,deniable,vault,flask
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Flask
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Flask==3.1.3
Requires-Dist: flask-talisman==1.1.0
Requires-Dist: Flask-Login==0.6.3
Requires-Dist: Flask-WTF==1.3.0
Requires-Dist: Flask-Limiter==4.1.1
Requires-Dist: Flask-Cors==6.0.4
Requires-Dist: Flask-Mail==0.10.0
Requires-Dist: WTForms==3.2.2
Requires-Dist: pydantic==2.13.4
Requires-Dist: cryptography==48.0.0
Requires-Dist: argon2-cffi==25.1.0
Requires-Dist: boto3==1.43.24
Requires-Dist: botocore==1.43.24
Requires-Dist: redis==8.0.0
Requires-Dist: APScheduler==3.11.2
Requires-Dist: paypalrestsdk==1.13.3
Requires-Dist: pyoqs-sdk==1.0
Requires-Dist: clicksend-client==5.0.91
Requires-Dist: python-dotenv==1.2.2
Requires-Dist: pytz==2026.2
Requires-Dist: gunicorn==23.0.0
Dynamic: license-file


# QuantumVault

<img width="1882" height="979" alt="image" src="https://github.com/user-attachments/assets/0a8b4d20-e00a-45f1-8b62-c0e609abf6a8" />


<img width="1882" height="979" alt="image" src="https://github.com/user-attachments/assets/aa1af1aa-9be4-4d56-a67f-9b1fa3f02287" />


<img width="1882" height="979" alt="image" src="https://github.com/user-attachments/assets/e8f11d33-85ba-4123-b31c-d70a08d7454b" />

From the creators of LazyOwn Redteam Framework comes a free and open-source **Zero-knowledge, zero-trust, end-to-end encrypted messaging and file vault, secured with hybrid post-quantum cryptography.**

QuantumVault is free and open-source software released under the **GNU Affero General Public License v3.0 (AGPLv3)**.

## Mission

LazyOwn RedTeam released QuantumVault as free software so that journalists, activists, and ordinary people can communicate with hybrid post-quantum end-to-end encryption, free from surveillance, censorship, or any single point of control over their right to private communication and free expression.

We hope you put it to good use.

LazyOwn RedTeam is a security research and offensive security collective. We spend our time finding the gaps that surveillance, censorship, and authoritarian control exploit, and we know how often ordinary people, journalists, activists, and dissidents are left without tools they can actually trust. Rather than keep this technology behind a paywall or a closed SaaS, we are releasing QuantumVault to the public so that anyone, an independent newsroom, an NGO, a community group, or an individual, can deploy their own instance, inspect every line of code, modify it, and run it under their own infrastructure and their own responsibility.


## What QuantumVault Does

- **Deniable Vault (VeriCrypt)**: Plausibly deniable encrypted storage con outer/inner volumes.
- **Encrypt and store files** client-side before they ever leave the user's device, then store them as opaque ciphertext on the server.
- **Exchange end-to-end encrypted messages** sealed with a hybrid post-quantum key exchange so that only the sender and the intended recipient can ever read them.
- **Authenticate without ever sending a password**, using SRP-6a, a zero-knowledge password proof.
- **Recover a forgotten password without a server-side reset**, using a one-time recovery code generated in the browser at registration.
- **Resist quantum and classical attacks alike**, since breaking the hybrid construction requires breaking both the post-quantum and the classical primitive.

### Zero-Knowledge, Zero-Trust by Design

"Zero-knowledge" means the server storing data never has access to plaintext, private keys, or passwords, not as a policy promise, but because the cryptography makes it structurally impossible. "Zero-trust" means operators do not need to be trusted to keep that promise: the source code can be read, the cryptographic primitives verified, and the protections confirmed directly.

The architecture is intentionally hybrid: communications are relayed and encrypted blobs are stored through a central server for convenience and reachability, but that server is reduced to a transport and storage layer. It never holds the keys needed to read what passes through it.

## Cryptography

All cryptographic operations that matter, key generation, encryption, and decryption, happen **in the browser**, using vendored, audit-friendly cryptographic libraries (`static/js/vendor/`, `static/js/qv-crypto.js`).

| Purpose | Primitive |
| --- | --- |
| Post-quantum key encapsulation | **ML-KEM-768** (FIPS 203) |
| Classical key exchange | **X25519** (Curve25519 ECDH) |
| Hybrid key wrapping | ML-KEM-768 + X25519, combined |
| Key derivation | **HKDF-SHA256** |
| Symmetric encryption | **AES-256-GCM** |
| Authentication | **SRP-6a** (zero-knowledge password proof, password never leaves the client) |
| Account recovery | **QV-RECOVERY-1** (160-bit recovery code, independently re-wraps the existing private key blob) |

The hybrid construction means that an attacker would need to break **both** ML-KEM-768 and X25519 to recover a user's keys, today or with a future quantum computer.

### Account recovery (QV-RECOVERY-1)

Because the server never has the password or the private key, a forgotten
password cannot be reset the way a traditional service would. Instead, at
registration the browser generates a 20-byte (160-bit) recovery code,
displayed once as 8 groups of 4 characters (e.g.
`ABCD-EFGH-JKMN-...`), and uses it to independently encrypt the same
private-key blob that the password protects. The recovery code is never
sent to or stored on the server, only the resulting ciphertext and its
salt.

To recover an account, visit `/recover`, enter the username, the
recovery code, and a new password. The browser fetches the stored
ciphertext, decrypts it locally with a key derived from the recovery
code, proves to the server that the decryption succeeded (by
reconstructing the account's public key from the recovered blob), and
then re-wraps the same private key under the new password. The
underlying keypair never changes, so previously stored messages and
files remain decryptable.

**The recovery code is shown exactly once**, in a one-time dialog right
after registration. If it is lost and the password is also forgotten,
the account's encrypted data cannot be recovered by anyone, including
the operator: this is a direct consequence of the zero-knowledge design,
not a missing feature.

## Cover Facade (plausible-deniability decoy site)

For a user under surveillance or coercion, the most dangerous signal is the mere
presence of an encryption tool. The cover facade hides QuantumVault behind an
innocuous public site so an observer who opens the instance URL sees a
commonplace page, not a vault.

- **Enable per instance** with `QV_FACADE_ENABLED=1` and a gate phrase hash in
  `QV_FACADE_GATE_HASH` (see `docs/FACADE.md` for the full environment contract).
- **Five built-in cover templates** ship with the application (search portal,
  newsletter, technology blog, art gallery, nonprofit), selected with
  `QV_FACADE_COVER_TEMPLATE`. Every cosmetic string is configurable.
- **Custom templates**: an operator may upload a Jinja template into
  `QV_FACADE_COVER_DIR` and select it with `QV_FACADE_COVER_TEMPLATE=custom`.
  Templates are validated before rendering: only a closed variable allow-list is
  permitted, and imports, attribute traversal, scripts, event handlers, external
  form actions, and embeds are rejected.
- **Two-step gate**: a correct secret phrase reveals the ordinary login; a duress
  phrase marks the session as duress so the browser preselects the decoy slot.
  A miss keeps the cover, and every attempt performs the same Argon2id work so
  the response is not an oracle.
- **Untrusted input everywhere**: cover variables are bounded, canonicalized, and
  stripped of control and spoofing characters, and rendered autoescaped.

## Metadata-size concealment and code integrity

Ciphertext hides content, not length. QuantumVault pads every message and file
to a fixed bucket before encryption, so the wire reveals only a coarse size
class (see `docs/PADDING_AND_INTEGRITY.md` for the full contract).

- **Fixed buckets**: messages pad to 512 B … 64 KiB, files to 64 KiB … 10 MiB
  (`QV_PAD_MESSAGE_BUCKETS` / `QV_PAD_FILE_BUCKETS` override the tables).
- **Fresh randomness, no pad cache**: pad bytes come from the OS CSPRNG on every
  envelope and are never stored or reused; only the immutable bucket table is
  cached, so the cache reveals nothing about any message.
- **Server enforcement**: envelopes whose size is not a bucket plus GCM overhead
  are rejected, so one unpadded client cannot re-open the size oracle.
- **SRI everywhere**: every script and stylesheet carries a Subresource Integrity
  pin from `static/sri_manifest.json` (`make sri` regenerates, `make verify-build`
  checks). Third-party beacons and font CDNs were removed rather than pinned, so
  pages make no third-party requests at all.

## Architecture and Stack

| Layer | Technology |
| --- | --- |
| Web framework | Flask 3 (`app_factory.py`, `wsgi.py`) |
| Authentication / sessions | Flask-Login, SRP-6a session store backed by Redis |
| Forms / CSRF | Flask-WTF, WTForms |
| Security headers | Flask-Talisman |
| Rate limiting | Flask-Limiter |
| Database | SQLite (`instance/users.db`) via SQLAlchemy models (`models/`) |
| Object storage | [Garage](https://garagehq.deuxfleurs.fr/) (self-hosted, S3-compatible) |
| Cache / ephemeral state | Redis |
| Email | Flask-Mail (AWS SES or SMTP) |
| SMS / MFA | ClickSend |
| Production server | Gunicorn |
| Client-side cryptography | Vendored JS: ML-KEM-768, X25519/Ed25519, HKDF, SHA-2/SHA-3, WebCrypto AES-GCM |

## Requirements

- Python 3.10+
- `python3-venv`
- Docker and Docker Compose (recommended), or a manually managed Redis instance and Garage instance
- `openssl` (for local TLS certificates and secret generation)

QuantumVault's server side does not require `liboqs` or any native post-quantum library: all post-quantum and classical cryptography runs client-side in the browser via the vendored JavaScript modules in `static/js/vendor/`. No server-side post-quantum library installation is needed to run the application.

## Quick Start

```bash
git clone https://github.com/grisuno/QuantumVault.git
cd QuantumVault

# One-shot setup: creates the virtualenv, installs Python dependencies,
# generates .env from .env.example, and (if Docker is available) brings
# up Garage + Redis and bootstraps the storage bucket.
make setup

# Start the Flask app in the foreground (dev mode, TLS on the loopback port)
make run
```

By default the app listens on `https://0.0.0.0:4443`.

If `make run` reports missing TLS material, generate a self-signed certificate:

```bash
openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'
```

### Running Without Docker

If Docker is not available, install dependencies and bring up the dependencies natively:

```bash
make venv         # create the virtualenv
make deps         # install Python dependencies
make env          # create .env from .env.example and generate Garage tokens
make redis-up     # start a local Redis instance
make garage-up    # download, run, and provision Garage natively
make run-local    # start the Flask app
```

### Production

Production deployments use Gunicorn against the WSGI entry point (`wsgi.py`). A reverse proxy in front should terminate TLS and forward to the bound port.

```bash
make serve
```

## Configuration

Configuration lives in `.env` (copy from `.env.example`, generated automatically by `make env`). Key settings:

- **Object storage (Garage / S3)**: `S3_ENDPOINT_URL`, `S3_ACCESS_KEY`, `S3_SECRET_KEY`, `S3_BUCKET`, `S3_REGION`
- **Session store / rate limiting**: `STORAGE_URI` (Redis URL)
- **Mail**: `MAIL_SERVER`, `MAIL_PORT`, `MAIL_USE_TLS`, `MAIL_USE_SSL`, `MAIL_USERNAME`, `MAIL_PASSWORD`, `MAIL_DEFAULT_SENDER`. Supports AWS SES or any SMTP provider, including Gmail with an App Password. If left empty, the app skips sending mail and logs the confirmation link instead, recoverable with `python scripts/email_tool.py link <username>`.
- **SMS / MFA (ClickSend)**: `CLICKSEND_USERNAME`, `CLICKSEND_API_KEY`. Leave blank to skip SMS in development.
- **Garage admin / RPC**: `GARAGE_ADMIN_TOKEN`, `GARAGE_RPC_SECRET`, `GARAGE_KEY_NAME`, `GARAGE_ADMIN_URL`
- **Flask**: `FLASK_DEBUG`
- **Feature flags**: `QV_ENABLE_SUBSCRIPTIONS` (default `1`) — set to `0` to disable the paid-plans blueprint and nav link for operators who only want the free, self-hosted core.
- **Privacy hardening**: `QV_AUDIT_LOG_IP`, `QV_AUDIT_LOG_UA` (both default `1`), `QV_TRUSTED_PROXY` (default `0`). See "Running for high-risk users (Tor)" below.

### Running for high-risk users (Tor)

QuantumVault's zero-knowledge cryptography already keeps message/file
content, private keys, and passwords away from the server. The settings
below additionally reduce the *operational metadata* an instance retains,
for operators serving journalists, activists, or anyone else whose safety
depends on minimizing what a compromised or subpoenaed server can reveal:

- Set `QV_AUDIT_LOG_IP=0` and `QV_AUDIT_LOG_UA=0` so the structured audit
  log (`utils/security.py` `audit_event`) records `ip` and `ua` as `null`
  instead of the requester's address and User-Agent string. The audit log
  still records timestamps, event names, and correlation IDs, so abuse
  patterns remain visible without storing identifying details.
- Leave `QV_TRUSTED_PROXY` unset (or `0`). This setting is for operators
  who run their own reverse proxy in front of gunicorn and want
  `X-Forwarded-For` honored; behind Tor, the address Tor presents is not a
  meaningful client identifier, so there is nothing to "trust" and the
  default (use the directly-connecting socket address) is correct.
- Serve the instance as a Tor onion service by pointing a `HiddenServicePort`
  in `torrc` at the port gunicorn binds to (see `make serve` /
  `wsgi.py`). No application code changes are needed — Tor handles
  the `.onion` address and end-to-end transport encryption; QuantumVault's
  own TLS/HSTS settings (`_build_talisman_kwargs` in `app_factory.py`) can
  remain as configured for the clearnet listener, if any, or be left at
  their defaults for an onion-only deployment reached over Tor's own
  encrypted circuits.
- Standard web server access logs (nginx/gunicorn) are outside
  QuantumVault's control; disable or rotate them aggressively at the
  reverse-proxy layer if they are not needed, since they can record client
  addresses independently of the application's own audit log.
- For disposable inbound addresses instead of a static `torrc` entry,
  use the superadmin panel's secure channels (see
  `docs/SECURE_CHANNELS.md`): one click publishes a Cloudflare quick
  tunnel, a disposable onion service, or both (hybrid), and rotation
  destroys the old addresses. Audit records keep only fingerprints,
  never the addresses. First run `make doctor` on the server to check
  that `tor`, `cloudflared`, Redis, and Garage are present;
  `make doctor-fix` installs what is missing. Set
  `QV_CHANNEL_LOCAL_SCHEME=https` when the local listener speaks TLS
  (the dev server does), otherwise the tunnel answers Bad Gateway.

## Common Make Targets

Run `make help` to list all available targets. The most relevant ones:

| Target | Description |
| --- | --- |
| `make setup` | First-time setup: virtualenv, dependencies, `.env`, and (if Docker is present) Garage + Redis |
| `make run` | Run the Flask app in the foreground, starting Docker Compose or a local Redis/Garage as needed |
| `make run-local` | Run Flask without touching Docker (manage Redis/Garage yourself) |
| `make serve` | Run Gunicorn against the production WSGI module |
| `make stop` | Stop the dev app, Docker Compose stack, and any Redis/Garage started by `make run` |
| `make compose-up` / `make compose-down` | Bring the Garage + Redis Docker Compose stack up or down |
| `make garage-up` / `make garage-down` | Run Garage natively without Docker |
| `make redis-up` / `make redis-down` / `make redis-status` | Manage a native Redis instance |
| `make db-reset` | Wipe the development SQLite database |
| `make backupdb` | Snapshot `instance/users.db` to `backups/` |
| `make doctor` | Check the full operator environment: modules, binaries, redis, garage, channel backends |
| `make doctor-fix` | Install everything `make doctor` reports missing (pip deps, apt packages, cloudflared, garage) |
| `make test` | Run the pytest suite (SRP-6a roundtrip, audit-log redaction, facade, cover, CSRF helper tests) |
| `make mutate` | Run mutation testing for the facade and cover contracts |
| `make audit` | Run the security audit stack: `pip-audit` + `bandit` + secret scanning |
| `make pip-audit` | Check the dependency tree for known vulnerabilities |
| `make bandit` | Static security scan of the Python codebase |
| `make semgrep` | Run Semgrep rules against crypto anti-patterns in the codebase |
| `make upgrade-deps` | Refresh the virtualenv to match `requirements.txt` and regenerate `requirements.lock` |
| `make clean` | Remove caches and build artifacts (keeps `.env` and `instance/users.db`) |

## Self-Hosting and AGPLv3

Because QuantumVault is licensed under AGPLv3, anyone running a modified version of it as a network service must make the corresponding source code available to its users. This keeps every deployment auditable.

Each instance of QuantumVault is operated independently by whoever deploys it. LazyOwn RedTeam provides the software, not a hosted service, and does not control or have visibility into independently operated instances.

## License

QuantumVault is released under the **GNU Affero General Public License v3.0 (AGPLv3)**. See the `LICENSE` file for the full text.

---

**QuantumVault: free software, post-quantum encryption, for a free press and free expression.**

![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54) ![Shell Script](https://img.shields.io/badge/shell_script-%23121011.svg?style=for-the-badge&logo=gnu-bash&logoColor=white) ![Flask](https://img.shields.io/badge/flask-%23000.svg?style=for-the-badge&logo=flask&logoColor=white) [![License: AGPL v3](https://img.shields.io/badge/License-AGPLv3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)

[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Y8Y2Z73AV)

<!-- readmenator-kb-link -->
## Knowledge Base

This project has been analyzed by [ReadMenator](https://github.com/grisuno/ReadMenator),
a zero-token polyglot static analysis tool. Regenerate with
`pip install readmenator && readmenator . --rebuild`. Analysis outputs:

- **[KNOWLEDGE_BASE.md](./KNOWLEDGE_BASE.md)** -- Full architecture reference with all
  classes, functions, imports, dependency graphs, UML class diagrams, security
  audit findings, community analysis, taint paths, hotspots, cycles, and more.
- **[readmenator-agent/](./readmenator-agent/)** -- Agent-friendly, grep-optimized index.
  - `INDEX.md` -- Quick reference: what each file does
  - `SYMBOLS.md` -- Every symbol with file:line
  - `ARCHITECTURE.md` -- Internal dependency pairs + external imports
  - `API.md` -- Public function contracts
  - `GOTCHAS.md` -- Change warnings (blast radius, cycles, hotspots)
  - `SECURITY.md` -- Findings by severity with fix hints
  - `MEMORY.md` -- Rules, workflow, style, deliverables, session log
  - `MANIFEST.json` -- Freshness (git_commit + source_fingerprint) + read order
  - `KB_<subsystem>.md` -- Per-subsystem context
  - `recipes/*.md` -- Grounded task guides (add-function, fix-cycle, ...)
- **[readmenator-wiki/](./readmenator-wiki/)** -- Navigable wiki (start here for the big picture).
  - `index.md` -- Entry point: overview, reading order, god nodes, connections
  - `community_*.md` -- One synthesis page per code community
  - `connections.json` -- Typed bridges between communities
  - `queries.md` -- Suggested questions + answer log
  - `REPORT.md` -- Honest audit: coverage, confidence, limits
- **[readmenator-graphrag/](./readmenator-graphrag/)** -- Zero-token GraphRAG index.
  - `index.json` + `REPORTS.md` -- Query with `readmenator . ask "<question>"`
- **[readmenator-apidocs/](./readmenator-apidocs/)** -- API reference (Sphinx/Doxygen style).
  - `index.md` + `modules/*.md` -- Signatures, parameters, returns, raises, examples, call graphs
  - `architecture.md` -- Tiered architecture + execution flows (control flow, call tree, sequence)
  - `classes.md`, `genindex.md`, `COVERAGE.md` -- Hierarchy, A-Z index, doc coverage + warnings
  - `index.html` + `api/` -- Offline searchable browser and machine-readable model (`api/index.json`, `api/modules/*.jsonl` one entity per line)
- **[readmenator-maps/](./readmenator-maps/)** -- Interactive gallery (`index.html`).
  - 5 system maps: architecture, workflow, sequence, dataflow, lifecycle
  - `graph-force.html` -- Force-graph explorer (2D/3D, reach, paths, lenses)
  - `graph-bundle.html` -- Edge bundle explorer (circle + sphere)
  - `components.html` -- Component diagrams
- **[docs/](./docs/)** -- Static site (GitHub Pages ready).
  - Gallery copy + `llms.txt` (agent entry point) + `md/` docs + video
- **[readmenator-diagrams/](./readmenator-diagrams/)** -- Component diagrams.
  - `analysis.json` + `graph LR` markdown + per-component pages + `index.html`
- **[readmenator-rules/](./readmenator-rules/)** -- Suggested Semgrep rules (`*.yml`),
  `yara_rules.yar` (YARA-lite) + `exclusions.yaml` (false-positive blocklist)
- **[readmenator.mp4](./readmenator.mp4)** -- Cinematic synthwave overview video
- **[.cursorrules](./.cursorrules)** -- Generated AI assistant rules
- **[readmenator_audit.sarif](./readmenator_audit.sarif)** -- SARIF v2.1.0 audit (when security scan is on)

Cache (`.readmenator_cache/`), packaged agent skills (`.claude/skills/`), and the
GitHub wiki mirror are also produced on `run`/`--rebuild`.

AI agents: Read `readmenator-wiki/index.md` first for the big picture, then `readmenator-agent/INDEX.md` for grep-friendly lookup.
Developers: Read `KNOWLEDGE_BASE.md` for full architecture reference, open `readmenator-maps/index.html` for the visual gallery.
<!-- /readmenator-kb-link -->

<!-- deploynator-footer -->

---

Deployed with [deploynator](https://github.com/grisuno/deploynator)

<!-- /deploynator-footer -->
