Skip to content

Latest commit

 

History

History
696 lines (536 loc) · 48.8 KB

File metadata and controls

696 lines (536 loc) · 48.8 KB
🇫🇷 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.0.2 — Pont JNI Rust Fialka-Core

Migration de la cryptographie native vers Rust — toute la crypto est désormais exécutée dans la bibliothèque Rust fialka-core, exposée via un pont JNI. Suppression complète de BouncyCastle.

🦀 Pont JNI Rust (Fialka-Core)

  • 30 fonctions JNI implémentées dans 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 — compilée avec cargo-ndk for arm64-v8a (906 KB) and x86_64 (984 KB)
  • git submoduleFialka-Core/ intégré comme submodule dans Fialka-Android

🔐 Migration cryptographique

  • CryptoManager.kt — 100% migré : tous les appels BouncyCastle remplacés par FialkaNative
    • identityDerive → 8704-octets bundle (Ed25519, X25519, ML-KEM-1024, ML-DSA-44)
    • encryptAes / decryptAes → FialkaNative.encryptAes / decryptAes
    • encryptChaCha / decryptChaCha → FialkaNative (nonce 12 octets, tag 16 octets)
    • encryptFile / decryptFile → FialkaNative (format : key[32] || iv[12] || CT)
    • hmacSha256 → FialkaNative.hmacSha256
    • hkdfZeroSalt / dérivation de clés → FialkaNative.hkdfZeroSalt
    • ed25519Sign / ed25519Verify → FialkaNative
    • x25519Dh → FialkaNative (suppression préfixes ASN.1 JCA : X509 12 octets, PKCS8 16 octets)
    • mlkemEncaps / mlkemDecaps → FialkaNative
    • mldsaSign / mldsaVerify → FialkaNative
    • deriveRootKeyPqxdh → FialkaNative
    • computeOnion / ed25519ToX25519Raw → FialkaNative
  • TorTransport.ktsignEd25519 / verifyEd25519 migrés vers FialkaNative
  • build.gradle.ktsorg.bouncycastle:bcprov-jdk18on:1.83 dépendance supprimée
  • Tests Robolectric + JVM supprimés (incompatibles avec JNI) ; tests migrés vers androidTest

🧩 Cross-platform

  • Même bibliothèque Rust utilisée sur Android (JNI) et toute autre cible (Windows/Linux/iOS via FFI)
  • Version V4.0.2versionCode 10

✅ 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

✅ V4.2.0-alpha — Wallet Monero XMR, Paramètres Tor & Seed Backup

versionCode 12 · versionName "4.2.0-alpha" · Wallet Monero non-custodial local, paiements XMR in-chat, améliorations Tor

💰 Wallet Monero (XMR) — Non-custodial

  • Wallet XMR local — clés privées générées et stockées exclusivement sur l'appareil (SQLCipher)
  • Dérivé depuis le seed — 1 seed Ed25519 → wallet XMR (déterministe)
  • Paiements XMR in-chat — envoi de montants XMR directement depuis une conversation
  • Adresse de donation — sous-adresse XMR pour soutenir le développement
  • Zéro custody — les développeurs n'ont aucune visibilité sur les fonds
  • Conformité légale — wallet non-custodial hors champ PSAN (AMF) et MiCA (Art. 2, 2023/1114)

🧅 Améliorations Tor & Réseau

  • Paramètres Tor avancés — bridges, pays exclus, timeouts configurables
  • Indicateur de bande passante Tor — affichage du débit en temps réel
  • Version V4.2.0-alphaversionCode 12

✅ V4.3.0-alpha — Backup .fialka E2E, Réseau Monero Stagenet/Mainnet, Gestion du stockage & Mise à jour légale

versionCode 13 · versionName "4.3.0-alpha" · Backup chiffré complet, sélection réseau Monero (Stagenet/Mainnet), écran de gestion du stockage, CATEGORY_DATA dans les paramètres, mise à jour légale V5

🌐 Réseau Monero — Sélection Stagenet/Mainnet

  • WalletPreferences — constantes MAINNET = 0 / STAGENET = 2, getNetworkType(), setNetworkType(), getNetworkLabel(), isStagenet()
  • Defaults intelligents par réseau — node 127.0.0.1:38081 (stagenet) vs 127.0.0.1:18081 (mainnet), restore height adaptée
  • WalletRepository — suppression du NETWORK_TYPE = 2 codé en dur, tout passe par WalletPreferences.getNetworkType(context) (4 usages)
  • Dialog "Supprimer pour changer" — si un wallet existe, changer de réseau déclenche une confirmation avec suppression du wallet existant (pas de griser les boutons)
  • Badges réseau — badge rouge STAGENET / vert MAINNET dans WalletHomeFragment, WalletSettingsFragment, WalletSeedBackupFragment
  • Banner STAGENET — bannière pleine largeur dans les paramètres wallet pour avertir des fonds fictifs
  • Fix critique : setWalletCreated(true) — maintenant appelé après création (seed backup) ET restauration (import seed), lock déclenchable correctement

🐛 Corrections

  • Fix label "Données" dans les ParamètresSettingsAdapter.getCategoryTitle() manquait le case CATEGORY_DATA, affichait la clé brute "data" au lieu de "💾 Données"
  • Fix validateAddress(context, address) — signature mise à jour dans ChatViewModel après refactoring WalletRepository

