<<<<<<< HEAD
Kecalek_python
=======
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.
Soubory
Server
| Soubor | Účel |
|---|---|
server.py |
Asyncio TCP server, handler dispatch, rate limiting, notifikace |
db.py |
MySQL CRUD, jedna connection na volání |
schema.sql |
MySQL schéma (users, conversations, messages, ...) |
Klient
| Soubor | Účel |
|---|---|
gui_client.py |
PyQt6 GUI |
client.py |
CLI klient |
chat_core.py |
Logika klienta — session management, šifrování, lokální klíče |
Sdílené (server + klient)
| Soubor | Účel |
|---|---|
crypto_utils.py |
Ed25519, X25519, AES-256-GCM, HKDF, PBKDF2, X3DH, Double Ratchet (state rollback), Sender Keys (state rollback), ECP1 key encryption |
protocol.py |
Newline-delimited JSON protokol, base64 encoding |
Quick Start
pip install -r requirements.txt- Spustit
schema.sqlv MySQL (kompletní clean start). Pro migraci existující DB:migration_multi_device.sql. python server.py- Klient:
python client.py(CLI) nebopython gui_client.py(GUI, PyQt6)
Jak funguje šifrování
Klíče na uživatele
| Klíč | Typ | Účel |
|---|---|---|
| RSA-4096 | Asymetrický | Pouze login challenge-response. Šifrovaný PBKDF2 (600k iterací) + AES-256-GCM. |
| Identity Key (IK) | Ed25519 | Podpisy, konverze na X25519 pro X3DH. Šifrovaný PBKDF2 (600k iterací) + AES-256-GCM. |
| Signed Pre-Key (SPK) | X25519 | DH v X3DH, podepsaný IK. Rotuje se každých 7 dní s grace periodem pro in-flight X3DH. |
| 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
- Alice chce napsat Bobovi poprvé → stáhne jeho key bundle (IK, SPK, OPK) ze serveru.
- X3DH: 4 DH výpočty → shared secret.
- Double Ratchet inicializován ze shared secret.
- Každá zpráva: symmetric ratchet (HMAC chain) → message key → AES-256-GCM.
- Každá odpověď: DH ratchet (nový X25519 keypair) → nový root key + chain key.
- Per-recipient ciphertext — každý recipient má vlastní šifrovaný blob.
- Při selhání dešifrování: automatický rollback stavu ratchetu (snapshot/restore).
Skupiny — Sender Keys
- Každý člen má vlastní sender key chain pro skupinu.
- Sender key se distribuuje ostatním členům přes pairwise Double Ratchet (jako DM).
- Skupinové zprávy: symmetric ratchet na sender key → AES-256-GCM.
- Jeden ciphertext pro celou skupinu (efektivní).
Lokální úložiště klíčů
~/.encrypted_chat/{email}/
private.pem # RSA (login) — ECP1 formát s heslem, PEM bez hesla
public.pem # RSA (login)
identity_private.bin # Ed25519 — ECP1 formát s heslem, 32B raw bez hesla
identity_public.bin # Ed25519
device_id.txt # UUID tohoto zařízení
spk_private.bin # Aktuální signed prekey (šifrovaný AES-256-GCM)
spk_id.txt
prev_spk_private.bin # Předchozí SPK, grace period (šifrovaný AES-256-GCM)
prev_spk_id.txt
opk_private/ # One-time prekeys (šifrované AES-256-GCM)
{opk_id}.bin
login_lockout.json # Brute-force lockout stav (failed_attempts, locked_until)
sessions/ # Double Ratchet stavy (šifrované AES-256-GCM)
{user_id}_{device_id}.bin
sender_keys/ # Vlastní sender keys pro skupiny
{conv_id}.bin
sender_keys_recv/ # Přijaté sender keys od ostatních
{conv_id}_{sender_id}_{device_id}.bin
Bezpečnostní hardening
Šifrování privátních klíčů na disku (ECP1 formát)
RSA a Ed25519 privátní klíče šifrované heslem používají vlastní formát ECP1 (Encrypted Chat PBKDF v1):
- PBKDF2-HMAC-SHA256 s 600 000 iteracemi (OWASP 2023 doporučuje 480k+)
- AES-256-GCM pro šifrování, magic bytes "ECP1" jako AAD
- Formát:
ECP1(4B) + salt(16B) + nonce(12B) + ciphertext+tag - Zpětná kompatibilita: Staré PEM soubory (z
BestAvailableEncryption) se načtou automaticky a při dalším uložení se přešifrují do ECP1.
Šifrování SPK/OPK na disku
SPK a OPK privátní klíče jsou šifrované AES-256-GCM klíčem _local_key (HKDF z Ed25519 identity key):
- Při save:
_encrypt_local(raw, local_key)→nonce(12B) + tag(16B) + ciphertext - Při load:
_decrypt_local()s transparentní migrací — pokud dešifrování selže, načte jako plaintext a uloží šifrovaně - Aplikováno na
spk_private.bin,prev_spk_private.bin,opk_private/*.bin
Brute-force ochrana (client-side lockout)
Po chybném zadání hesla se prodlužuje čas do dalšího pokusu:
- Vzorec:
min(2^N, 300)sekund, kde N = počet neúspěšných pokusů (2s, 4s, 8s, ... až 5 min) - Stav:
login_lockout.jsonv adresáři klíčů (failed_attempts,locked_until) - Aplikováno na:
ChatClient.login()(síťový login) + GUI privacy overlay unlock (_on_unlock_attempt) - Reset: Úspěšné přihlášení smaže lockout soubor
- Defense-in-depth: Smazání souboru resetuje počítadlo, ale PBKDF2-600k stále zpomaluje každý pokus (~0.5s/pokus)
SPK rotace (7 dní)
Signed Pre-Key se rotuje periodicky:
- Po přihlášení
_ensure_prekeys()zjistí stáří SPK ze serveru (spk_created_at) - Pokud je SPK starší než 7 dní → vygeneruje nový, starý uloží jako grace period
- Grace period:
prev_spk_private.bin— pokud příchozí X3DH selže s aktuálním SPK, zkusí předchozí - Omezuje dopad kompromitace SPK — útočník může vytvářet nové sessions max 7 dní
Odolnost ratchetu (state rollback)
Double Ratchet i Sender Keys automaticky rollbackují stav při selhání dešifrování:
- Před modifikací chain keys/counters se vytvoří snapshot
- Pokud AES-GCM dešifrování selže (corrupted data, wrong key), stav se obnoví
- Session zůstane funkční i po zpracování poškozené zprávy
Registrace
register→ server pošle 6-místný kód na email (nebo vrátí přímo v dev módu bez SMTP).register_confirm→ potvrzení kódu.- Automaticky se vygenerují a uploadnou prekeys (1 SPK + 50 OPKs).
- Login.
Multi-Device Support
Pravý multi-device (Signal-like) — každé zařízení má nezávislé Double Ratchet sessions. Při posílání DM se zpráva šifruje zvlášť pro každé zařízení příjemce. Všechna zařízení uživatele sdílejí Ed25519 identity key (pro self-encryption kompatibilitu).
Architektura
- Devices tabulka — každé přihlášení registruje device (UUID), server mapuje writer→device
- Per-device prekeys — každé zařízení má vlastní SPK + OPKs, server vrací
device_bundlespole - Per-device sessions — sessions klíčované
"user_id:device_id", nezávislé Double Ratchet instance - Self-encryption — odesílatel šifruje vlastní kopii statickým klíčem z identity key (čitelné všemi vlastními zařízeními)
- Notifikace —
device_entriespole, klient vybere záznam odpovídající svému device_id
Device Pairing (zjednodušený)
Nové zařízení získá RSA + Ed25519 identity klíče od existujícího zařízení. Přenos šifrovaný RSA-OAEP + AES-GCM přes server (server nevidí klíče). Nové zařízení si po přihlášení automaticky vygeneruje vlastní SPK + OPKs.
- Nové zařízení:
Link Device→ dostane 8-místný kód. - Existující zařízení:
Authorize Device→ zadá kód → odešle RSA + identity klíče. - Nové zařízení importuje klíče, přihlásí se, vygeneruje vlastní prekeys.
Migrace
- Existující DB: spustit
migration_multi_device.sql(nebomigration_multi_device_resume.sqlpro idempotentní re-run) - Čistá DB:
schema.sqljiž obsahuje všechny multi-device sloupce
Device Revocation (Key Rotation)
Rotuje RSA login klíč. Odpojí ostatní sessions. Forward secrecy zajišťuje, že kompromitace jednoho session klíče neodhalí historii — není potřeba re-encryption.
Konfigurace
Server + DB
SERVER_HOST(default127.0.0.1),SERVER_PORT(default9999)MYSQL_HOST,MYSQL_PORT,MYSQL_USER,MYSQL_PASSWORD,MYSQL_DATABASE
TLS
TLS_ENABLED— zapne TLS (defaultfalse)TLS_REQUIRED— vyžaduje TLS_ENABLED, jinak server odmítne startTLS_CERT_FILE,TLS_KEY_FILE— cesty k certifikátu a privátnímu klíči (PEM)TLS_AUTOGEN— auto-generuje self-signed cert (jen sENVIRONMENT=dev)TLS_CA_FILE(klient) — vlastní CA certifikát pro ověření serveruTLS_INSECURE(klient) — vypne ověření certifikátu (jen sENVIRONMENT=dev)ENVIRONMENT—dev/developmentpovolí TLS_INSECURE a TLS_AUTOGEN
Produkční nasazení s Let's Encrypt
# 1. Nainstalovat certbot
sudo apt install certbot
# 2. Získat certifikát (port 80 musí být volný pro ověření)
sudo certbot certonly --standalone -d chat.example.com
# 3. V .env nastavit:
TLS_ENABLED=true
TLS_CERT_FILE=/etc/letsencrypt/live/chat.example.com/fullchain.pem
TLS_KEY_FILE=/etc/letsencrypt/live/chat.example.com/privkey.pem
# 4. Klient — stačí zapnout TLS (Let's Encrypt je v systémovém trust store):
TLS_ENABLED=true
Certifikát funguje na jakémkoliv portu (9999, 443, ...) — je vázaný na doménu, ne port. Certbot automaticky obnovuje certifikát každých 90 dní.
Dev/testování (self-signed)
ENVIRONMENT=dev
TLS_ENABLED=true
TLS_AUTOGEN=true # server auto-generuje self-signed cert
TLS_INSECURE=true # klient přeskočí ověření certifikátu
SMTP
SMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASS,SMTP_FROM- Bez SMTP = dev mód (kód se vrací přímo klientovi).
Obrázky
UPLOAD_DIR(defaultuploads),MAX_IMAGE_BYTES(default 5 MB,0= bez limitu)
Limity
MAX_MESSAGE_BYTES(default65536),MAX_INPUT_CHARS(GUI, default2000)- Rate limity: register 3/min, login 10/min, send_message 20/min, pairing_poll 10/min
- Connection: 20 req/s per connection, max 10 per IP, 200 global
- Pairing TTL: 120s, max 5 failed poll pokusů
Logging
LOG_LEVEL(defaultINFO)
Features
- Registrace (2-step, SMTP), login (RSA challenge-response), key rotation
- Multi-device — per-device sessions (Signal-like), device pairing (RSA + identity key transfer), automatické prekey generování na novém zařízení
- DM s forward secrecy (X3DH + Double Ratchet) — per-device šifrování
- Skupiny se Sender Keys (distribuované přes pairwise ratchet)
- Skupinové pozvánky — přidání do skupiny vyžaduje souhlas (accept/decline)
- Odpovědi na zprávy (reply_to)
- Mazání zpráv (soft-delete pro všechny, real-time notifikace)
- Mazání konverzací (pravý klik → smaže pro uživatele, pokud nezbývají členové smaže celou konverzaci)
- Šifrované obrázky (AES-256-GCM, chunked upload, thumbnail v bublině)
- Šifrované soubory (PDF, ZIP, atd. až 50 MB, chunked upload)
- Read receipts (real-time, client-side resoluce)
- Prekey replenishment (automatické doplňování OPKs po loginu + SPK rotace každých 7 dní)
- Silné šifrování klíčů na disku (PBKDF2 600k iterací + AES-256-GCM, ECP1 formát)
- Odolný ratchet — automatický rollback stavu při selhání dešifrování
- TLS (volitelný, auto-gen self-signed)
- Real-time notifikace konverzací — nové konverzace, přidání/odebrání členů se zobrazí okamžitě bez re-loginu
- Connection state indicator — zelená/červená/oranžová tečka, automatický reconnect s exponential backoff
- Online/offline status — zelená tečka na avataru v seznamu konverzací + v group info
- User profily — telefon, lokace, avatar, nastavení viditelnosti (email, telefon, lokace)
- Phantom users — anti user-enumeration: konverzace s neregistrovaným emailem funguje normálně (odesílatel vidí své zprávy), zprávy pro phantom příjemce se neukládají, phantom se smaže při skutečné registraci
- Clickable links — HTTPS modré, HTTP oranžové s ikonou zámku + potvrzovací dialog
GUI (PyQt6)
- Dark theme (Catppuccin Mocha)
- Seznam konverzací s kulatými avatary a online indikátorem (zelená tečka)
- Unread count badge na konverzacích (číselný počet nepřečtených zpráv)
- Message bubliny s barevným left border, timestamp vedle jména
- Read receipts (checkmarks), group info dialog, add/remove member
- Context menu: reply, delete, view image, download file
- Attach button pro obrázky a soubory, thumbnail v bublině, full-size viewer + save
- Pagination ("Load older messages")
- Connection indicator (zelená=online, červená=offline, oranžová=reconnecting)
- Auto-reconnect s exponential backoff (1s → 2s → 4s → ... → max 30s)
- Tlačítko "My Profile" — editace vlastního profilu (telefon, lokace, avatar, viditelnost)
- User profil dialog — klik na info tlačítko v group info → read-only profil uživatele
- Avatar upload/download (JPEG/PNG, max 2 MB, kruhový výřez)
- Leave group (červené tlačítko v group info, přenos creatora)
- Pozvánky do skupin — seznam pending pozvánek nad konverzacemi, pravý klik → accept/decline
- Periodický refresh avatarů a pozvánek (každé 2 minuty)
CLI
- Základní funkcionalita (DM, skupiny, šifrování). Profily a soubory pouze přes GUI.
Závislosti
cryptography— Ed25519, X25519, AES-GCM, RSA, HKDF, PBKDF2mysql-connector-python— MySQLpython-dotenv— env varsPyQt6— GUIPillow— resize/thumbnail obrázků
Known Issues
- Sender Keys pro skupiny se nedistribuují znovu při přidání nového člena (nový člen neuvidí staré skupinové zprávy).
TODO
Security — Zbývající
- H9: Self-encryption key — statický/deterministický klíč (by-design pro cross-device, architektonické omezení)
- M1: Nekonzistentní Ed25519 serializace (částečně vyřešeno M3 — ECP1 formát, ale 3 legacy formáty)
- M6: TOCTOU race v membership checks
- M7: MySQL spojení bez TLS
- L1-L8: Low-priority hardening
- Penetrační testy — manuální + automatizované
Features — High Priority
- Redistribuce sender keys při přidání nového člena do skupiny
- Typing indicators
Features — Medium Priority
- Hledání zpráv v konverzacích
- Group admin roles (více adminů)
- Edit sent messages
Features — Low Priority
- Dark/light theme toggle
- Desktop notifications (system tray)
- Database connection pooling
- Image gallery view
- Systemd + Docker deployment
Monetizace
Oddělený platební server (Stripe, KYC/AML compliant) od chat serveru (anonymní). Platba → premium kód → aktivace na chat serveru. Žádný přímý link platba↔chat identita.
- Free tier: 5 konverzací, 10 MB soubory, 1 zařízení, 30 dní retence, max 10 členů/skupina
- Premium: neomezeno — aktivace jednorázovým kódem z platebního serveru
- Enterprise: self-hosted, LDAP/SSO, admin dashboard, SLA — faktura na firmu
- Detaily implementace viz
CLAUDE.md
Hotovo — Security
- C1-C6: Všechny CRITICAL opraveny — readuntil DoS, sender key fast-forward, OPK permissions, upload size check, path traversal (UUID validace + is_relative_to)
- H1-H8, H10-H14: Většina HIGH opravena — lokální šifrování dat (AES-256-GCM), TLS hardening (INSECURE/AUTOGEN jen v dev), anti-enumeration, race conditions (asyncio.Lock), protokol error handling, avatar path traversal, hesla v paměti (bytearray+zero), image validace, filename sanitizace, OPK race condition (SELECT FOR UPDATE)
- M2-M5+M8-M13: Většina MEDIUM opravena — HKDF salt, PBKDF2 600k iterací (ECP1 formát), SPK rotace 7 dní s grace periodem, rate limit cleanup, UUID validace, ratchet state rollback, message_ids cap, pairing poll token, upload check, chmod 0o700/0o600
- SPK/OPK šifrování + brute-force lockout — všechny privátní klíče na disku šifrované (ECP1 nebo AES-256-GCM), exponenciální backoff po chybném hesle (2^N s, max 5 min)
Hotovo — Features
- Multi-device support — per-device sessions (Signal-like), device pairing, automatické prekey generování
- Unread counts pro offline uživatele
- Clickable HTTP links — HTTPS modré, HTTP oranžové s varováním
- User profily (telefon, lokace, avatar, viditelnost)
- Connection state indicator + auto-reconnect
- Encrypted file sharing (až 50 MB)
- Leave group + přenos creatora
- Unread count badge
- User avatars (upload/download, kruhový výřez)
- Online/offline status (zelená tečka na avataru)
- Mazání konverzací
- Skupinové pozvánky (accept/decline)
- Graceful server shutdown
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 | 10 | 2 (M1 částečně, M6, M7) |
| LOW | 8 | 0 | 8 |
Detaily viz CLAUDE.md.
d506e65 (initial commit)