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

15 KiB
Raw Blame History

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
  • ChatClientactor, single source of truth for all crypto & network ops
  • Models — plain structs 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

  • Registration — email + password + verification code
  • Login — RSA challenge-response authentication
  • Biometric Login — Face ID / Touch ID via Keychain
  • PoW Challenge — SHA-256 proof-of-work during registration surge
  • Brute-Force Lockout — exponential backoff (2^n seconds, max 300s)
  • Change Username — update display name
  • Change Password — re-encrypt RSA + Ed25519 keys with new PBKDF2 password
  • Key Rotation — regenerate all keys with grace period for in-flight sessions
  • Logout — clean disconnect, clear session

Multi-Device

  • Device Pairing — authorize new device via pairing flow
  • Device List — view all authorized devices
  • Device Removal — revoke device authorization
  • Self-Encryption — own messages readable on all devices

Messaging

  • Text Messages — encrypted DM and group messages
  • Message Replies — reply-to with visual indicator
  • Reactions — 6 emoji reactions (👍❤️😂😮😢👎) with toggle
  • Message Pinning — pin/unpin with pinned messages sheet
  • Message Deletion — soft delete with "Message deleted" indicator
  • Message Forwarding — forward to any conversation with source attribution
  • Message Search — full-text search with result navigation (prev/next)
  • Read Receipts — track who read each message
  • Delivery Receipts — sent → delivered → read indicators (checkmarks)
  • Incremental Sync — fetch only new messages via after_ts
  • Deleted Syncget_deleted_since for incremental deletion sync
  • Message Padding — metadata privacy via bucket-based padding

Media & Files

  • Image Upload — encrypt + chunked upload (24KB chunks)
  • Image Thumbnails — base64 JPEG preview inline
  • Image Viewer — full-screen with pinch zoom
  • File Upload — any file type with mime detection
  • File Download — decrypt + share via system share sheet
  • File Icons — type-based system icons (PDF, DOC, ZIP, etc.)

Conversations

  • Direct Messages — 1-on-1 encrypted chat
  • Group Conversations — multi-member with Sender Keys
  • Create Conversation — new DM or group
  • Rename Conversation — group rename (creator only)
  • Delete Conversation — remove DM or delete group
  • Favorites — pin conversations to top with star icon
  • Unread Counts — per-conversation badge
  • Online Status — real-time presence (green dot)

Group Management

  • Add Member — by email
  • Remove Member — creator only
  • Leave Group — with confirmation
  • Group Avatar — upload/change group photo
  • Group Rename — change group name
  • Group Invitations — accept/decline with banner UI

Profile

  • User Profile — username, email, phone, location
  • Avatar — upload/change profile photo
  • Field Visibility — toggle phone/location visibility
  • View Other Profiles — see other users' info (respects visibility)

Contact Verification

  • Safety Numbers — 60-digit verification code per contact pair
  • Fingerprints — identity key fingerprints
  • QR Code Generation — generate scannable verification QR
  • QR Code Scanning — camera-based QR scan for verification
  • Verification Status — verified (green) / trusted (blue) / unverified (gray)
  • TOFU Registry — track identity key first-seen, detect changes
  • Shield Icon — verification badge in chat toolbar

Connection & Reliability

  • TCP/TLS — Network.framework with optional TLS
  • Configurable Server — host, port, TLS toggle in login screen
  • Connection Indicator — visual status (disconnected/connecting/connected)
  • Auto-Reconnect — exponential backoff (1s → 30s, 5 attempts)
  • Background/Foreground Handling — reconnect when returning from background
  • Auth Failure Detection — immediate logout on key rotation

Caching & Storage

  • Message Cache — encrypted per-conversation cache on disk
  • Avatar Cache — disk + in-memory cache
  • Conversation Cache — cached list for instant UI
  • Session Persistence — Double Ratchet states saved encrypted
  • Sender Key Persistence — group key chains saved encrypted
  • Device Bundle Cache — 5-minute TTL in-memory
  • Keychain Storage — biometric-protected credentials

Network Protocol

Transport

TCP → optional TLS → Newline-delimited JSON (\n terminated)

Message Format

{"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

# 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.