Initial commit — encrypted chat server + Python clients (v0.8.5)
E2E encrypted chat (X3DH + Double Ratchet, Signal Protocol). Server: asyncio TCP + TLS, MySQL. Clients: PyQt6 GUI + CLI. Secrets (.env, TLS keys, Cloudflare token), runtime data and mobile clients (separate repos) are gitignored. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
326
README.md
Normal file
326
README.md
Normal file
@@ -0,0 +1,326 @@
|
||||
# Encrypted Chat
|
||||
|
||||
End-to-end encrypted chat s forward secrecy (X3DH + Double Ratchet, Signal Protocol).
|
||||
Server ukládá a přeposílá šifrované bloby — nikdy nevidí plaintext.
|
||||
|
||||
## Architektura
|
||||
|
||||
```
|
||||
┌─────────────┐ TLS/TCP ┌─────────────┐ MySQL ┌─────────┐
|
||||
│ GUI/CLI │◄───────────────►│ Server │◄──────────────►│ DB │
|
||||
│ klient │ JSON + base64 │ (asyncio) │ │ │
|
||||
└─────────────┘ └─────────────┘ └─────────┘
|
||||
│ │
|
||||
│ X3DH + Double Ratchet │ Opaque blobs
|
||||
│ Sender Keys (skupiny) │ (server nevidí plaintext)
|
||||
▼ ▼
|
||||
Lokální klíče Šifrované zprávy
|
||||
(~/.encrypted_chat/) + metadata
|
||||
```
|
||||
|
||||
## Soubory
|
||||
|
||||
### Server
|
||||
| Soubor | Řádky | Účel |
|
||||
|--------|-------|------|
|
||||
| `server.py` | ~2 900 | Asyncio TCP server, 45 handlerů, rate limiting, 5 asyncio.Lock guardů, real-time notifikace |
|
||||
| `db.py` | ~1 700 | MySQL CRUD, connection pooling (pool_size=10), phantom users, reactions/pins CRUD |
|
||||
| `schema.sql` | ~190 | MySQL schéma (14 tabulek) |
|
||||
|
||||
### Klient
|
||||
| Soubor | Řádky | Účel |
|
||||
|--------|-------|------|
|
||||
| `gui_client.py` | ~6 300 | PyQt6 GUI — dark/light téma, widget-based message bubbles, verifikace kontaktů, privacy overlay |
|
||||
| `client.py` | ~900 | CLI klient — 23 menu opcí |
|
||||
| `chat_core.py` | ~3 500 | Sdílená logika — session management, X3DH/ratchet šifrování, lokální klíče, multi-device |
|
||||
| `theme.py` | ~540 | Catppuccin dark + Signal-inspired light téma, live switching |
|
||||
|
||||
### Sdílené (server + klient)
|
||||
| Soubor | Účel |
|
||||
|--------|------|
|
||||
| `crypto_utils.py` (~935 ř.) | Ed25519, X25519, AES-256-GCM, HKDF, PBKDF2, X3DH, Double Ratchet (state rollback), Sender Keys (state rollback), ECP1 key encryption, contact verification (fingerprints, safety numbers, QR), message padding |
|
||||
| `protocol.py` (~140 ř.) | Newline-delimited JSON protokol, base64 encoding, verze (0.8.4) |
|
||||
|
||||
### iOS klient
|
||||
| Složka | Účel |
|
||||
|--------|------|
|
||||
| `ios_client/` (47 Swift souborů, ~5 000 ř.) | Nativní iOS port — CryptoKit + pure Swift GF(2^255-19) + Security.framework RSA, SwiftUI views, wire-kompatibilní s Python serverem |
|
||||
|
||||
### Testy
|
||||
| Soubor | Účel |
|
||||
|--------|------|
|
||||
| `tests/pentest_client.py` (~340 ř.) | Automatizované security regresní testy (AuthZ, malformed headers, session reset, rate limits) |
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. `pip install -r requirements.txt`
|
||||
2. Spustit `schema.sql` v MySQL
|
||||
3. `python server.py`
|
||||
4. Klient: `python gui_client.py` (GUI) nebo `python client.py` (CLI)
|
||||
|
||||
## Jak funguje šifrování
|
||||
|
||||
### Klíče na uživatele
|
||||
| Klíč | Typ | Účel |
|
||||
|------|-----|------|
|
||||
| RSA-4096 | Asymetrický | Pouze login challenge-response. Šifrovaný ECP1 (PBKDF2 600k + AES-256-GCM). |
|
||||
| Identity Key (IK) | Ed25519 | Podpisy, konverze na X25519 pro X3DH. Šifrovaný ECP1. |
|
||||
| Signed Pre-Key (SPK) | X25519 | DH v X3DH, podepsaný IK. **Rotuje se každých 7 dní** s grace periodem. |
|
||||
| One-Time Pre-Keys (OPK) | X25519 | Jednorázové, spotřebuje se při X3DH, automaticky doplňované (< 20 → +50). |
|
||||
|
||||
### DM (1:1 zprávy) — X3DH + Double Ratchet
|
||||
1. Alice stáhne Bobovy per-device key bundles (IK, SPK, OPK) → X3DH per device → shared secret per device.
|
||||
2. Double Ratchet inicializován ze shared secret — jedna session per (user, device).
|
||||
3. Každá zpráva: symmetric ratchet (HMAC chain) → message key → AES-256-GCM.
|
||||
4. Každá odpověď: DH ratchet (nový X25519 keypair) → nový root key + chain key.
|
||||
5. Per-device ciphertext — každé zařízení příjemce dostane individuálně šifrovaný blob.
|
||||
6. Self-encrypted kopie s SELF_DEVICE_ID sentinel, čitelná všemi vlastními zařízeními.
|
||||
|
||||
### Skupiny — Sender Keys
|
||||
1. Každý odesílatel má vlastní SenderKeyState per group.
|
||||
2. Sender key distribuován členům přes pairwise Double Ratchet (jako control DM).
|
||||
3. Skupinové zprávy: symmetric ratchet na sender key → AES-256-GCM.
|
||||
4. Stejný ciphertext pro všechny příjemce (efektivní).
|
||||
|
||||
### Kontaktní verifikace (Signal-style)
|
||||
- **Safety numbers** — 60-digit číslo (12 skupin × 5 číslic), deterministické pro každý pár.
|
||||
- **QR kódy** — binární payload zakódovaný jako base64.
|
||||
- **Fingerprints** — 30-digit per-user číslo.
|
||||
- **TOFU** — Trust On First Use + explicit verification + key change warning.
|
||||
|
||||
### Lokální úložiště klíčů
|
||||
```
|
||||
~/.encrypted_chat/{email}/
|
||||
private.pem / public.pem — RSA (login, ECP1 formát)
|
||||
identity_private.bin / _public.bin — Ed25519 (ECP1 formát)
|
||||
device_id.txt — UUID tohoto zařízení
|
||||
spk_private.bin / spk_id.txt — Aktuální SPK (AES-256-GCM)
|
||||
prev_spk_private.bin / prev_spk_id.txt — Předchozí SPK, grace period
|
||||
opk_private/{opk_id}.bin — One-time prekeys (AES-256-GCM)
|
||||
sessions/{uid}_{did}.bin — Double Ratchet stavy (AES-256-GCM)
|
||||
sender_keys/{conv_id}.bin — Vlastní sender keys
|
||||
sender_keys_recv/{conv}_{uid}_{did}.bin — Přijaté sender keys
|
||||
known_identity_keys.bin — TOFU registr (AES-256-GCM)
|
||||
verified_contacts.bin — Explicitní verifikace (AES-256-GCM)
|
||||
message_cache/{conv_id}.bin — Šifrovaný message cache
|
||||
login_lockout.json — Brute-force lockout stav
|
||||
```
|
||||
|
||||
## Bezpečnostní hardening
|
||||
|
||||
### Šifrování privátních klíčů (ECP1 formát)
|
||||
- **PBKDF2-HMAC-SHA256** s 600 000 iteracemi (OWASP 2023)
|
||||
- **AES-256-GCM**, magic bytes "ECP1" jako AAD
|
||||
- **Formát:** `ECP1(4B) + salt(16B) + nonce(12B) + ciphertext+tag`
|
||||
- Zpětná kompatibilita: staré PEM se migrují automaticky
|
||||
|
||||
### Lokální šifrování dat
|
||||
- Session/sender key soubory, OPK, SPK, message cache, verifikační soubory — AES-256-GCM klíčem z HKDF(identity_key)
|
||||
- `chmod 0o700` na adresáře, `0o600` na soubory
|
||||
|
||||
### Brute-force ochrana
|
||||
- Exponenciální backoff: `min(2^N, 300)` sekund po N chybných pokusech
|
||||
- Aplikováno na login + privacy overlay unlock
|
||||
|
||||
### SPK rotace (7 dní)
|
||||
- Automatická rotace s grace periodem pro in-flight X3DH
|
||||
- Omezuje dopad kompromitace SPK
|
||||
|
||||
### Ratchet state rollback
|
||||
- Snapshot/restore při selhání dešifrování (DoubleRatchet + SenderKeyState)
|
||||
|
||||
### Secure deletion
|
||||
- Overwrite `os.urandom()` + `fsync` + `unlink` na smazané citlivé soubory
|
||||
|
||||
### Message padding
|
||||
- Bucketed padding (64B–64KB) maskuje délku zpráv
|
||||
|
||||
### Metadata privacy
|
||||
- Log sanitizace (žádná PII), metadata retention (90 dní), sender chain minimalizace
|
||||
|
||||
### Anti-enumeration
|
||||
- Phantom users pro neregistrované emaily
|
||||
- Generické odpovědi na register/login/get_user_info
|
||||
|
||||
## Multi-Device Support
|
||||
|
||||
Pravý multi-device (Signal-like) — každé zařízení má nezávislé Double Ratchet sessions.
|
||||
|
||||
- **Devices tabulka** — každé přihlášení registruje device (UUID)
|
||||
- **Per-device prekeys** — každé zařízení má vlastní SPK + OPKs
|
||||
- **Per-device sessions** — klíčované `"user_id:device_id"`
|
||||
- **Self-encryption** — statický klíč z identity key (čitelné všemi vlastními zařízeními)
|
||||
- **Pairing** — přenos RSA + Ed25519, nové zařízení generuje vlastní SPK + OPKs
|
||||
|
||||
## Features
|
||||
|
||||
### Protokol & šifrování
|
||||
- X3DH + Double Ratchet (DM) s forward secrecy
|
||||
- Sender Keys (skupiny) s distribucí přes pairwise ratchet
|
||||
- Per-device šifrování (multi-device)
|
||||
- SPK rotace (7 dní) + grace period
|
||||
- Ratchet state rollback při selhání
|
||||
- ECP1 šifrování klíčů (PBKDF2 600k)
|
||||
- Message padding (bucketed 64B–64KB)
|
||||
- Kontaktní verifikace (safety numbers, fingerprints, QR kódy)
|
||||
|
||||
### Komunikace
|
||||
- DM + skupinové konverzace
|
||||
- Reakce na zprávy (thumbsup, heart, laugh, surprised, sad, thumbsdown)
|
||||
- Přeposílání zpráv (text, obrázky, soubory)
|
||||
- Připnuté zprávy (pin/unpin + dialog)
|
||||
- @Mentions s autocomplete
|
||||
- Odpovědi na zprávy (reply_to)
|
||||
- Hledání zpráv (client-side, Ctrl+F)
|
||||
- Šifrované obrázky (AES-256-GCM, chunked upload, thumbnail)
|
||||
- Šifrované soubory (až 50 MB, chunked upload)
|
||||
- Read receipts (real-time)
|
||||
|
||||
### Skupiny
|
||||
- Skupinové pozvánky (accept/decline)
|
||||
- Leave group + přenos creatora
|
||||
- Rename group (creator only)
|
||||
- Delete conversation (DMs per-user, groups creator-only)
|
||||
- Group avatar
|
||||
|
||||
### Správa
|
||||
- Multi-device support (per-device sessions, pairing)
|
||||
- User profily (telefon, lokace, avatar, viditelnost)
|
||||
- Online/offline status
|
||||
- Session reset (při poškození ratchetu)
|
||||
- Key rotation (revokace zařízení)
|
||||
- Brute-force lockout
|
||||
|
||||
### GUI (PyQt6)
|
||||
- Dark (Catppuccin Mocha) + Light (Signal) téma s live switching
|
||||
- Widget-based message bubbles s ConversationDelegate
|
||||
- Cirkulární avatary + online zelená tečka
|
||||
- Unread count badges
|
||||
- Privacy overlay / lock screen (30s timeout + heslo)
|
||||
- Drag & drop souborů
|
||||
- Frameless dialogy
|
||||
- Connection indicator (green/red/orange) + auto-reconnect
|
||||
- VerificationDialog (safety numbers, QR, fingerprints)
|
||||
- Key change warning dialog
|
||||
|
||||
### CLI
|
||||
- 23 menu opcí (DM, skupiny, soubory, reakce, piny, forwarding, verifikace, zařízení, search)
|
||||
|
||||
### iOS (SwiftUI)
|
||||
- Wire-kompatibilní s Python serverem
|
||||
- Kompletní Signal Protocol (X3DH, Double Ratchet, Sender Keys)
|
||||
- CryptoKit + pure Swift field arithmetic + Security.framework RSA
|
||||
- SwiftUI views (login, chat, groups, profiles, search)
|
||||
|
||||
## Konfigurace
|
||||
|
||||
### Server + DB
|
||||
- `SERVER_HOST` (default `127.0.0.1`), `SERVER_PORT` (default `9999`)
|
||||
- `MYSQL_HOST`, `MYSQL_PORT`, `MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_DATABASE`
|
||||
- `DB_POOL_SIZE` (default `10`)
|
||||
|
||||
### TLS
|
||||
- `TLS_ENABLED` — zapne TLS (default `false`)
|
||||
- `TLS_REQUIRED` — vyžaduje TLS_ENABLED
|
||||
- `TLS_CERT_FILE`, `TLS_KEY_FILE` — cesty k certifikátu (PEM)
|
||||
- `TLS_AUTOGEN` — auto-generuje self-signed cert (**jen s `ENVIRONMENT=dev`**)
|
||||
- `TLS_CA_FILE` (klient) — vlastní CA certifikát
|
||||
- `TLS_INSECURE` (klient) — vypne ověření certifikátu (**jen s `ENVIRONMENT=dev`**)
|
||||
|
||||
### SMTP
|
||||
- `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASS`, `SMTP_FROM`
|
||||
- Bez SMTP = dev mód (kód se vrací přímo klientovi)
|
||||
|
||||
### Limity
|
||||
- `MAX_MESSAGE_BYTES` (default `65536`), `MAX_IMAGE_BYTES` (5 MB), `MAX_FILE_BYTES` (50 MB)
|
||||
- `MAX_INPUT_CHARS` (GUI, default `2000`)
|
||||
- `METADATA_RETENTION_DAYS` (default `90`)
|
||||
- Rate limity: register 3/min, login 10/min, send_message 20/min
|
||||
- Connection: 20 req/s, max 10/IP, 200 global
|
||||
|
||||
### Logging
|
||||
- `LOG_LEVEL` (default `INFO`)
|
||||
|
||||
## Bezpečnostní audit
|
||||
|
||||
Dva bezpečnostní audity provedeny (kód review). Nalezeno 6 CRITICAL, 12 HIGH, 12 MEDIUM, 8 LOW nálezů.
|
||||
|
||||
| Závažnost | Celkem | Opraveno | Zbývá |
|
||||
|-----------|--------|----------|-------|
|
||||
| CRITICAL | 6 | **6** | 0 |
|
||||
| HIGH | 12 | **11** | 1 (H9 — by-design) |
|
||||
| MEDIUM | 12 | **11** | 1 (M7) |
|
||||
| LOW | 8 | **1** | 7 |
|
||||
|
||||
Detaily viz `SECURITY_AUDIT.md` a `CLAUDE.md`.
|
||||
|
||||
## Known Issues
|
||||
|
||||
- **Sender Key Redistribution:** Nový člen skupiny nedešifruje staré skupinové zprávy (sender keys se nedistribuují znovu při přidání).
|
||||
- **iOS: Contact Key Verification** — safety numbers, QR kódy, TOFU zatím neimplementovány v iOS klientu.
|
||||
|
||||
## Docker a CI/CD
|
||||
|
||||
### Lokální vývoj s Docker Compose
|
||||
|
||||
```bash
|
||||
# Spustit server + MySQL
|
||||
docker compose up
|
||||
|
||||
# Rebuild po změně kódu
|
||||
docker compose up --build
|
||||
|
||||
# Zastavit a smazat data
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
Server bude dostupný na `localhost:5000`. MySQL na `localhost:3306`.
|
||||
Schéma se automaticky importuje při prvním spuštění.
|
||||
|
||||
### Ruční build Docker image
|
||||
|
||||
```bash
|
||||
docker build -t encrypted-chat-server .
|
||||
docker run -p 5000:5000 \
|
||||
-e MYSQL_HOST=host.docker.internal \
|
||||
-e MYSQL_USER=chat \
|
||||
-e MYSQL_PASSWORD=chatpassword \
|
||||
-e MYSQL_DATABASE=encrypted_chat \
|
||||
-e ENVIRONMENT=dev \
|
||||
encrypted-chat-server
|
||||
```
|
||||
|
||||
### Produkční deployment
|
||||
|
||||
1. Získat TLS certifikát (Let's Encrypt / vlastní CA)
|
||||
2. Nastavit env vars — viz `.env.example`
|
||||
3. Spustit:
|
||||
```bash
|
||||
docker compose -f docker-compose.yml up -d
|
||||
```
|
||||
4. Ověřit health: `docker compose ps`
|
||||
|
||||
Kritické produkční proměnné:
|
||||
- `TLS_ENABLED=true`, `TLS_CERT_FILE`, `TLS_KEY_FILE`
|
||||
- `MYSQL_PASSWORD` — silné heslo
|
||||
- `ENVIRONMENT=production` (ne `dev`)
|
||||
- `SMTP_*` — pro registrační emaily
|
||||
|
||||
### CI/CD (GitHub Actions)
|
||||
|
||||
Pipeline v `.github/workflows/ci.yml` spouští při každém push/PR:
|
||||
|
||||
1. **Lint** — `ruff check` na všechny Python soubory
|
||||
2. **Crypto testy** — `test_crypto_integration.py` (bez serveru)
|
||||
3. **Integration testy** — spustí MySQL + server, pak `test_server_integration.py`
|
||||
4. **Docker build** — ověří že se image builduje bez chyb
|
||||
|
||||
## Závislosti
|
||||
|
||||
- `cryptography` — Ed25519, X25519, AES-GCM, RSA, HKDF, PBKDF2
|
||||
- `mysql-connector-python` — MySQL s connection pooling
|
||||
- `python-dotenv` — env vars
|
||||
- `PyQt6` — GUI
|
||||
- `Pillow` — resize/thumbnail obrázků
|
||||
- `qrcode` — generování QR kódů
|
||||
- `pyzbar` (volitelné) — skenování QR kódů
|
||||
Reference in New Issue
Block a user