filip f0666ea6ac Preserve next-message bytes when draining oversized protocol message
ProtocolReader discarded the entire chunk containing the newline
delimiter while draining an oversized message, including bytes after
the newline that belong to the next pipelined message. This corrupted
framing for the rest of the connection (affects server and client).
Salvaged bytes are now kept in a _leftover buffer that read_message()
consumes before touching the stream.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 16:08:12 +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%