Filip 750290ddc1 Fix OPK loss on SPK-grace retry, deletion sync, add keys_updated push
- chat_core: defer one-time-prekey deletion until the first message
  decrypts successfully; deleting it on load made the SPK grace-period
  retry derive a wrong shared secret and lose the message permanently
- chat_core: fix get_deleted_since params (since -> since_ts) and
  response field (message_ids -> deleted_ids) so incremental deletion
  sync actually works
- chat_core: route keys_updated pushes into the notification queue
- server: notify contacts with keys_updated when a user uploads a new
  SPK or logs in with a new device, so clients invalidate cached key
  bundles instead of waiting for the TTL
- server: rate-limit download_stream like other heavy handlers

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 01:39:36 +02:00

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 (64B64KB) 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 64B64KB)
  • 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

# 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

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:
    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. Lintruff check na všechny Python soubory
  2. Crypto testytest_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ů
Description
Šifrovaný messenger pro Desktop a Server Side
Readme 4.8 MiB
Languages
Python 99.3%
Shell 0.5%
Dockerfile 0.2%