Journal des modifications

Changelog

Chaque version rapproche Fialka de l'invulnérabilité de son ancêtre M-125.

Each release brings Fialka closer to the invulnerability of its M-125 ancestor.

🇫🇷 Français | 🇬🇧 English

🗺 Changelog & Roadmap


✅ V1 — Core

Fondations : chiffrement E2E, contacts via QR, conversations persistantes.

  • Chiffrement E2E (X25519 ECDH + AES-256-GCM)
  • Perfect Forward Secrecy (Double Ratchet X25519)
  • QR Code (génération + scan)
  • Saisie manuelle de clé publique
  • Demandes de contact (envoi, notification inbox, accepter/refuser)
  • Conversations en attente (pending → accepted)
  • Notification d'acceptation en temps réel
  • Profil (pseudo modifiable, copier/partager clé)
  • Suppression de compte complète
  • Design WhatsApp-like
  • Anti-doublons + anti-replay
  • TTL Firebase (7 jours)
  • Hardening crypto (zeroing, mutex, atomic send)
  • Support Android 15 edge-to-edge (targetSdk 35)
  • Re-authentification Firebase automatique après app kill
  • Badge messages non lus sur la liste des conversations
  • Marqueur "Nouveaux messages" dans le chat (disparaît après lecture)
  • Réception des messages en temps réel sur la liste des conversations
  • Push notifications FCM opt-in (Cloud Function + zéro contenu message)
  • Écran Paramètres (push ON/OFF, token supprimable)
  • Fingerprint emojis 96-bit (64 palette × 16 positions, anti-MITM)
  • Profil du contact (empreinte, vérification manuelle, badge chat)
  • SQLCipher — Chiffrement de la base Room locale (256-bit, EncryptedSharedPreferences)
  • Metadata hardening — senderPublicKey + messageIndex supprimés de Firebase (trial decryption)
  • App Lock — Code PIN 6 chiffres + déverrouillage biométrique opt-in
  • Profil amélioré — Cards, en-tête avatar, zone danger, UX modernisée
  • Paramètres améliorés — Sections verrouillage / notifications / sécurité
  • Messages éphémères — Timer côté envoi + côté lecture, durée synchro Firebase
  • Dark mode — Thème DayNight complet, couleurs adaptatives
  • Auto-lock timeout — Configurable (5s → 5min), défaut 5 secondes
  • Sous-écran Fingerprint — Visualisation + vérification dédiée
  • Profil contact redesign — Hub conversation (éphémère, fingerprint, danger zone)
  • 5 thèmes UI — Midnight, Hacker, Phantom (défaut), Aurora, Daylight + sélecteur visuel
  • Animations complètes — Transitions navigation, bulles animées, liste en cascade, toolbar scrollable

✅ V2 — Crypto Upgrade

Full Double Ratchet X25519, remplacement de P-256 par Curve25519.

  • Full Double Ratchet X25519 — DH ratchet + KDF chains + healing automatique
  • X25519 natif — Courbe Curve25519 (API 33+), remplace P-256
  • Initial chains — Les deux côtés peuvent envoyer immédiatement après acceptation
  • Échange d'éphémères naturel — Via les vrais messages, pas de message bootstrap

✅ V2.1 — Account Lifecycle

Backup BIP-39, restauration, suppression complète, détection de comptes morts.

  • Phrase mnémonique BIP-39 — Backup de la clé privée X25519 en 24 mots (256 bits + 8-bit checksum SHA-256)
  • Backup après création — Écran dédié affiche les 24 mots en grille 3 colonnes (confirmation checkbox)
  • Restauration de compte — Saisie de 24 mots + pseudo → restaure clé privée → dérive clé publique (DH base point u=9)
  • Suppression compte complète — Nettoie Firebase : profil /users/{uid}, /inbox/{hash}, /conversations/{id}
  • Nettoyage ancien profilremoveOldUserByPublicKey() supprime l'ancien nœud /users/ orphelin
  • Détection conversation morte — AlertDialog clair ("Conversation supprimée") avec option supprimer
  • Re-invitation contact — Contact local stale nettoyé pour permettre re-invitation
  • Auto-détection à la réception — Inbox listener vérifie conversations stale → nettoyage auto
  • Firebase rules conversation.read et .write restreints au niveau $conversationId

✅ V2.2 — UI Modernization

5 thèmes, animations complètes, CoordinatorLayout, zéro couleur hardcodée.

  • 5 thèmes — Midnight (teal/cyan), Hacker (AMOLED Matrix green), Phantom (anthracite purple, défaut), Aurora (amber/orange), Daylight (clean light blue)
  • 22 attributs de couleurattrs.xml complet : toolbar, bulles, avatars, badges, input bar, surfaces, dividers
  • Sélecteur de thèmes — Grille MaterialCardView avec prévisualisation des couleurs et indicateur de sélection
  • Bulles dynamiques — Couleurs de bulles sent/received par thème via backgroundTint (base blanche + tint)
  • Avatars/badges thématiques — Couleurs d'avatars, badges non lus, FAB, send button adaptées au thème
  • Toolbar thématique — Toutes les toolbars (10+) utilisent ?attr/colorToolbarBackground, elevation 0dp
  • Transitions de navigation — Slide droite/gauche (forward/back), slide haut/bas (modales), fade (onboarding)
  • Animations des bulles — Entrée depuis la droite (sent) / gauche (received), nouveaux messages uniquement
  • Liste animée — Cascade fall-in sur la liste des conversations (8% de décalage)
  • CoordinatorLayout — Toolbar se replie au scroll + réapparaît (scroll|enterAlways|snap)
  • FAB auto-hideHideBottomViewOnScrollBehavior masque le FAB au scroll
  • Zéro couleur hardcodée — Toutes les couleurs UI → ?attr/ (theme-aware)

✅ V3.0 — Security Hardening

Durcissement sécuritaire complet : chiffrement renforcé, anti-analyse de trafic, partage de fichiers E2E.

🛡️ Build & Obfuscation

  • R8/ProGuardisMinifyEnabled=true, isShrinkResources=true, repackaging en release
  • Log strippingLog.d(), Log.v(), Log.i() supprimés par ProGuard (assumenosideeffects)

🔐 Crypto & Métadonnées

  • Delete-after-delivery — Ciphertext supprimé de Firebase RTDB immédiatement après déchiffrement réussi
  • Message padding — Plaintext paddé à taille fixe (256/1K/4K/16K octets) avec header 2 octets + remplissage SecureRandom
  • senderUid HMACsenderUid = HMAC-SHA256(conversationId, UID) tronqué 128 bits — Firebase ne peut plus corréler le même utilisateur entre conversations
  • PBKDF2 PIN — SHA-256 remplacé par PBKDF2-HMAC-SHA256 (600K itérations, salt 16 octets) ; migration auto des anciens hashes

👻 Anti-analyse de trafic

  • Dummy traffic — Messages factices périodiques (45–120s aléatoire) via le vrai Double Ratchet — indistinguables des vrais messages sur le réseau
  • Toggle configurable — Activation/désactivation dans Paramètres → Sécurité → Trafic factice
  • Prefix opaque — Marqueur dummy en octets de contrôle non-imprimables (\u0007\u001B\u0003)

📎 Partage de fichiers E2E

  • Chiffrement par fichier — Clé AES-256-GCM aléatoire par fichier, chiffré côté client
  • Firebase Storage — Upload chiffré, métadonnées (URL + clé + IV + nom + taille) envoyées via le ratchet
  • Réception auto — Download + déchiffrement local + stockage app-private ; fichier Storage supprimé après livraison
  • UI attach — Bouton 📎 dans le chat, file picker, limite 25 Mo, clic pour ouvrir
  • Storage rules — Accès authentifié uniquement, 50 Mo max, chemin /encrypted_files/

🗄️ Base de données

  • Index Room — Index composites : messages(conversationId, timestamp), messages(expiresAt), conversations(accepted), contacts(publicKey)
  • Double-listener guardprocessedFirebaseKeys empêche la désynchronisation ratchet quand 2 listeners traitent le même message

✅ V3.1 — Settings Redesign & PIN Upgrade

Paramètres repensés Signal/Telegram, PIN 6 chiffres, sous-écran Confidentialité, performance PIN.

⚙️ Paramètres

  • Redesign complet — Hiérarchie Signal-like : Général (Apparence, Notifications), Confidentialité, Sécurité, À propos
  • Sous-écran Confidentialité — Messages éphémères, delete-after-delivery, dummy traffic regroupés
  • PrivacyFragment — Nouveau fragment dédié avec navigation intégrée
  • Section À propos — Version dynamique, info chiffrement, licence GPLv3

🔐 Sécurité PIN

  • PIN 6 chiffres — Remplacement du code à 4 chiffres, 6 dots sur l’écran de verrouillage
  • Suppression legacy — Retrait du support SHA-256 et backward compat 4 chiffres
  • Coroutines PIN — Vérification PBKDF2 (600K itérations) sur Dispatchers.Default, zéro freeze UI
  • Cache EncryptedSharedPreferences — Double-checked locking, plus d’init Keystore répétée
  • Vérification unique — Check uniquement au 6ème chiffre (plus de check intermédiaire)

✅ V3.2 — Ed25519 Message Signing

Signature par message Ed25519, badge ✅/⚠️, durcissement Firebase rules, nettoyage clés de signature.

✍️ Signature de messages

  • Ed25519 (BouncyCastle 1.78.1) — Paire de clés de signature dédiée (séparée de X25519)
  • Données signéesciphertext_UTF8 || conversationId_UTF8 || createdAt_bigEndian8 — anti-falsification + anti-replay
  • Provider JCASecurity.removeProvider("BC") + insertProviderAt(BouncyCastleProvider(), 1) dans Application.onCreate()
  • Stockage clé — Clé privée dans EncryptedSharedPreferences ; clé publique sur /signing_keys/{SHA256_hash} et /users/{uid}/signingPublicKey
  • Vérification à la réception — Récupération clé publique Ed25519 par hash d'identité, badge ✅ (valide) ou ⚠️ (invalide/absent)
  • Timestamp clientcreatedAt = System.currentTimeMillis() (pas ServerValue.TIMESTAMP) pour cohérence signature