💾 Backup & Restauration — Format .fialka

  • Format .fialka — Magic bytes 0xF1A15A5E + PBKDF2-HMAC-SHA256 (600K itérations + salt 16 bytes) + AES-256-GCM (nonce 12 bytes + tag 16 bytes)
  • Contenu du backup — identité (clés Ed25519), contacts, wallet XMR (optionnel) — PAS les messages (confidentialité par conception)
  • Export chiffré — phrase de passe connue de l'utilisateur uniquement, les développeurs n'ont aucun accès
  • Import avec validation — vérification magic bytes + déchiffrement + restauration complète de l'identité
  • Accès via Paramètres → Données — export et import accessibles depuis la nouvelle catégorie CATEGORY_DATA

🗄️ Gestion du stockage — StorageFragment

  • StorageFragment.kt — écran de gestion du stockage en temps réel
  • Stats en temps réel — nombre de messages, nombre de fichiers, taille DB (SQLCipher WAL+SHM), taille cache
  • Actions de nettoyage — vider le cache, supprimer les messages fichiers (avec confirmation count), purger les messages expirés
  • Zone sensible — supprimer tous les messages (avec double confirmation)
  • refreshStats() appelé après chaque action
  • Nouvelles requêtes DAOgetTotalMessageCount, getFileMessageCount, deleteFileMessages, deleteAllMessages, getTotalConversationCount, deleteAllConversations

⚙️ Paramètres — CATEGORY_DATA

  • Nouvelle catégorie "Données" (chipData) dans les Paramètres — regroupe stockage, export backup, import backup
  • Stockage migré de type ACTIONNAVIGATE vers storageFragment
  • Navigationaction_settings_to_storage + node storageFragment dans nav_graph.xml

📚 Mise à jour légale — TermsManager V5

  • CURRENT_TERMS_VERSION = 5 — force le re-consentement pour tous les utilisateurs existants
  • TERMS.md V5 — Section 6 complète : légalité wallet XMR (France/AMF/PSAN, UE/MiCA 2023/1114, US/FinCEN/OFAC/IRS, autres juri)
  • Section 13 — notice légale backup .fialka
  • PRIVACY.md — Section 4.1 wallet XMR (données locales uniquement), Section 5.1 backup
  • strings.xmlterms_section_wallet_title/body, terms_section_backup_title/body ajoutés
  • Version V4.3.0-alphaversionCode 13

🎭 App Disguise — Écran de couverture calculatrice

  • AppDisguiseFragment.kt — Paramètre de sélection du déguisement (Calculatrice, Notes, Météo, Horloge)
  • AppDisguiseManager.kt — Gestion des activity-alias, enable/disable dynamique via PackageManager
  • CoverCalculatorActivity.kt — Fausse calculatrice fonctionnelle (couverture réaliste)
  • CoverSecretSetupBottomSheet.kt — Configuration du code secret d'accès au vrai chat
  • Icônes de déguisementic_disguise_calculator, ic_disguise_clock, ic_disguise_notes, ic_disguise_weather

✅ V4.3.5-alpha — Internationalisation complète (i18n)

versionCode 14 · versionName "4.3.5-alpha" · Externalisation complète de toutes les chaînes codées en dur, traduction anglaise intégrale (~1300+ strings), sélecteur de langue in-app, audit XML exhaustif, dépendances bumped.

🌍 Internationalisation (i18n)

  • values-en/strings.xml — ~1300+ traductions anglaises, parité complète avec le FR (locale par défaut)
  • LocaleHelper.kt — Utilitaire de changement de locale au runtime, persistance dans SharedPreferences
  • LanguageSelectionFragment.kt — Sélecteur de langue in-app (FR / EN) avec redémarrage de l'Activity
  • locale_config.xml — Déclaration des locales supportées dans AndroidManifest (fr, en)
  • ic_language.xml — Nouvelle icône vectorielle langue dans le menu des paramètres

🔧 Externalisation des chaînes hardcodées

  • 50+ fichiers Kotlin — Audit complet : toutes les chaînes hardcodées remplacées par getString(R.string.*)
  • 30+ layouts XML — Tous les android:text, android:hint, android:contentDescription hardcodés remplacés par @string/*
  • 4 menus XML — Titres de menus (menu_search, menu_my_profile, menu_settings, menu_reply, menu_wallet_seed_action, menu_wallet_settings_action) externalisés
  • ConversationsFragment.kt — Menu FAB ("💬 Nouvelle conversation", "👥 Nouveau groupe") → getString(R.string.fab_new_conversation) / getString(R.string.fab_new_group)
  • ConversationsAdapter.kt — Statut "En attente d'acceptation" et placeholder → getString(R.string.pending_acceptance_short) / getString(R.string.conversation_new_placeholder)
  • fragment_create_group.xml + nav_graph.xml — Label "Nouveau groupe" → @string/create_group_title
  • 35 nouvelles clés i18nmenu_*, cd_* (content descriptions), hint_*, fab_* (fab_new_conversation, fab_new_group), pending_acceptance_short, conversation_new_placeholder, create_group_title, xmr_pay_btn, settings_autolock_after_3s

📦 Dépendances

  • KSP 2.3.6 → 2.3.7
  • swiperefreshlayout 1.1.0 → 1.2.0
  • actions/upload-artifact v4 → v7 (CI GitHub Actions)