Files
Kecalek_python/ios_client 0.8.5/ARCHITECTURE.md
2026-03-14 12:43:56 +01:00

347 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Kecalek iOS — Architecture & Features
**Version:** 0.8.5
**Platform:** iOS 26+ / Swift 6
**Files:** 57 Swift source files
---
## Project Structure
```
Kecalek/
├── KecalekApp.swift # App entry point, tab navigation
├── AppState.swift # Login state, connection monitoring, reconnection
├── Core/
│ ├── ChatClient.swift # Main actor — all server communication & crypto (3400+ lines)
│ ├── KeyStorage.swift # Persistent key storage (RSA, Ed25519, sessions, TOFU)
│ ├── KeychainService.swift # Secure credential storage (biometric auth)
│ └── MessageCache.swift # Encrypted message cache (per-conversation)
├── Crypto/
│ ├── CryptoUtils.swift # AES-256-GCM, HKDF, chain KDF, local encryption
│ ├── DoubleRatchet.swift # Signal Double Ratchet (DM encryption)
│ ├── X3DH.swift # Extended Triple Diffie-Hellman (session init)
│ ├── SenderKeyState.swift # Sender Key chains (group encryption)
│ ├── Ed25519Crypto.swift # Identity key generation & signing
│ ├── X25519Crypto.swift # DH key agreement & Ed25519↔X25519 conversion
│ ├── RSACrypto.swift # RSA-2048 key generation, PKCS#1/PKCS#8
│ ├── KeyEncryption.swift # ECP1 format: PBKDF2 600K + AES-GCM key encryption
│ ├── FieldArithmetic.swift # GF(2^255-19) for Ed25519→X25519 conversion
│ ├── MessagePadding.swift # Bucket-based padding (64B64KB) for metadata privacy
│ ├── ContactVerification.swift # Fingerprints, safety numbers, QR codes
│ └── CryptoErrors.swift # Error types
├── Network/
│ ├── ConnectionManager.swift # TCP/TLS via Network.framework (actor)
│ └── ProtocolHandler.swift # Newline-delimited JSON encoding/decoding
├── Models/
│ ├── Message.swift # Message, reactions, replies, pins, files, images
│ ├── Conversation.swift # Conversation, members, group detection
│ ├── User.swift # User, UserProfile
│ ├── DeviceBundle.swift # X3DH key bundle per device
│ └── Invitation.swift # Group invitation
├── ViewModels/
│ ├── AuthViewModel.swift # Login, register, pairing, biometrics
│ ├── ChatViewModel.swift # Messages, sending, search, reactions, pins
│ ├── ConversationListVM.swift # Conversations, online users, favorites, avatars
│ ├── ProfileViewModel.swift # Profile editing, avatar upload
│ └── VerificationVM.swift # Safety numbers, QR verification
├── Views/
│ ├── Auth/ # LoginView, RegisterView, PairingView, AuthorizeDeviceView
│ ├── Chat/ # ChatView, MessageBubbleView, MessageInputView, etc.
│ ├── Components/ # CircularAvatarView, ConnectionIndicator, OnlineDotOverlay
│ ├── Conversations/ # ConversationListView, ConversationRowView, NewConversationSheet
│ ├── Groups/ # GroupInfoView, InvitationBanner, CreateGroupSheet
│ ├── Profile/ # ProfileView, EditProfileView
│ └── Verification/ # SafetyNumberView, QRCodeScannerView, VerificationStatusView
└── Utilities/
├── Constants.swift # Version, limits, timeouts, server defaults, crypto params
└── Extensions.swift # Data hex/base64, DateParsing, Dictionary helpers
```
---
## Architecture
### Pattern: MVVM + Actor Isolation
- **Views** — SwiftUI, declarative UI, bind to `@Observable` ViewModels
- **ViewModels** — `@Observable final class`, business logic, async operations
- **ChatClient** — `actor`, single source of truth for all crypto & network ops
- **Models** — plain `struct`s with `Identifiable`, `Codable`
### Concurrency Model
- `ChatClient` is an **actor** — all crypto state (keys, sessions, ratchets) is thread-safe
- All network calls use `async/await`
- Real-time notifications via `AsyncStream<ChatNotification>` (multiple subscribers)
- Background tasks: avatar loading, reconnection, notification listening
### Connection Lifecycle
```
App Launch → Login (RSA challenge-response) → TCP/TLS connected
→ Background listener loop reads messages continuously
→ Notifications broadcast via AsyncStream to all subscribers
→ On disconnect: exponential backoff reconnect (1s → 30s, 5 attempts)
→ On auth failure: immediate logout (keys rotated)
→ On foreground: check connection health, reconnect if stale (>30s)
```
---
## Encryption (Signal Protocol)
### Key Types
| Key | Algorithm | Size | Purpose |
|-----|-----------|------|---------|
| RSA | RSA-2048 | 256B | Login authentication (challenge-response) |
| Identity Key (IK) | Ed25519 | 32B | Long-term identity, signs SPK |
| Signed Pre-Key (SPK) | X25519 | 32B | Medium-term, rotated every 7 days |
| One-Time Pre-Keys (OPKs) | X25519 | 32B each | Single-use, batch of 50, replenish at 20 |
| Ratchet Keys | X25519 | 32B | Ephemeral per DH ratchet step |
| Sender Keys | Random | 32B | Per-group, per-sender chain key |
### DM Encryption (X3DH + Double Ratchet)
1. **Session Init (X3DH):**
- Alice computes: DH(IK_A, SPK_B) || DH(EK_A, IK_B) || DH(EK_A, SPK_B) || DH(EK_A, OPK_B)
- HKDF-SHA256 derives 32-byte shared secret
- Double Ratchet initialized
2. **Message Encryption (Double Ratchet):**
- Root key → chain key → message key (HKDF chain)
- DH ratchet step on each direction change
- AES-256-GCM with derived message key
- AAD: ratchet header (dh_pub, n, pn)
- Max skip: 256 messages
3. **Message Format:**
```
plaintext → MessagePadding.pad() → AES-256-GCM encrypt → base64 → JSON
```
### Group Encryption (Sender Keys)
1. Each member maintains own sender key chain
2. Sender key distributed to all members via pairwise Double Ratchet DMs
3. Messages encrypted with AES-256-GCM using derived chain key
4. Chain ID = SHA-256(sender_key) for verification
5. Max skip: 256 messages per chain
### Message Padding
Bucket sizes: `64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536` bytes
```
Format: 0x01 | plaintext | random_padding | pad_length (4B big-endian)
```
All messages padded to nearest bucket size — prevents metadata analysis of message lengths.
### Self-Encryption
- Derived from identity private key via HKDF
- Encrypts own message copies for multi-device access
- Static key — same across all user's devices
### Contact Verification (TOFU)
- **Fingerprint:** Iterated SHA-512 (5200 rounds) over identity key
- **Safety Number:** 60 digits (12 groups of 5), deterministic ordering by userId
- **QR Code:** Binary `version(1B) + uid_len(1B) + uid + identity_key(32B)`
- **TOFU Registry:** Track first-seen identity keys, alert on change
- **Verification Status:** unverified → trusted (TOFU) → verified (manual/QR)
---
## Features
### Authentication & Accounts
- [x] **Registration** — email + password + verification code
- [x] **Login** — RSA challenge-response authentication
- [x] **Biometric Login** — Face ID / Touch ID via Keychain
- [x] **PoW Challenge** — SHA-256 proof-of-work during registration surge
- [x] **Brute-Force Lockout** — exponential backoff (2^n seconds, max 300s)
- [x] **Change Username** — update display name
- [x] **Change Password** — re-encrypt RSA + Ed25519 keys with new PBKDF2 password
- [x] **Key Rotation** — regenerate all keys with grace period for in-flight sessions
- [x] **Logout** — clean disconnect, clear session
### Multi-Device
- [x] **Device Pairing** — authorize new device via pairing flow
- [x] **Device List** — view all authorized devices
- [x] **Device Removal** — revoke device authorization
- [x] **Self-Encryption** — own messages readable on all devices
### Messaging
- [x] **Text Messages** — encrypted DM and group messages
- [x] **Message Replies** — reply-to with visual indicator
- [x] **Reactions** — 6 emoji reactions (👍❤️😂😮😢👎) with toggle
- [x] **Message Pinning** — pin/unpin with pinned messages sheet
- [x] **Message Deletion** — soft delete with "Message deleted" indicator
- [x] **Message Forwarding** — forward to any conversation with source attribution
- [x] **Message Search** — full-text search with result navigation (prev/next)
- [x] **Read Receipts** — track who read each message
- [x] **Delivery Receipts** — sent → delivered → read indicators (checkmarks)
- [x] **Incremental Sync** — fetch only new messages via `after_ts`
- [x] **Deleted Sync** — `get_deleted_since` for incremental deletion sync
- [x] **Message Padding** — metadata privacy via bucket-based padding
### Media & Files
- [x] **Image Upload** — encrypt + chunked upload (24KB chunks)
- [x] **Image Thumbnails** — base64 JPEG preview inline
- [x] **Image Viewer** — full-screen with pinch zoom
- [x] **File Upload** — any file type with mime detection
- [x] **File Download** — decrypt + share via system share sheet
- [x] **File Icons** — type-based system icons (PDF, DOC, ZIP, etc.)
### Conversations
- [x] **Direct Messages** — 1-on-1 encrypted chat
- [x] **Group Conversations** — multi-member with Sender Keys
- [x] **Create Conversation** — new DM or group
- [x] **Rename Conversation** — group rename (creator only)
- [x] **Delete Conversation** — remove DM or delete group
- [x] **Favorites** — pin conversations to top with star icon
- [x] **Unread Counts** — per-conversation badge
- [x] **Online Status** — real-time presence (green dot)
### Group Management
- [x] **Add Member** — by email
- [x] **Remove Member** — creator only
- [x] **Leave Group** — with confirmation
- [x] **Group Avatar** — upload/change group photo
- [x] **Group Rename** — change group name
- [x] **Group Invitations** — accept/decline with banner UI
### Profile
- [x] **User Profile** — username, email, phone, location
- [x] **Avatar** — upload/change profile photo
- [x] **Field Visibility** — toggle phone/location visibility
- [x] **View Other Profiles** — see other users' info (respects visibility)
### Contact Verification
- [x] **Safety Numbers** — 60-digit verification code per contact pair
- [x] **Fingerprints** — identity key fingerprints
- [x] **QR Code Generation** — generate scannable verification QR
- [x] **QR Code Scanning** — camera-based QR scan for verification
- [x] **Verification Status** — verified (green) / trusted (blue) / unverified (gray)
- [x] **TOFU Registry** — track identity key first-seen, detect changes
- [x] **Shield Icon** — verification badge in chat toolbar
### Connection & Reliability
- [x] **TCP/TLS** — Network.framework with optional TLS
- [x] **Configurable Server** — host, port, TLS toggle in login screen
- [x] **Connection Indicator** — visual status (disconnected/connecting/connected)
- [x] **Auto-Reconnect** — exponential backoff (1s → 30s, 5 attempts)
- [x] **Background/Foreground Handling** — reconnect when returning from background
- [x] **Auth Failure Detection** — immediate logout on key rotation
### Caching & Storage
- [x] **Message Cache** — encrypted per-conversation cache on disk
- [x] **Avatar Cache** — disk + in-memory cache
- [x] **Conversation Cache** — cached list for instant UI
- [x] **Session Persistence** — Double Ratchet states saved encrypted
- [x] **Sender Key Persistence** — group key chains saved encrypted
- [x] **Device Bundle Cache** — 5-minute TTL in-memory
- [x] **Keychain Storage** — biometric-protected credentials
---
## Network Protocol
### Transport
```
TCP → optional TLS → Newline-delimited JSON (\n terminated)
```
### Message Format
```json
{"type": "send_message", "request_id": "uuid", "conversation_id": "...", "ciphertext": "base64..."}
```
### API Methods (36 endpoints)
**Auth:** `register`, `register_confirm`, `login_start`, `login_finish`, `change_username`, `change_password`
**Keys:** `get_key_bundle`, `ensure_prekeys`, `get_prekey_count`, `rotate_keys`, `reset_session`
**Messaging:** `send_message`, `get_messages`, `delete_message`, `mark_read`, `mark_conversation_read`, `react_message`, `pin_message`, `get_pinned_messages`, `get_deleted_since`, `forward_message`, `confirm_delivery`, `search_messages`
**Conversations:** `list_conversations`, `create_conversation`, `find_conversation`, `delete_conversation`, `rename_conversation`, `add_member`, `remove_member`, `leave_group`, `accept_invitation`, `decline_invitation`, `list_invitations`
**Profiles:** `get_profile`, `update_profile`, `update_avatar`, `get_avatar`, `update_group_avatar`, `get_group_avatar`
**Files:** `upload_file`, `download_file`
**Devices:** `list_devices`, `remove_device`, `pairing_start`, `pairing_wait`, `authorize_device`
### Notification Types (17 real-time events)
```
new_message, messages_read, message_deleted, message_reacted,
message_pinned, message_unpinned, message_delivered,
conversation_created, conversation_renamed, conversation_deleted,
member_added, member_removed, group_invitation,
user_online, user_offline, online_users,
session_reset, keys_updated
```
---
## Storage Layout
```
~/Library/Application Support/EncryptedChat/{email}/
├── private.pem # RSA private key (password-protected)
├── public.pem # RSA public key
├── identity_private.bin # Ed25519 private (ECP1: PBKDF2 + AES-GCM)
├── identity_public.bin # Ed25519 public
├── spk_private.bin # Current signed pre-key (X25519)
├── spk_id.txt # SPK ID
├── prevspk_private.bin # Previous SPK (grace period)
├── prevspk_id.txt
├── opk_{id}.bin # One-time pre-keys
├── sessions/
│ └── {userId}_{deviceId}.bin # Double Ratchet state (encrypted)
├── sender_keys/
│ └── {convId}_{senderId}_{deviceId}.bin # Sender Key chain (encrypted)
├── message_cache/
│ └── {convId}.json # Message cache (encrypted)
├── conversations_cache.json # Conversation list cache (encrypted)
├── avatars/
│ └── {convId}.bin # Avatar image data (encrypted)
├── known_identity_keys.bin # TOFU registry (encrypted)
├── verified_contacts.bin # Verified contacts (encrypted)
└── favorites.bin # Favorite conversation IDs (encrypted)
```
---
## Build
```bash
# Xcode build
open /Users/filip/Desktop/kecalek_ios/Kecalek/Kecalek.xcodeproj
# Command-line build
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer \
xcodebuild -scheme Kecalek \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
build
```
**Result:** 57 files, 0 errors, 0 warnings.