🛡️ Durcissement Firebase

  • Participants scopés/conversations/$id/participants lisible uniquement par les membres (plus par tous les authentifiés)
  • Nettoyage clés de signature/signing_keys/{hash} supprimé à la suppression de compte

✅ V3.3 — Material 3, Tor Integration, Attachment UX & Log Hardening

Migration complète Material Design 3, intégration Tor (SOCKS5 + VPN TUN), icônes d'attachement inline style Session, permissions Android 13+, durcissement Firebase et logs.

🎨 Material Design 3

  • Migration M2 → M3 — Tous les 5 thèmes migrés de Theme.MaterialComponents vers Theme.Material3.Dark.NoActionBar / Theme.Material3.Light.NoActionBar
  • Rôles de couleur M3 complets — Ajout de colorPrimaryContainer, colorOnPrimary, colorSecondary, colorSurfaceVariant, colorOutline, colorSurfaceContainerHigh/Medium/Low, colorError, etc. sur les 5 thèmes
  • TextInputLayout M3 — Migration vers Widget.Material3.TextInputLayout.OutlinedBox (Onboarding, Restore, AddContact)
  • Boutons M3 — Migration vers Widget.Material3.Button.TextButton / OutlinedButton (TorBootstrap, Onboarding, Profile)
  • Geste prédictif Android 13+enableOnBackInvokedCallback="true" dans le manifest

📎 Icônes d'attachement inline (style Session)

  • Remplacement du BottomSheet — Les 3 options (Fichier 📁, Photo 🖼, Caméra 📷) apparaissent comme des icônes verticales animées au-dessus du bouton +
  • Animation slide-up + fade-in — Les icônes glissent vers le haut avec fondu, le bouton + tourne en × (rotation 45°)
  • Overlay de fermeture — Vue transparente plein écran pour fermer les icônes au tap n'importe où
  • ic_add.xml — Nouvelle icône vectorielle + pour le bouton d'attachement

📱 Permissions Android 13+

  • READ_MEDIA_IMAGES — Permission Android 13+ pour l'accès aux photos
  • READ_MEDIA_AUDIO — Permission Android 13+ pour l'accès aux fichiers audio
  • READ_EXTERNAL_STORAGE — Fallback avec maxSdkVersion="32" pour Android 12 et inférieur
  • Permission launchers — Logique complète de demande de permission avec dialogue de refus

🔥 Corrections Firebase

  • Sign-out Firebase — Suppression de database.goOnline() après auth.signOut() (corrige l'erreur de permission Firebase)
  • Firebase locale — Remplacement de useAppLanguage() par setLanguageCode(Locale.getDefault().language) explicite (corrige X-Firebase-Locale null)
  • Double publication de clé de signature — Flag signingKeyPublished + markSigningKeyPublished() élimine la publication redondante entre OnboardingViewModel et ConversationsViewModel

🛡️ Durcissement des logs

  • ProGuard complet — Ajout de Log.w(), Log.e(), Log.wtf() dans assumenosideeffects (en plus de d/v/i) — suppression totale des logs en release
  • Sanitisation des logs — Suppression des UIDs Firebase, hash de clés et préfixes de clés des messages de log de debug
  • Zéro donnée sensibleFirebaseRelay.kt et ChatRepository.kt n'affichent plus de chemins Firebase ou d'identifiants dans les logs

🧅 Intégration Tor

  • TorManager.kt — Singleton avec StateFlow<TorState> (IDLE, STARTING, BOOTSTRAPPING(%), CONNECTED, ERROR, DISCONNECTED)
  • TorVpnService.kt — Service VPN TUN → hev-socks5-tunnel → SOCKS5 :9050 → Tor → Internet
  • libtor.so + libhev-socks5-tunnel.so — Binaires natifs arm64-v8a embarqués
  • ProxySelector global — Tout le trafic HTTP routé via SOCKS5 127.0.0.1:9050 quand Tor activé
  • Démarrage conditionnelFialkaApplication.onCreate() démarre Tor si activé
  • TorBootstrapFragmentstartDestination du nav graph, choix Tor/Normal au premier lancement
  • Progress circulaire animé — Pourcentage en temps réel, texte de statut dynamique, pulse animation
  • Respecte les 5 thèmes — Couleurs via ?attr/ du thème actif
  • Toggle Tor — ON/OFF dans Paramètres → Sécurité avec reconnexion manuelle
  • Statut temps réel — "Connecté via Tor" / "Reconnexion..." / "Déconnecté"
  • Dummy traffic par conversation — Trafic factice individuel par conversation active

✅ V3.4 — Post-Quantum & Device Security

PQXDH hybride (ML-KEM-1024 + X25519), DeviceSecurityManager StrongBox, QR deep link v2, vérification d'empreinte indépendante, corrections de désynchronisation ratchet.

🔐 Cryptographie Post-Quantique (PQXDH)

  • ML-KEM-1024 (Kyber) — Encapsulation post-quantique via BouncyCastle 1.80, paire clé encaps/decaps dédiée
  • PQXDH hybride — Échange de clés X25519 classique + ML-KEM-1024 encapsulation en parallèle
  • Upgrade différée du rootKey — La première conversation démarre en classique X25519 ; le rootKey est upgradé avec le secret ML-KEM au premier message (pas de message bootstrap)
  • kemCiphertext dans le premier message — Le ciphertext ML-KEM est envoyé une seule fois, dans le premier message Firebase de la conversation
  • QR deep link v2 — Format fialka://contact?key=<X25519>&kem=<ML-KEM-1024-pubKey>&name=<displayName> — clé ML-KEM encodée dans le QR
  • Auto-fill nom depuis QR — Le pseudo du contact est pré-rempli automatiquement depuis le scan QR

🛡️ Sécurité Appareil

  • DeviceSecurityManager — Sonde StrongBox hardware, niveaux de sécurité MAXIMUM/STANDARD
  • Bannière StrongBox — Indicateur visuel dans Paramètres → À propos selon le niveau de sécurité détecté
  • displayName masqué — Le pseudo n'est plus stocké sur Firebase (storeDisplayName → no-op), supprimé des Firebase rules
  • Paramètres réorganisés — Carte sécurité déplacée dans la section À propos, texte chiffrement mis à jour

🔧 Corrections Critiques

  • Fix désynchronisation PQXDHsyncExistingMessages() à l'acceptation d'un contact pour déclencher correctement l'init PQXDH
  • Delete-after-failure — Les messages échoués au déchiffrement sont nettoyés de Firebase (évite boucle d'erreur infinie)
  • lastDeliveredAt — Nouveau champ sur l'entité Conversation pour filtrage lower-bound des messages Firebase (évite re-traitement)
  • Fix dual-listenerConcurrentHashMap.putIfAbsent() + éviction LRU pour empêcher les race conditions sur les listeners Firebase
  • Fix déchiffrement à l'acceptation — Le responder déclenche maintenant le sync des messages existants dès l'acceptation

🔏 Vérification d'empreinte

  • Vérification indépendante — Chaque utilisateur vérifie de son côté (état local Room uniquement, pas de sync d'état)
  • Événements Firebase — Notification événementielle fingerprintEvent: "verified:<timestamp>" (push seulement, pas de sync d'état)
  • Messages système — Info message dans le chat quand un participant vérifie/retire la vérification
  • Lien cliquable — "Voir l'empreinte" dans les messages système redirige vers l'écran fingerprint
  • Toggle vérifier/retirer — Bouton dans FingerprintFragment pour marquer vérifié ou retirer la vérification
  • Badges mis à jour — ✅ Vérifié / ⚠️ Non vérifié (remplace l'ancien format vert/orange)

🗄️ Base de données

  • Room v16 — Migration v15→v16 : ajout colonne lastDeliveredAt sur Conversation
  • Version 3.4.0versionCode 5, versionName "3.4.0"

✅ V3.4.1 — One-Shot Photos, Restore Redesign & QR Fingerprint

Photos éphémères one-shot, écran de restauration repensé avec grille BIP-39, vérification d'empreinte par QR code, améliorations UI.

📸 Photos éphémères One-Shot

  • Envoi one-shot — Option "photo éphémère" : la photo ne peut être vue qu'une seule fois par le destinataire ET l'expéditeur
  • Suppression sécurisée 2 phases — Phase 1 : flag oneShotOpened=1 immédiat dans Room (empêche la re-visualisation) ; Phase 2 : suppression physique du fichier après 5 secondes (délai pour l'app de visualisation)
  • Protection anti-navigation — Le flag DB est posé immédiatement au clic (pas dans un Handler.postDelayed), empêchant le contournement par retour arrière
  • UI expéditeur — 4 états : one-shot expiré (🔥 verrouillé, grisé), one-shot prêt (🔥 "Ouvrir 1 fois"), fichier normal, message texte
  • UI destinataire — 6 états avec gestion one-shot intégrée dans les bulles reçues
  • Indicateur d'envoi — Icône ✓ de confirmation d'envoi dans les bulles

🔑 Écran de restauration repensé

  • Grille BIP-39 professionnelle — 24 cellules AutoCompleteTextView en grille 3×8 avec numérotation
  • Autocomplete BIP-39 — Chaque cellule propose les 2048 mots BIP-39 avec seuil de 1 caractère
  • Auto-avancement — Sélection d'un mot ou Entrée passe automatiquement à la cellule suivante
  • Coloration de focus — Vert = mot valide BIP-39, rouge = mot invalide
  • Compteur de mots — Affichage "X / 24 mots" en temps réel
  • Validation visuelle — Mots invalides surlignés en rouge lors de la tentative de restauration

🔏 QR Code Fingerprint

  • Toggle emoji/QR — Bascule animée (rotation 180° + fade) entre emojis 16 caractères et QR code
  • QR SHA-256 hex — Le QR encode le fingerprint en hexadécimal SHA-256 (64 caractères ASCII, pas les emojis) pour éviter les problèmes d'encodage Unicode
  • Scanner QR fingerprint — Utilise le même CustomScannerActivity que l'invitation de contact (torche, orientation libre)
  • Vérification automatique — Scan QR → comparaison hex ignoreCase → dialogue ✅ match ou ❌ MITM warning
  • Méthode getSharedFingerprintHex() — Nouvelle méthode dans CryptoManager retournant le SHA-256 hex brut des clés publiques triées

🎨 Améliorations UI

  • Dialogue de confirmation d'envoi — Confirmation avant envoi de fichiers
  • Barre de progression — Indicateur d'upload/download de fichiers
  • Bouton retry — Réessayer l'envoi en cas d'échec
  • Protocole affiché — "PQXDH · X25519 + ML-KEM-1024 · AES-256-GCM · Double Ratchet" dans le profil du contact
  • Fix timestamps — Correction de l'affichage des horodatages dans les bulles
  • Fix maxWidth — Largeur maximale des bulles corrigée
  • Audit 29 layouts — Revue complète et corrections des 29 fichiers de layout
  • PIN oublié — Flux de récupération "PIN oublié" avec phrase mnémonique

🗄️ Base de données

  • Room v17 — Migration v16→v17 : ajout colonne oneShotOpened sur MessageLocal
  • flagOneShotOpened() — Nouvelle requête DAO : UPDATE messages SET oneShotOpened = 1 WHERE localId = :messageId
  • Version 3.4.1versionCode 6, versionName "3.4.1"

🛡️ Audit de sécurité (42+ vulnérabilités corrigées)

  • Firebase rules write-once/signing_keys/{hash}, /mlkem_keys/{hash}, /inbox/{hash}/{convId} imposent !data.exists() — empêche l'écrasement de clés et le replay de demandes
  • Firebase rules validationsenderUid.length === 32, ciphertext non-vide + max 65536, iv non-vide + max 100, createdAt <= now + 60000
  • Zeroing mémoire HKDFhkdfExtractExpand() efface IKM, hkdfExpand() efface PRK + expandInput après usage
  • Zeroing mémoire MnemonicprivateKeyToMnemonic() et mnemonicToPrivateKey() effacent tous les tableaux d'octets intermédiaires et nettoient le StringBuilder
  • Validation entrée PQXDHderiveRootKeyPQXDH() exige les deux entrées de 32 octets exactement
  • Séparateur ConversationIdderiveConversationId() utilise "|" pour éviter les collisions de concaténation de clés
  • FLAG_SECURE — Appliqué sur MainActivity, LockScreenActivity, RestoreFragment et le dialog mnemonic — bloque screenshots, enregistrement d'écran, aperçu tâches
  • Masquage mnemonic — Le champ mnemonic du PIN oublié utilise TYPE_TEXT_VARIATION_PASSWORD
  • Seuil autocomplete — Seuil autocomplete BIP-39 augmenté de 1 → 3 caractères
  • Nettoyage RestoreFragment — Les 24 champs de mots sont effacés dans onDestroyView()
  • Durcissement deep links — Réécriture complète de parseInvite() : whitelist paramètres, limites de taille, rejet doublons, rejet caractères de contrôle, validation Base64, max 4000 chars
  • Validation ML-KEM — Validation côté client de la clé publique ML-KEM (longueur < 2500, décodage Base64, taille décodée 1500–1650 octets)
  • Sécurité presse-papiers — Flag EXTRA_IS_SENSITIVE + auto-effacement 30 secondes via Handler.postDelayed
  • SecureFileManager — Nouvel utilitaire : écrasement 2 passes (données aléatoires + zéros, fd.sync()) avant File.delete()
  • Zeroing fileBytessaveFileLocally() appelle fileBytes.fill(0) après écriture
  • Suppression sécurisée one-shot — Les fichiers one-shot utilisent SecureFileManager.secureDelete()
  • Nettoyage conversations mortesdeleteStaleConversation() écrase le répertoire de fichiers de la conversation
  • Nettoyage messages expirésdeleteExpiredMessages() supprime les fichiers associés en premier
  • Guards FirebaseRelaysendMessage() avec require() sur tous les champs (conversationId, ciphertext, iv, taille senderUid, createdAt)
  • Validation Cloud Function — Validation regex pour senderUid (/^[0-9a-f]{32}$/) et format conversationId
  • Payload FCM opaque — Données push réduites à {type: "new_message", sync: "1"} — zéro fuite de metadata
  • Notification génériqueMyFirebaseMessagingService affiche « Nouveau message reçu » (pas de nom, pas d'ID conversation)
  • usesCleartextTraffic=false — Imposé sur <application> — bloque tout trafic HTTP non chiffré
  • filterTouchesWhenObscured — Activé sur MainActivity et LockScreenActivity — protection tapjacking
  • Storage rules suppression par propriétaireresource.metadata['uploaderUid'] == request.auth.uid requis pour supprimer
  • Metadata uploaduploadEncryptedFile() attache uploaderUid dans les StorageMetadata

✅ V3.5 — SPQR, ChaCha20-Poly1305 & Threat Model

Triple Ratchet post-quantique (SPQR), chiffrement alternatif ChaCha20-Poly1305, modèle de menace documenté.

🔐 SPQR — Ré-encapsulation PQ périodique (Triple Ratchet)

  • PQ Ratchet Step — Nouvelle fonction DoubleRatchet.pqRatchetStep() : mixe un secret ML-KEM frais dans le rootKey via HKDF (info: Fialka-SPQR-pq-ratchet)
  • Intervalle de ré-encapsulationPQ_RATCHET_INTERVAL = 10 messages : toutes les 10 messages, le sender effectue un ML-KEM encaps et upgrape le rootKey
  • Sender-side — Dans sendMessage(), quand le compteur atteint 10 et que PQXDH est initialisé : mlkemEncaps(remoteMlkemPublicKey)pqRatchetStep(rootKey, ssPQ) → nouveau rootKey + kemCiphertext attaché au message
  • Receiver-side — Dans receiveMessage(), détection du kemCiphertext sur une session déjà PQ-initialisée : mlkemDecaps()pqRatchetStep() → rootKey upgradé, compteur réinitialisé
  • Compteur persistant — Nouveau champ pqRatchetCounter dans RatchetState (Room entity), incrémenté à chaque message envoyé
  • Compatibilité — Le mécanisme est transparent : pas de champ supplémentaire sur le wire (réutilise kemCiphertext), distingué du PQXDH initial par pqxdhInitialized

🔒 ChaCha20-Poly1305 — Chiffrement alternatif

  • encryptChaCha() / decryptChaCha() — Implémentation complète via BouncyCastle ChaCha20Poly1305 AEAD (nonce 12 octets, tag 16 octets)
  • Détection hardware AEShasHardwareAes() détecte la présence de l'extension ARMv8 Crypto ; ChaCha20 est sélectionné automatiquement sur les appareils sans accélération matérielle AES
  • Sélection dynamique — Le chiffrement de chaque message utilise AES-256-GCM (défaut) ou ChaCha20-Poly1305 selon le hardware du sender
  • Champ cipherSuite — Nouveau champ dans FirebaseMessage (0 = AES-GCM, 1 = ChaCha20) ; le receiver déchiffre avec le bon algorithme automatiquement
  • Rétrocompatibilité — Les anciens messages sans cipherSuite (= 0) sont déchiffrés en AES-GCM comme avant

📋 Modèle de menace documenté

  • SECURITY.md — Ajout d'une section Threat Model complète avec 6 tiers d'adversaires (T1 curious → T6 quantum)
  • Matrice protection/résiduel — Tableau détaillé des protections et risques résiduels par tier
  • Limites documentées — Section explicite « Ce que Fialka ne protège PAS »
  • Principes de design — 7 principes : defense in depth, hybrid PQ, forward secrecy, post-compromise healing, zero trust transport, minimal metadata, fail-safe defaults

🗄️ Base de données

  • Room v18 — Migration v17→v18 : ajout colonne pqRatchetCounter sur RatchetState
  • Version 3.5versionCode 7, versionName "3.5"

✅ V4.0 — Kill Firebase & P2P Pur via Tor

Suppression totale de Firebase, infrastructure P2P pure via Tor Hidden Services, système Mailbox offline 4 modes, identité « 1 Seed → Tout », ML-DSA-44, pipeline de livraison avec statuts, refresh UI 2026. versionCode 8 · versionName "4.0" · Room v24

🔥 Kill Firebase — P2P Pur

  • Suppression totale de Firebase — Firebase BoM, Auth, RTDB, Storage, FCM, Cloud Functions entièrement retirés. Zéro dépendance serveur central.
  • TorTransport — Protocole binaire de trames (magic 0xF1 0xA1), 13 types de trames (P2P + commandes Mailbox), écriture/lecture avec timeout
  • P2PServer — Listener de trames entrantes, dispatch TYPE_MESSAGE, TYPE_CONTACT_REQ, TYPE_KEY_BUNDLE, TYPE_CONTACT_REQ_RESPONSE, etc.
  • OutboxManager — Boucle de retry avec backoff exponentiel (max 50 tentatives, plafond 30 min), DeliveryResult (DIRECT / MAILBOX / QUEUED)
  • UnifiedPush — Notifications sans Firebase

🆔 Identité « 1 Seed → Tout »

  • Seed Ed25519 unique — Dérive : Account ID, adresse .onion, X25519, ML-KEM-1024, ML-DSA-44, fingerprint émoji
  • ML-DSA-44 — Signature post-quantique hybride au handshake de chaque session (Ed25519 + ML-DSA-44 simultanés)
  • AccountIDSHA3-256(pubkey Ed25519) → Base58 (ex : Fa3x...9Z)
  • Adresse .onion déterministe — Dérivée du seed, stable entre réinstallations
  • SeedVerificationFragment — Confirmation de 3 mots après la sauvegarde du seed

🌐 Tor V4

  • Guardian Project Torlibtor.so pour Tor v3 Hidden Services réels
  • Multi-circuit — Circuits actifs affichés en temps réel dans l'interface
  • killOrphanedTor() — Lit le cookie d'auth AVANT suppression (AUTHENTICATE <hex>), empêche les démons orphelins
  • Anti-orphan messagesgetPendingMessages() inclut les messages bloqués en STATUS_SENDING

📬 Système Mailbox (4 modes)

  • Direct P2P — Communication directe, pas de relais
  • Personal.onion personnel comme boîte aux lettres asynchrone
  • Private Node — Nœud privé avec liste blanche membres
  • Public Node — Nœud public ouvert
  • MailboxServer — Stockage opaque de blobs chiffrés, jamais de déchiffrement serveur, contrôle OWNER, TTL 7 jours
  • MailboxClientManager — Polling 60s, _fetching: StateFlow<Boolean> pour bloquer l'UI pendant le fetch
  • Propagation mailboxOnionsenderMailboxOnion inclus dans tous les messages ; P2PServer met à jour participantMailboxOnion à la réception
  • Stats cumulativestotalDeposited, totalFetched, totalDataProcessed persistés en SharedPreferences (blobs supprimés après livraison)
  • Dashboard auto-refresh — Toutes les 30s

📦 Pipeline de livraison avec statuts

  • MessageLocal.deliveryStatusSENT(0) / MAILBOX(1) / FAILED(2) / PENDING(3)
  • OutboxMessage.messageLocalId — Liaison retour vers MessageLocal pour mise à jour du statut
  • Badges de livraison — ✓ Envoyé · 📬 Mailbox · ⏳ En attente · ❌ Échec
  • Bouton Renvoyer — Messages FAILEDOutboxDao.resetRetryForMessage() relance la tentative
  • Bannière fetchfetchBanner + ProgressBar dans le chat, input désactivé pendant le fetch Mailbox

🎨 Refresh UI 2026

  • Settings refactoriséSettingsAdapter + SettingsViewModel, recherche + filtres catégorie (Apparence, Notifications, Confidentialité, Sécurité, Réseau, À propos)
  • ThemeSelectorBottomSheet — Sélecteur visuel 5 thèmes avec prévisualisation en temps réel
  • DurationSelectorBottomSheet — Sélecteur de durée messages éphémères
  • Écran conversations — Eyebrow « MESSAGERIE CHIFFRÉE » (monospace 9sp) + titre 24sp, bande accent gauche 3dp sur chaque item
  • Ajouter un contact — Section hero « CONNEXION SÉCURISÉE », diviseur OR visuel, ConstraintLayoutLinearLayout
  • Profil — Avatar 108dp, eyebrow « GHOST IDENTITY », caption Ed25519 · ML-DSA-44 · ML-KEM-1024 en monospace
  • Profil contact — Eyebrow « NODE INFO », badge E2E pill avec fond bg_key_box

🔧 Corrections critiques pipeline P2P

  • Fix messages orphelinsgetPendingMessages() inclut STATUS_SENDING bloqués (récupération après crash/reboot)
  • Fix resolveRecipientEd25519 — Fallback sur publicKey si signingPublicKey absent
  • Fix sendContactRequest — Retourne Boolean, logs complets
  • Fix killOrphanedTor — Lecture du cookie auth AVANT suppression du fichier

🗄️ Base de données

  • Room v24deliveryStatus sur MessageLocal, messageLocalId + fallbackOnion sur OutboxMessage, migrations v18→v24
  • MailboxDatabase v1 — Entités MailboxBlob, MailboxMember, MailboxInvite (mode MAILBOX uniquement)
  • Version 4.0versionCode 8, versionName "4.0"

✅ V4.0.1 — Sécurité Keystore, Corrections SQLCipher & Fiabilité transport

Remplacement de security-crypto par FialkaSecurePrefs (Keystore direct), correction crash SQLCipher 4.14.1, correction NPE DurationSelectorBottomSheet, fiabilité complète du transport (5 corrections).

🔐 Sécurité — FialkaSecurePrefs (Android Keystore direct)

  • Suppression de security-cryptoandroidx.security:security-crypto:1.1.0-alpha06 et MasterKey.Builder / EncryptedSharedPreferences entièrement retirés
  • FialkaSecurePrefs — Nouvelle implémentation object utilisant l’Android Keystore directement : AES-256-GCM, alias clé fialka_ks_{name}, fichier préférences {name}_v2
  • StrongBox avec fallback TEE — Tentative silencieuse sur StrongBox, retrait automatique vers TEE standard en cas d’absence
  • Migration des 6 fichiersCryptoManager, FialkaDatabase, MailboxDatabase, AppMode, AppLockManager, MailboxClientManager migrés vers FialkaSecurePrefs.open()
  • AGP 8.9.1 + compileSdk 36 + Gradle 8.13 — Mise à niveau de la chaîne de build ; zéro avertissement en release

🐛 Correction — Crash SQLCipher à l’initialisation

  • System.loadLibrary("sqlcipher")sqlcipher-android:4.14.1 supprime l’initialiseur statique ; FialkaApplication.onCreate() charge la bibliothèque native en premier
  • Appels défensifsFialkaDatabase.getInstance() et MailboxDatabase.buildDatabase() appellent également loadLibrary en garde défensive

🐛 Correction — NPE DurationSelectorBottomSheet

  • Paramètre context suppriméDurationSelectorBottomSheet n’accepte plus de Context externe ; BottomSheetDialogFragment dispose de son propre contexte
  • show() simplifié — Suppression de fragmentManager.findFragmentById(R.id.nav_host_fragment)?.requireContext()!! qui retournait null depuis childFragmentManager

⚡ Fiabilité du transport

  • Réduction du délai de retryRETRY_INTERVAL_MS 60 s → 15 s ; plafond MAX_RETRY_DELAY_MS 30 min → 3 min (backoff : 15 s / 30 s / 1 min / 2 min / 3 min)
  • Statut DELIVERY_FAILED sur messages épuisés — Les messages atteignant 50 tentatives reçoivent le statut DELIVERY_FAILED AVANT suppression de la file (corrige le sablier ⏳ permanent)
  • Fallback Mailbox dans processOutboxForContact() — Si le dépôt P2P échoue, dépôt automatique via Mailbox avec mise à jour vers DELIVERY_MAILBOX
  • Sweep Mailbox dans broadcastPresence() — Après la boucle des contacts hors-ligne, processOutbox() est appelé pour traiter les messages en attente
  • Fetch adaptatif MailboxClientManager — Base 10 s, 5 s si messages reçus (+OutboxManager.flushNow()), backoff jusqu’à 60 s sur erreur

📦 Dépendances mises à jour

  • BouncyCastle 1.80 → 1.83 (ML-KEM-1024, Ed25519, ML-DSA-44)
  • SQLCipher 4.5.4 → 4.14.1
  • Room 2.7.1 → 2.8.4
  • Coroutines 1.9.0 → 1.10.2
  • Navigation 2.8.9 → 2.9.7 | Lifecycle 2.8.7 → 2.10.0

🟡 V4.1.0-alpha — Auth Ed25519, Tests Unitaires & Sécurité Migration

versionCode 11 · versionName "4.1.0-alpha" · Correction sécurité + couverture tests + protection UX

🔐 Sécurité — Vérification signature Ed25519 sur les demandes de contact

  • P2PServer.handleContactRequest() — Vérifie maintenant la signature Ed25519 sur les demandes de contact entrantes. Auparavant, senderSigningPublicKey était reçu mais jamais vérifié — n'importe qui pouvait usurper une identité.
  • Données signées canoniquessenderPubKey(UTF-8) || 0x00 || conversationId(UTF-8) || createdAt(big-endian 8 octets) — séparé par domaine, déterministe
  • sendContactRequest() — Signe maintenant le payload avec FialkaNative.ed25519Sign() et inclut le champ requestSignature
  • Rétrocompatible — Les anciens clients sans requestSignature sont encore acceptés (fenêtre de migration progressive)

🧪 Tests Unitaires — Couverture Crypto & Ratchet

  • Robolectric 4.13 ajouté comme dépendance de test
  • CryptoManagerPureTest — 20 tests : déterminisme/commutativité/unicité de deriveConversationId, encodage timestamp buildSignedData, pseudonymat cross-conversation hashSenderUid
  • RatchetSimulationTest — 16 tests : ratchet bidirectionnel, unicité 500 clés, intervalle SPQR=10, correction pqRatchetStep, symétrie initiator/responder
  • DoubleRatchetTest — 2 tests JNI marqués @Ignore (nécessitent libfialka_core.so — à migrer en tests instrumentés)
  • 45 tests unitaires au total, 0 échec

🛡️ Protection UX — Avertissement migration destructive

  • FialkaDatabase.needsDestructiveMigration() — Détecte quand une mise à jour de schéma Room déclencherait fallbackToDestructiveMigration (DROP ALL TABLES)
  • MainActivity — Affiche un AlertDialog bloquant avant tout accès DB lors d'une mise à jour : l'utilisateur doit confirmer explicitement la perte de données ou quitter
  • FialkaDatabase.recordCurrentVersion() — Persiste la version du schéma dans des SharedPreferences simples après ouverture confirmée

🛠 Infrastructure Dev

  • version.properties — Source unique de vérité pour VERSION_CODE + VERSION_NAME ; build.gradle.kts le lit automatiquement — modifier uniquement version.properties pour bumper la version
  • Version V4.1.0-alphaversionCode 11

🔜 V3.6 — Planifié (partiellement livré dans V4.0)

Camouflage avancé, plausible deniability, messages vocaux E2E, sealed sender, améliorations messagerie.

🎭 Camouflage de l’app (App Disguise)

  • Changement d’icône — L’utilisateur choisit une icône de camouflage parmi des présets : Calculatrice, Notes, Actualités, Météo, Horloge, etc.
  • Changement du nom affiché — Le nom de l’app dans le launcher change pour correspondre à l’icône choisie (« Calculatrice », « Notes », « Actualités », etc.)
  • Thèmes d’icône — Chaque déguisement a son icône + nom cohérent (style professionnel)
  • Activity-alias — Implémentation via <activity-alias> dans le manifest (enable/disable dynamique via PackageManager)
  • Confirmation + redémarrage — Dialog de confirmation avec prévisualisation → « Redémarrer maintenant » → kill + relaunch
  • Faux écran de couverture — L’app déguisée ouvre une vraie fausse app fonctionnelle (calculatrice, notes, etc.). Le vrai chat est accessible via un geste secret (long press caché ou code spécial)
  • Persistance — Choix sauvegardé dans SharedPreferences, restauré au démarrage

🔐 Plausible Deniability & Protection

  • Dual PIN — PIN normal ouvre le chat ; PIN de contrainte ouvre un profil vide ou déclenche un wipe silencieux (plausible deniability, niveau journaliste/activiste)
  • Panic button — Secouer le téléphone (shake) → suppression instantanée de toutes les conversations + clés + déconnexion (wipe complet)
  • Screenshot protectionFLAG_SECURE sur toutes les fenêtres ✔️ Fait dans l'audit de sécurité V3.4.1
  • Keyboard incognitoflagNoPersonalizedLearning sur tous les champs de saisie — le clavier ne mémorise/apprend rien

🔐 Crypto avancée

  • Sealed sender — L’identité de l’expéditeur est cachée côté Firebase — le destinataire déduit le sender uniquement après déchiffrement

💬 Messagerie avancée

  • Messages vocaux E2E — Enregistrement audio, chiffrement AES-256-GCM, envoi via le ratchet, lecteur inline dans le chat
  • Reply / Quote — Répondre à un message spécifique avec citation (bulle citée + nouveau message)
  • Groupes — Conversations à 3+ participants (Sender Keys)
  • Suppression pour tous — Supprimer un message côté local + Firebase
  • Typing indicators — « En train d’écrire... » (chiffré E2E, opt-in)

🛡️ Infrastructure

  • Relay privé — Serveur relay dédié pour réduire la dépendance Firebase

← Retour au README

🇫🇷 Français | 🇬🇧 English

🗺 Changelog & Roadmap


✅ V1 — Core

Foundations: E2E encryption, contacts via QR, persistent conversations.

  • E2E Encryption (X25519 ECDH + AES-256-GCM)
  • Perfect Forward Secrecy (Double Ratchet X25519)
  • QR Code (generation + scanning)
  • Manual public key input
  • Contact requests (sending, inbox notification, accept/reject)
  • Pending conversations (pending → accepted)
  • Real-time acceptance notification
  • Profile (editable nickname, copy/share key)
  • Full account deletion
  • WhatsApp-like design
  • Anti-duplicate + anti-replay
  • Firebase TTL (7 days)
  • Crypto hardening (zeroing, mutex, atomic send)
  • Android 15 edge-to-edge support (targetSdk 35)
  • Automatic Firebase re-authentication after app kill
  • Unread messages badge on conversations list
  • "New messages" separator in chat (disappears after reading)
  • Real-time message reception on the conversations list
  • Opt-in FCM push notifications (Cloud Function + zero message content)
  • Settings screen (push ON/OFF, removable token)
  • Fingerprint emojis 96-bit (64 palette × 16 positions, anti-MITM)
  • Contact profile (fingerprint, manual verification, chat badge)
  • SQLCipher — Local Room database encryption (256-bit, EncryptedSharedPreferences)
  • Metadata hardening — senderPublicKey + messageIndex removed from Firebase (trial decryption)
  • App Lock — 6-digit PIN + opt-in biometric unlock
  • Profile improvement — Cards, avatar header, danger zone, modernized UX
  • Settings improvement — Lock / notifications / security sections
  • Ephemeral messages — Timer on send + on read, duration synced on Firebase
  • Dark mode — Full DayNight theme, adaptive colors
  • Auto-lock timeout — Configurable (5s → 5min), default 5 seconds
  • Fingerprint sub-screen — Visualization + dedicated verification
  • Contact profile redesign — Conversation hub (ephemeral, fingerprint, danger zone)
  • 5 UI themes — Midnight, Hacker, Phantom (default), Aurora, Daylight + visual selector
  • Full animations — Navigation transitions, animated bubbles, cascade list, scrollable toolbar

✅ V2 — Crypto Upgrade

Full Double Ratchet X25519, replaced P-256 with Curve25519.

  • Full Double Ratchet X25519 — DH ratchet + KDF chains + automatic healing
  • Native X25519 — Curve25519 (API 33+), replaces P-256
  • Initial chains — Both sides can send immediately after acceptance
  • Natural ephemeral exchange — Via real messages, no bootstrap message

✅ V2.1 — Account Lifecycle

BIP-39 backup, restore, full deletion, dead account detection.

  • BIP-39 mnemonic phrase — X25519 private key backup in 24 words (256 bits + 8-bit SHA-256 checksum)
  • Backup after creation — Dedicated screen shows 24 words in 3 columns (confirmation checkbox)
  • Account restore — Input 24 words + nickname → restore private key → derive public key (DH base point u=9)
  • Full account deletion — Cleans Firebase: profile /users/{uid}, /inbox/{hash}, /conversations/{id}
  • Old profile cleanupremoveOldUserByPublicKey() removes the orphaned old /users/ node
  • Dead conversation detection — Clear AlertDialog ("Conversation deleted") with delete option
  • Contact re-invitation — Stale local contact cleaned up to allow re-invitation
  • Auto-detection on receipt — Inbox listener checks stale conversations → auto cleanup
  • Conversation Firebase rules.read and .write restricted at $conversationId level

✅ V2.2 — UI Modernization

5 themes, full animations, CoordinatorLayout, zero hardcoded colors.

  • 5 themes — Midnight (teal/cyan), Hacker (AMOLED Matrix green), Phantom (anthracite purple, default), Aurora (amber/orange), Daylight (clean light blue)
  • 22 color attributes — Full attrs.xml: toolbar, bubbles, avatars, badges, input bar, surfaces, dividers
  • Theme selector — MaterialCardView grid with color preview and selection indicator
  • Dynamic bubbles — Sent/received bubble colors by theme via backgroundTint (white base + tint)
  • Themed avatars/badges — Avatars, unread badges, FAB, send button colors adapt to theme
  • Themed toolbar — All toolbars (10+) use ?attr/colorToolbarBackground, elevation 0dp
  • Navigation transitions — Right/left slide (forward/back), up/down slide (modals), fade (onboarding)
  • Bubble animations — Entrance from right (sent) / left (received), new messages only
  • Animated list — Fall-in cascade on the conversations list (8% delay)
  • CoordinatorLayout — Toolbar collapses on scroll + snaps back (scroll|enterAlways|snap)
  • Auto-hide FABHideBottomViewOnScrollBehavior hides the FAB on scroll
  • Zero hardcoded colors — All UI colors → ?attr/ (theme-aware)

✅ V3.0 — Security Hardening

Complete security hardening: reinforced encryption, traffic analysis countermeasures, E2E file sharing.

🛡️ Build & Obfuscation

  • R8/ProGuardisMinifyEnabled=true, isShrinkResources=true, repackaging in release builds
  • Log strippingLog.d(), Log.v(), Log.i() removed by ProGuard (assumenosideeffects)

🔐 Crypto & Metadata

  • Delete-after-delivery — Ciphertext removed from Firebase RTDB immediately after successful decryption
  • Message padding — Plaintext padded to fixed-size buckets (256/1K/4K/16K bytes) with 2-byte header + SecureRandom fill
  • senderUid HMACsenderUid = HMAC-SHA256(conversationId, UID) truncated to 128 bits — Firebase cannot correlate the same user across conversations
  • PBKDF2 PIN — PBKDF2-HMAC-SHA256 (600K iterations, 16-byte salt); 6-digit PIN enforced

👻 Traffic Analysis Countermeasures

  • Dummy traffic — Periodic cover messages (45–120s random interval) via real Double Ratchet — indistinguishable from real messages on the wire
  • Configurable toggle — Enable/disable in Settings → Security → Cover Traffic
  • Opaque prefix — Dummy marker uses non-printable control bytes (\u0007\u001B\u0003)

📎 E2E File Sharing

  • Per-file encryption — Random AES-256-GCM key per file, encrypted client-side
  • Firebase Storage — Upload encrypted, metadata (URL + key + IV + name + size) sent via the ratchet
  • Auto-receive — Download + local decryption + app-private storage; Storage file deleted after delivery
  • Attach UI — 📎 button in chat, file picker, 25 MB limit, tap to open
  • Storage rules — Authenticated-only access, 50 MB max, restricted to /encrypted_files/ path

🗄️ Database

  • Room indexes — Composite indexes: messages(conversationId, timestamp), messages(expiresAt), conversations(accepted), contacts(publicKey)
  • Double-listener guardprocessedFirebaseKeys prevents ratchet desync when 2 listeners process the same message

✅ V3.1 — Settings Redesign & PIN Upgrade

Signal/Telegram-style settings, 6-digit PIN, Privacy sub-screen, PIN performance.

⚙️ Settings

  • Full redesign — Signal-like hierarchy: General (Appearance, Notifications), Privacy, Security, About
  • Privacy sub-screen — Ephemeral messages, delete-after-delivery, dummy traffic grouped together
  • PrivacyFragment — Dedicated fragment with integrated navigation
  • About section — Dynamic version, encryption info, GPLv3 license

🔐 PIN Security

  • 6-digit PIN — Replaced 4-digit code, 6 dots on lock screen
  • Legacy removal — Removed SHA-256 support and 4-digit backward compatibility
  • PIN coroutines — PBKDF2 verification (600K iterations) on Dispatchers.Default, zero UI freeze
  • Cached EncryptedSharedPreferences — Double-checked locking, no repeated Keystore init
  • Single verification — Check only at 6th digit (no intermediate checks)

✅ V3.2 — Ed25519 Message Signing

Per-message Ed25519 signatures, ✅/⚠️ badge, Firebase rules hardening, signing key cleanup.

✍️ Message Signing

  • Ed25519 (BouncyCastle 1.78.1) — Dedicated signing key pair (separate from X25519)
  • Signed dataciphertext_UTF8 || conversationId_UTF8 || createdAt_bigEndian8 — anti-forgery + anti-replay
  • JCA ProviderSecurity.removeProvider("BC") + insertProviderAt(BouncyCastleProvider(), 1) in Application.onCreate()
  • Key storage — Private key in EncryptedSharedPreferences; public key at /signing_keys/{SHA256_hash} and /users/{uid}/signingPublicKey
  • Verification on receive — Fetches Ed25519 public key by identity hash, badge ✅ (valid) or ⚠️ (invalid/missing)
  • Client timestampcreatedAt = System.currentTimeMillis() (not ServerValue.TIMESTAMP) for signature consistency

🛡️ Firebase Hardening

  • Scoped participants/conversations/$id/participants readable only by members (no longer by all authenticated users)
  • Signing key cleanup/signing_keys/{hash} deleted on account deletion

✅ V3.3 — Material 3, Tor Integration, Attachment UX & Log Hardening

Full Material Design 3 migration, Tor integration (SOCKS5 + VPN TUN), Session-style inline attachment icons, Android 13+ permissions, Firebase & log hardening.

🎨 Material Design 3

  • M2 → M3 Migration — All 5 themes migrated from Theme.MaterialComponents to Theme.Material3.Dark.NoActionBar / Theme.Material3.Light.NoActionBar
  • Full M3 color roles — Added colorPrimaryContainer, colorOnPrimary, colorSecondary, colorSurfaceVariant, colorOutline, colorSurfaceContainerHigh/Medium/Low, colorError, etc. across all 5 themes
  • M3 TextInputLayout — Migrated to Widget.Material3.TextInputLayout.OutlinedBox (Onboarding, Restore, AddContact)
  • M3 Buttons — Migrated to Widget.Material3.Button.TextButton / OutlinedButton (TorBootstrap, Onboarding, Profile)
  • Predictive back gestureenableOnBackInvokedCallback="true" in manifest for Android 13+

📎 Inline Attachment Icons (Session-style)

  • BottomSheet replaced — 3 options (File 📁, Photo 🖼, Camera 📷) appear as animated vertical icons above the + button
  • Slide-up + fade-in animation — Icons slide up with fade, + button rotates to × (45° rotation)
  • Dismiss overlay — Full-screen transparent view to dismiss icons on tap anywhere
  • ic_add.xml — New vector + icon for attachment button

📱 Android 13+ Permissions

  • READ_MEDIA_IMAGES — Android 13+ permission for photo access
  • READ_MEDIA_AUDIO — Android 13+ permission for audio file access
  • READ_EXTERNAL_STORAGE — Fallback with maxSdkVersion="32" for Android 12 and below
  • Permission launchers — Full permission request logic with denial dialog

🔥 Firebase Fixes

  • Firebase sign-out — Removed database.goOnline() after auth.signOut() (fixes Firebase permission error)
  • Firebase locale — Replaced useAppLanguage() with explicit setLanguageCode(Locale.getDefault().language) (fixes X-Firebase-Locale null)
  • Double signing key publishsigningKeyPublished flag + markSigningKeyPublished() eliminates redundant publish between OnboardingViewModel and ConversationsViewModel

🛡️ Log Hardening

  • Complete ProGuard stripping — Added Log.w(), Log.e(), Log.wtf() to assumenosideeffects (on top of d/v/i) — total log suppression in release
  • Log sanitization — Removed Firebase UIDs, key hashes and key prefixes from debug log messages
  • Zero sensitive dataFirebaseRelay.kt and ChatRepository.kt no longer print Firebase paths or identifiers in logs

🧅 Tor Integration

  • TorManager.kt — Singleton with StateFlow<TorState> (IDLE, STARTING, BOOTSTRAPPING(%), CONNECTED, ERROR, DISCONNECTED)
  • TorVpnService.kt — VPN TUN service → hev-socks5-tunnel → SOCKS5 :9050 → Tor → Internet
  • libtor.so + libhev-socks5-tunnel.so — Native arm64-v8a binaries embedded
  • Global ProxySelector — All HTTP traffic routed via SOCKS5 127.0.0.1:9050 when Tor enabled
  • Conditional startupFialkaApplication.onCreate() starts Tor if enabled
  • TorBootstrapFragmentstartDestination of nav graph, Tor/Normal choice on first launch
  • Animated circular progress — Real-time percentage, dynamic status text, pulse animation
  • Respects all 5 themes — Colors via ?attr/ from active theme
  • Tor toggle — ON/OFF in Settings → Security with manual reconnect
  • Real-time status — "Connected via Tor" / "Reconnecting..." / "Disconnected"
  • Per-conversation dummy traffic — Individual cover messages per active conversation

✅ V3.4 — Post-Quantum & Device Security

Hybrid PQXDH (ML-KEM-1024 + X25519), StrongBox DeviceSecurityManager, QR deep link v2, independent fingerprint verification, ratchet desync fixes.

🔐 Post-Quantum Cryptography (PQXDH)

  • ML-KEM-1024 (Kyber) — Post-quantum encapsulation via BouncyCastle 1.80, dedicated encaps/decaps key pair
  • Hybrid PQXDH — Classic X25519 key exchange + ML-KEM-1024 encapsulation in parallel
  • Deferred rootKey upgrade — Initial conversation starts classic X25519-only; rootKey is upgraded with ML-KEM secret on the first message (no bootstrap message)
  • kemCiphertext in first message — ML-KEM ciphertext sent once, in the first Firebase message of the conversation
  • QR deep link v2 — Format fialka://contact?key=<X25519>&kem=<ML-KEM-1024-pubKey>&name=<displayName> — ML-KEM key encoded in QR
  • Auto-fill name from QR — Contact nickname auto-populated from QR scan data

🛡️ Device Security

  • DeviceSecurityManager — StrongBox hardware probe, MAXIMUM/STANDARD security levels
  • StrongBox banner — Visual indicator in Settings → About based on detected security level
  • displayName hidden — Nickname no longer stored on Firebase (storeDisplayName → no-op), removed from Firebase rules
  • Settings reorganized — Security card moved to About section, encryption text updated

🔧 Critical Fixes

  • PQXDH desync fixsyncExistingMessages() on contact acceptance to properly trigger PQXDH init
  • Delete-after-failure — Failed decryption messages cleaned from Firebase (prevents infinite error loop)
  • lastDeliveredAt — New field on Conversation entity for Firebase message lower-bound filtering (prevents re-processing)
  • Dual-listener fixConcurrentHashMap.putIfAbsent() + LRU eviction to prevent race conditions on Firebase listeners
  • Decryption-on-accept fix — Responder now triggers existing message sync on acceptance

🔏 Fingerprint Verification

  • Independent verification — Each user verifies on their own side (local Room state only, no state sync)
  • Firebase events — Event-based notification fingerprintEvent: "verified:<timestamp>" (push only, no state sync)
  • System messages — Info message in chat when a participant verifies/un-verifies
  • Clickable link — "View fingerprint" in system messages navigates to the fingerprint screen
  • Verify/un-verify toggle — Button in FingerprintFragment to mark verified or remove verification
  • Updated badges — ✅ Verified / ⚠️ Unverified (replaces old green/orange format)

🗄️ Database

  • Room v16 — Migration v15→v16: added lastDeliveredAt column on Conversation
  • Version 3.4.0versionCode 5, versionName "3.4.0"

✅ V3.4.1 — One-Shot Photos, Restore Redesign & QR Fingerprint

One-shot ephemeral photos, redesigned restore screen with BIP-39 grid, QR code fingerprint verification, UI improvements.

📸 One-Shot Ephemeral Photos

  • One-shot send — "Ephemeral photo" option: photo can only be viewed once by both the recipient AND the sender
  • 2-phase secure deletion — Phase 1: immediate oneShotOpened=1 flag in Room (prevents re-viewing); Phase 2: physical file deletion after 5 seconds (delay for viewer app to load)
  • Anti-navigation bypass — DB flag is set immediately on click (not in Handler.postDelayed), preventing back-navigation circumvention
  • Sender UI — 4 states: one-shot expired (🔥 locked, grayed), one-shot ready (🔥 "Open once"), normal file, text message
  • Receiver UI — 6 states with integrated one-shot handling in received bubbles
  • Send indicator — ✓ check icon confirmation in sent bubbles

🔑 Redesigned Restore Screen

  • Professional BIP-39 grid — 24 AutoCompleteTextView cells in 3×8 grid with numbering
  • BIP-39 autocomplete — Each cell suggests from 2048 BIP-39 words with 1-character threshold
  • Auto-advance — Word selection or Enter automatically moves to the next cell
  • Focus coloring — Green = valid BIP-39 word, red = invalid word
  • Word counter — Real-time "X / 24 words" display
  • Visual validation — Invalid words highlighted in red on restore attempt

🔏 QR Code Fingerprint

  • Emoji/QR toggle — Animated toggle (180° rotation + fade) between 16-char emojis and QR code
  • QR SHA-256 hex — QR encodes the fingerprint as SHA-256 hex (64 ASCII chars, not emojis) to avoid Unicode encoding issues
  • QR fingerprint scanner — Uses the same CustomScannerActivity as contact invitation (torch, free orientation)
  • Automatic verification — QR scan → hex comparison ignoreCase → ✅ match dialog or ❌ MITM warning dialog
  • getSharedFingerprintHex() method — New CryptoManager method returning raw SHA-256 hex of sorted public keys

🎨 UI Improvements

  • Send confirmation dialog — Confirmation before sending files
  • Progress bar — File upload/download indicator
  • Retry button — Retry send on failure
  • Protocol display — "PQXDH · X25519 + ML-KEM-1024 · AES-256-GCM · Double Ratchet" shown in contact profile
  • Timestamp fix — Fixed timestamp display in message bubbles
  • maxWidth fix — Corrected maximum bubble width
  • 29 layout audit — Complete review and fixes of all 29 layout files
  • Forgot PIN — PIN recovery flow via mnemonic phrase

🗄️ Database

  • Room v17 — Migration v16→v17: added oneShotOpened column on MessageLocal
  • flagOneShotOpened() — New DAO query: UPDATE messages SET oneShotOpened = 1 WHERE localId = :messageId
  • Version 3.4.1versionCode 6, versionName "3.4.1"

🛡️ Security Audit (42+ vulnerabilities fixed)

  • Firebase rules write-once/signing_keys/{hash}, /mlkem_keys/{hash}, /inbox/{hash}/{convId} now enforce !data.exists() — prevents key overwrite and contact request replay
  • Firebase rules validationsenderUid.length === 32, ciphertext non-empty + max 65536, iv non-empty + max 100, createdAt <= now + 60000
  • HKDF memory zeroinghkdfExtractExpand() zeros IKM, hkdfExpand() zeros PRK + expandInput after use
  • Mnemonic memory zeroingprivateKeyToMnemonic() and mnemonicToPrivateKey() zero all intermediate byte arrays and clear StringBuilder
  • PQXDH input validationderiveRootKeyPQXDH() requires both inputs exactly 32 bytes
  • ConversationId separatorderiveConversationId() uses "|" separator to prevent key concatenation collisions
  • FLAG_SECURE — Applied on MainActivity, LockScreenActivity, RestoreFragment, and mnemonic dialog — blocks screenshots, screen recording, task switcher
  • Mnemonic masking — Forgot-PIN mnemonic input uses TYPE_TEXT_VARIATION_PASSWORD
  • Autocomplete threshold — BIP-39 autocomplete threshold raised from 1 → 3 characters
  • RestoreFragment wipe — All 24 word inputs wiped in onDestroyView()
  • Deep link hardening — Complete rewrite of parseInvite(): parameter whitelist, length limits, duplicate rejection, control char rejection, Base64 validation, 4000-char max
  • ML-KEM validation — Client-side ML-KEM public key validation (length < 2500, Base64 decode, decoded size 1500–1650 bytes)
  • Clipboard securityEXTRA_IS_SENSITIVE flag + 30-second auto-clear via Handler.postDelayed
  • SecureFileManager — New utility: 2-pass overwrite (random data + zeros, fd.sync()) before File.delete()
  • File bytes zeroingsaveFileLocally() calls fileBytes.fill(0) after writing
  • Secure one-shot delete — One-shot files use SecureFileManager.secureDelete()
  • Stale conversation wipedeleteStaleConversation() securely wipes conversation files directory
  • Expired message wipedeleteExpiredMessages() securely deletes associated files first
  • FirebaseRelay guardssendMessage() has require() on all fields (conversationId, ciphertext, iv, senderUid length, createdAt)
  • Cloud Function validation — Regex validation for senderUid (/^[0-9a-f]{32}$/) and conversationId format
  • Opaque FCM payload — Push data reduced to {type: "new_message", sync: "1"} — zero metadata leakage
  • Generic notificationMyFirebaseMessagingService shows "Nouveau message reçu" (no sender name, no conversation ID)
  • usesCleartextTraffic=false — Enforced on <application> — blocks all unencrypted HTTP
  • filterTouchesWhenObscured — Enabled on MainActivity and LockScreenActivity — tapjacking protection
  • Storage rules owner-only deleteresource.metadata['uploaderUid'] == request.auth.uid required for delete
  • Upload metadatauploadEncryptedFile() attaches uploaderUid StorageMetadata

✅ V3.5 — SPQR, ChaCha20-Poly1305 & Threat Model

Post-quantum Triple Ratchet (SPQR), alternative ChaCha20-Poly1305 cipher, documented threat model.

🔐 SPQR — Periodic PQ Re-encapsulation (Triple Ratchet)

  • PQ Ratchet Step — New DoubleRatchet.pqRatchetStep() function: mixes a fresh ML-KEM secret into rootKey via HKDF (info: Fialka-SPQR-pq-ratchet)
  • Re-encapsulation intervalPQ_RATCHET_INTERVAL = 10 messages: every 10 messages, the sender performs ML-KEM encaps and upgrades rootKey
  • Sender-side — In sendMessage(), when counter reaches 10 and PQXDH is initialized: mlkemEncaps(remoteMlkemPublicKey)pqRatchetStep(rootKey, ssPQ) → new rootKey + kemCiphertext attached to message
  • Receiver-side — In receiveMessage(), detects kemCiphertext on an already PQ-initialized session: mlkemDecaps()pqRatchetStep() → rootKey upgraded, counter reset
  • Persistent counter — New pqRatchetCounter field in RatchetState (Room entity), incremented on every sent message
  • Compatibility — Transparent mechanism: no extra wire field (reuses kemCiphertext), distinguished from initial PQXDH by pqxdhInitialized flag

🔒 ChaCha20-Poly1305 — Alternative Cipher

  • encryptChaCha() / decryptChaCha() — Full implementation via BouncyCastle ChaCha20Poly1305 AEAD (12-byte nonce, 16-byte tag)
  • Hardware AES detectionhasHardwareAes() detects ARMv8 Crypto Extension; ChaCha20 is auto-selected on devices without hardware AES acceleration
  • Dynamic selection — Each message uses AES-256-GCM (default) or ChaCha20-Poly1305 based on sender hardware
  • cipherSuite field — New field in FirebaseMessage (0 = AES-GCM, 1 = ChaCha20); receiver decrypts with the correct algorithm automatically
  • Backward compatibility — Old messages without cipherSuite (= 0) are decrypted with AES-GCM as before

📋 Documented Threat Model

  • SECURITY.md — Added comprehensive Threat Model section with 6 adversary tiers (T1 curious → T6 quantum)
  • Protection/residual matrix — Detailed table of protections and residual risks per tier
  • Documented limitations — Explicit section "What Fialka does NOT protect against"
  • Design principles — 7 principles: defense in depth, hybrid PQ, forward secrecy, post-compromise healing, zero trust transport, minimal metadata, fail-safe defaults

🗄️ Database

  • Room v18 — Migration v17→v18: added pqRatchetCounter column to RatchetState
  • Version 3.5versionCode 7, versionName "3.5"

✅ V4.0 — Kill Firebase & Pure P2P via Tor

Complete Firebase removal, pure P2P infrastructure via Tor Hidden Services, 4-mode offline Mailbox system, "1 Seed → Everything" identity, ML-DSA-44 hybrid post-quantum handshake, delivery pipeline with status badges, 2026 UI refresh. versionCode 8 · versionName "4.0" · Room v24

🔥 Kill Firebase — Pure P2P

  • Complete Firebase removal — Firebase BoM, Auth, RTDB, Storage, FCM, Cloud Functions fully removed. Zero central server dependency.
  • TorTransport — Binary frame protocol (magic 0xF1 0xA1), 13 frame types (P2P + Mailbox commands), read/write with timeout
  • P2PServer — Incoming frame listener, dispatch for TYPE_MESSAGE, TYPE_CONTACT_REQ, TYPE_KEY_BUNDLE, TYPE_CONTACT_REQ_RESPONSE, etc.
  • OutboxManager — Retry loop with exponential backoff (max 50 attempts, 30-min cap), DeliveryResult enum (DIRECT / MAILBOX / QUEUED)
  • UnifiedPush — Notifications without Firebase dependency

🆔 Identity "1 Seed → Everything"

  • Single Ed25519 seed — Derives: Account ID, .onion address, X25519, ML-KEM-1024, ML-DSA-44, emoji fingerprint
  • ML-DSA-44 — Post-quantum hybrid signature at every session handshake (Ed25519 + ML-DSA-44 simultaneously)
  • AccountIDSHA3-256(Ed25519 pubkey) → Base58 (e.g. Fa3x...9Z)
  • Deterministic .onion address — Derived from seed, stable across reinstalls
  • SeedVerificationFragment — 3-word confirmation after seed backup

🌐 Tor V4

  • Guardian Project Torlibtor.so for real Tor v3 Hidden Services
  • Multi-circuit — Active circuits shown in real-time in the UI
  • killOrphanedTor() — Reads auth cookie BEFORE deletion (AUTHENTICATE <hex>), prevents orphaned daemons
  • Anti-orphan messagesgetPendingMessages() includes messages stuck in STATUS_SENDING

📬 Mailbox System (4 modes)

  • Direct P2P — Direct communication, no relay
  • Personal — Personal .onion as async mailbox
  • Private Node — Private node with member whitelist
  • Public Node — Open public node
  • MailboxServer — Opaque encrypted blob storage, zero server-side decryption, OWNER access control, 7-day TTL
  • MailboxClientManager — 60s polling, _fetching: StateFlow<Boolean> to block UI during fetch
  • mailboxOnion propagationsenderMailboxOnion included in all outgoing messages; P2PServer updates participantMailboxOnion on receipt
  • Cumulative statstotalDeposited, totalFetched, totalDataProcessed persisted in SharedPreferences (blobs deleted after delivery)
  • Dashboard auto-refresh — Every 30 seconds

📦 Delivery Pipeline with Status Badges

  • MessageLocal.deliveryStatusSENT(0) / MAILBOX(1) / FAILED(2) / PENDING(3)
  • OutboxMessage.messageLocalId — Back-link to MessageLocal for status updates
  • Delivery badges — ✓ Sent · 📬 Mailbox · ⏳ Pending · ❌ Failed — displayed in outgoing message bubbles
  • Resend buttonFAILED messages show a Resend button; OutboxDao.resetRetryForMessage() re-queues the attempt
  • Fetch bannerfetchBanner + ProgressBar in chat, input disabled during Mailbox fetch

🎨 2026 UI Refresh

  • Settings overhaulSettingsAdapter + SettingsViewModel, search bar + category filters (Appearance, Notifications, Privacy, Security, Network, About)
  • ThemeSelectorBottomSheet — Visual 5-theme picker with live preview
  • DurationSelectorBottomSheet — Ephemeral message duration selector
  • Conversations screen — "MESSAGERIE CHIFFRÉE" eyebrow (9sp monospace) + 24sp bold title, 3dp colorPrimary accent strip on each item
  • Add contact — "CONNEXION SÉCURISÉE" hero section, visual OR divider, ConstraintLayoutLinearLayout
  • Profile — 108dp avatar ring, "GHOST IDENTITY" eyebrow, Ed25519 · ML-DSA-44 · ML-KEM-1024 monospace caption
  • Contact profile — "NODE INFO" eyebrow, E2E badge pill with bg_key_box background

🔧 Critical P2P Pipeline Fixes

  • Orphan message fixgetPendingMessages() includes STATUS_SENDING stuck messages (recovery after crash/reboot)
  • resolveRecipientEd25519 fix — Fallback to publicKey if signingPublicKey absent
  • sendContactRequest fix — Returns Boolean, full logging
  • killOrphanedTor fix — Reads auth cookie BEFORE deleting the file

🗄️ Database

  • Room v24deliveryStatus on MessageLocal, messageLocalId + fallbackOnion on OutboxMessage, migrations v18→v24
  • MailboxDatabase v1MailboxBlob, MailboxMember, MailboxInvite entities (MAILBOX mode only)
  • Version 4.0versionCode 8, versionName "4.0"

✅ V4.0.2 — Fialka-Core Rust JNI Bridge

Native Rust cryptography migration — all crypto is now executed inside the fialka-core Rust library, exposed via a JNI bridge. Complete removal of BouncyCastle.

🦀 Rust JNI Bridge (Fialka-Core)

  • 30 JNI functions implemented in Fialka-Core/src/ffi/mod.rs via the jni = 0.21 crate
  • FialkaNative.kt — Kotlin bridge object, System.loadLibrary("fialka_core"), 30 external fun
  • libfialka_core.so — compiled with cargo-ndk for arm64-v8a (906 KB) and x86_64 (984 KB)
  • git submoduleFialka-Core/ integrated as a submodule in Fialka-Android

🔐 Cryptographic migration

  • CryptoManager.kt — 100% migrated: all BouncyCastle calls replaced with FialkaNative
    • identityDerive → 8704-byte bundle (Ed25519, X25519, ML-KEM-1024, ML-DSA-44)
    • encryptAes / decryptAes → FialkaNative.encryptAes / decryptAes
    • encryptChaCha / decryptChaCha → FialkaNative (12-byte nonce, 16-byte tag)
    • encryptFile / decryptFile → FialkaNative (format: key[32] || iv[12] || CT)
    • hmacSha256 → FialkaNative.hmacSha256
    • hkdfZeroSalt / key derivation → FialkaNative.hkdfZeroSalt
    • ed25519Sign / ed25519Verify → FialkaNative
    • x25519Dh → FialkaNative (strip JCA ASN.1 prefixes: X509 12 bytes, PKCS8 16 bytes)
    • mlkemEncaps / mlkemDecaps → FialkaNative
    • mldsaSign / mldsaVerify → FialkaNative
    • deriveRootKeyPqxdh → FialkaNative
    • computeOnion / ed25519ToX25519Raw → FialkaNative
  • TorTransport.ktsignEd25519 / verifyEd25519 migrated to FialkaNative
  • build.gradle.ktsorg.bouncycastle:bcprov-jdk18on:1.83 dependency removed
  • Robolectric + JVM tests removed (incompatible with JNI); tests migrated to androidTest

🧩 Cross-platform

  • Same Rust library used on Android (JNI) and on any other target (Windows/Linux/iOS via FFI)
  • Version V4.0.2versionCode 10

🟡 V4.1.0-alpha — Ed25519 Contact Auth, Unit Tests & Migration Safety

versionCode 11 · versionName "4.1.0-alpha" · Security fix + test coverage + UX safety

🔐 Security — Ed25519 Signature Verification on Contact Requests

  • P2PServer.handleContactRequest() — Now verifies the Ed25519 signature on incoming contact requests. Previously, senderSigningPublicKey was received but never verified — anyone could spoof an identity.
  • Canonical signed datasenderPubKey(UTF-8) || 0x00 || conversationId(UTF-8) || createdAt(big-endian 8 bytes) — domain-separated, deterministic
  • sendContactRequest() — Now signs the payload with FialkaNative.ed25519Sign() and includes requestSignature field
  • Backward compatible — Old clients without requestSignature are still accepted (graceful migration window)

🧪 Unit Tests — Crypto & Ratchet Coverage

  • Robolectric 4.13 added as test dependency
  • CryptoManagerPureTest — 20 tests: deriveConversationId determinism/commutativity/uniqueness, buildSignedData timestamp encoding, hashSenderUid cross-conversation pseudonymity
  • RatchetSimulationTest — 16 tests: bidirectional ratchet, 500-step key uniqueness, SPQR interval=10, pqRatchetStep correctness, initiator/responder symmetry
  • DoubleRatchetTest — 2 JNI-dependent tests marked @Ignore (require libfialka_core.so — must run as instrumented tests)
  • 45 unit tests total, 0 failures

🛡️ UX Safety — Destructive Migration Warning

  • FialkaDatabase.needsDestructiveMigration() — Detects when a Room schema upgrade would trigger fallbackToDestructiveMigration (DROP ALL TABLES)
  • MainActivity — Shows a blocking AlertDialog before any DB access on upgrade: user must explicitly confirm data loss or quit
  • FialkaDatabase.recordCurrentVersion() — Persists schema version in plain SharedPreferences after confirmed open

🛠 Dev Infrastructure

  • version.properties — Single source of truth for VERSION_CODE + VERSION_NAME; build.gradle.kts reads it automatically — only edit version.properties to bump version
  • Version V4.1.0-alphaversionCode 11

Replaced security-crypto with FialkaSecurePrefs (direct Keystore), fixed SQLCipher 4.14.1 crash, fixed DurationSelectorBottomSheet NPE, full transport reliability (5 fixes).

🔐 Security — FialkaSecurePrefs (Direct Android Keystore)

  • security-crypto removedandroidx.security:security-crypto:1.1.0-alpha06 and MasterKey.Builder / EncryptedSharedPreferences fully removed
  • FialkaSecurePrefs — New object implementation using the Android Keystore directly: AES-256-GCM, key alias fialka_ks_{name}, prefs file {name}_v2
  • StrongBox with TEE fallback — Silent attempt on StrongBox, automatic fallback to standard TEE if unavailable
  • 6 files migratedCryptoManager, FialkaDatabase, MailboxDatabase, AppMode, AppLockManager, MailboxClientManager migrated to FialkaSecurePrefs.open()
  • AGP 8.9.1 + compileSdk 36 + Gradle 8.13 — Build toolchain upgrade; zero warnings in release builds

🐛 Fix — SQLCipher crash on startup

  • System.loadLibrary("sqlcipher")sqlcipher-android:4.14.1 removed the static initializer; FialkaApplication.onCreate() now loads the native library first
  • Defensive callsFialkaDatabase.getInstance() and MailboxDatabase.buildDatabase() also call loadLibrary as a defensive guard

🐛 Fix — DurationSelectorBottomSheet NPE

  • context parameter removedDurationSelectorBottomSheet no longer takes an external Context; BottomSheetDialogFragment provides its own context
  • show() simplified — Removed fragmentManager.findFragmentById(R.id.nav_host_fragment)?.requireContext()!! which returned null from childFragmentManager

⚡ Transport Reliability

  • Reduced retry delayRETRY_INTERVAL_MS 60 s → 15 s; MAX_RETRY_DELAY_MS cap 30 min → 3 min (backoff: 15 s / 30 s / 1 min / 2 min / 3 min)
  • DELIVERY_FAILED on exhausted messages — Messages reaching 50 retries are marked DELIVERY_FAILED BEFORE queue deletion (fixes permanent hourglass ⏳)
  • Mailbox fallback in processOutboxForContact() — If P2P deposit fails, automatically deposits via Mailbox and updates to DELIVERY_MAILBOX
  • Mailbox sweep in broadcastPresence() — After the offline-contacts loop, processOutbox() is called to sweep queued messages
  • Adaptive fetch in MailboxClientManager — Base 10 s, 5 s when messages received (+OutboxManager.flushNow()), backoff up to 60 s on error

📦 Updated Dependencies

  • BouncyCastle 1.80 → 1.83 (ML-KEM-1024, Ed25519, ML-DSA-44)
  • SQLCipher 4.5.4 → 4.14.1
  • Room 2.7.1 → 2.8.4
  • Coroutines 1.9.0 → 1.10.2
  • Navigation 2.8.9 → 2.9.7 | Lifecycle 2.8.7 → 2.10.0

🔜 V3.6 — Planned (partially delivered in V4.0)

Advanced camouflage, plausible deniability, E2E voice messages, sealed sender, messaging improvements.

🎭 App Disguise (Icon & Name Camouflage)

  • Icon change — User picks a camouflage icon from presets: Calculator, Notes, News, Weather, Clock, etc.
  • Display name change — App name in launcher changes to match the chosen icon (“Calculator”, “Notes”, “News”, etc.)
  • Icon themes — Each disguise has a matching icon + name (professional style)
  • Activity-alias — Implementation via <activity-alias> in manifest (dynamic enable/disable via PackageManager)
  • Confirmation + restart — Confirmation dialog with preview → “Restart now” → kill + relaunch
  • Functional cover screen — Disguised app opens a real functional fake app (calculator, notes, etc.). The real chat is accessible via a secret gesture (hidden long press or special code)
  • Persistence — Choice saved in SharedPreferences, restored on startup

🔐 Plausible Deniability & Protection

  • Dual PIN — Normal PIN opens chat; duress PIN opens an empty profile or triggers a silent wipe (plausible deniability, journalist/activist level)
  • Panic button — Shake phone → instant deletion of all conversations + keys + sign-out (full wipe)
  • Screenshot protectionFLAG_SECURE on all windows ✔️ Done in V3.4.1 Security Audit
  • Keyboard incognitoflagNoPersonalizedLearning on all input fields — keyboard does not learn or log anything

🔐 Advanced Crypto

  • Sealed sender — Sender identity hidden on Firebase side — recipient deduces sender only after decryption

💬 Advanced Messaging

  • E2E voice messages — Audio recording, AES-256-GCM encryption, sent via ratchet, inline player in chat
  • Reply / Quote — Reply to a specific message with quoted citation (quoted bubble + new message)
  • Groups — 3+ participant conversations (Sender Keys)
  • Delete for everyone — Delete a message on local + Firebase
  • Typing indicators — “Typing...” (E2E encrypted, opt-in)

🛡️ Infrastructure

  • Private relay — Dedicated relay server to reduce Firebase dependency

← Back to README