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
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
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 profil —
removeOldUserByPublicKey()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 —
.readet.writerestreints au niveau$conversationId
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 couleur —
attrs.xmlcomplet : 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-hide —
HideBottomViewOnScrollBehaviormasque le FAB au scroll - Zéro couleur hardcodée — Toutes les couleurs UI →
?attr/(theme-aware)
Durcissement sécuritaire complet : chiffrement renforcé, anti-analyse de trafic, partage de fichiers E2E.
- R8/ProGuard —
isMinifyEnabled=true,isShrinkResources=true, repackaging en release - Log stripping —
Log.d(),Log.v(),Log.i()supprimés par ProGuard (assumenosideeffects)
- 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 HMAC —
senderUid= 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
- 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)
- 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/
- Index Room — Index composites : messages(conversationId, timestamp), messages(expiresAt), conversations(accepted), contacts(publicKey)
- Double-listener guard —
processedFirebaseKeysempêche la désynchronisation ratchet quand 2 listeners traitent le même message
Paramètres repensés Signal/Telegram, PIN 6 chiffres, sous-écran Confidentialité, performance PIN.
- 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
- 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)
Signature par message Ed25519, badge ✅/
⚠️ , durcissement Firebase rules, nettoyage clés de signature.
- Ed25519 (BouncyCastle 1.78.1) — Paire de clés de signature dédiée (séparée de X25519)
- Données signées —
ciphertext_UTF8 || conversationId_UTF8 || createdAt_bigEndian8— anti-falsification + anti-replay - Provider JCA —
Security.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 client —
createdAt=System.currentTimeMillis()(pasServerValue.TIMESTAMP) pour cohérence signature
- Participants scopés —
/conversations/$id/participantslisible uniquement par les membres (plus par tous les authentifiés) - Nettoyage clés de signature —
/signing_keys/{hash}supprimé à la suppression de compte
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.
- Migration M2 → M3 — Tous les 5 thèmes migrés de
Theme.MaterialComponentsversTheme.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
- 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
- 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
- Sign-out Firebase — Suppression de
database.goOnline()aprèsauth.signOut()(corrige l'erreur de permission Firebase) - Firebase locale — Remplacement de
useAppLanguage()parsetLanguageCode(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
- ProGuard complet — Ajout de
Log.w(),Log.e(),Log.wtf()dansassumenosideeffects(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 sensible —
FirebaseRelay.ktetChatRepository.ktn'affichent plus de chemins Firebase ou d'identifiants dans les logs
- 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:9050quand Tor activé - Démarrage conditionnel —
FialkaApplication.onCreate()démarre Tor si activé - TorBootstrapFragment —
startDestinationdu 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
PQXDH hybride (ML-KEM-1024 + X25519), DeviceSecurityManager StrongBox, QR deep link v2, vérification d'empreinte indépendante, corrections de désynchronisation ratchet.
- 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
- 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
- Fix désynchronisation PQXDH —
syncExistingMessages()à 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-listener —
ConcurrentHashMap.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 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)
- Room v16 — Migration v15→v16 : ajout colonne
lastDeliveredAtsur Conversation - Version 3.4.0 —
versionCode 5,versionName "3.4.0"
Photos éphémères one-shot, écran de restauration repensé avec grille BIP-39, vérification d'empreinte par QR code, améliorations UI.
- 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=1immé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
- Grille BIP-39 professionnelle — 24 cellules
AutoCompleteTextViewen 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
- 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
CustomScannerActivityque 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
- 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
- Room v17 — Migration v16→v17 : ajout colonne
oneShotOpenedsur MessageLocal -
flagOneShotOpened()— Nouvelle requête DAO :UPDATE messages SET oneShotOpened = 1 WHERE localId = :messageId - Version 3.4.1 —
versionCode 6,versionName "3.4.1"
- 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 validation —
senderUid.length === 32, ciphertext non-vide + max 65536, iv non-vide + max 100,createdAt <= now + 60000 - Zeroing mémoire HKDF —
hkdfExtractExpand()efface IKM,hkdfExpand()efface PRK + expandInput après usage - Zeroing mémoire Mnemonic —
privateKeyToMnemonic()etmnemonicToPrivateKey()effacent tous les tableaux d'octets intermédiaires et nettoient le StringBuilder - Validation entrée PQXDH —
deriveRootKeyPQXDH()exige les deux entrées de 32 octets exactement - Séparateur ConversationId —
deriveConversationId()utilise"|"pour éviter les collisions de concaténation de clés - FLAG_SECURE — Appliqué sur
MainActivity,LockScreenActivity,RestoreFragmentet 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 viaHandler.postDelayed - SecureFileManager — Nouvel utilitaire : écrasement 2 passes (données aléatoires + zéros,
fd.sync()) avantFile.delete() - Zeroing fileBytes —
saveFileLocally()appellefileBytes.fill(0)après écriture - Suppression sécurisée one-shot — Les fichiers one-shot utilisent
SecureFileManager.secureDelete() - Nettoyage conversations mortes —
deleteStaleConversation()écrase le répertoire de fichiers de la conversation - Nettoyage messages expirés —
deleteExpiredMessages()supprime les fichiers associés en premier - Guards FirebaseRelay —
sendMessage()avecrequire()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érique —
MyFirebaseMessagingServiceaffiche « 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
MainActivityetLockScreenActivity— protection tapjacking - Storage rules suppression par propriétaire —
resource.metadata['uploaderUid'] == request.auth.uidrequis pour supprimer - Metadata upload —
uploadEncryptedFile()attacheuploaderUiddans les StorageMetadata
Triple Ratchet post-quantique (SPQR), chiffrement alternatif ChaCha20-Poly1305, modèle de menace documenté.
- 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é-encapsulation —
PQ_RATCHET_INTERVAL = 10messages : 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 +kemCiphertextattaché au message - Receiver-side — Dans
receiveMessage(), détection dukemCiphertextsur une session déjà PQ-initialisée :mlkemDecaps()→pqRatchetStep()→ rootKey upgradé, compteur réinitialisé - Compteur persistant — Nouveau champ
pqRatchetCounterdansRatchetState(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 parpqxdhInitialized
-
encryptChaCha()/decryptChaCha()— Implémentation complète via BouncyCastleChaCha20Poly1305AEAD (nonce 12 octets, tag 16 octets) - Détection hardware AES —
hasHardwareAes()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 dansFirebaseMessage(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
- 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
- Room v18 — Migration v17→v18 : ajout colonne
pqRatchetCountersur RatchetState - Version 3.5 —
versionCode 7,versionName "3.5"
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
- 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
- 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)
- AccountID —
SHA3-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
- Guardian Project Tor —
libtor.sopour 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 messages —
getPendingMessages()inclut les messages bloqués enSTATUS_SENDING
- Direct P2P — Communication directe, pas de relais
- Personal —
.onionpersonnel 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
mailboxOnion—senderMailboxOnioninclus dans tous les messages ; P2PServer met à jourparticipantMailboxOnionà la réception - Stats cumulatives —
totalDeposited,totalFetched,totalDataProcessedpersistés en SharedPreferences (blobs supprimés après livraison) - Dashboard auto-refresh — Toutes les 30s
-
MessageLocal.deliveryStatus—SENT(0)/MAILBOX(1)/FAILED(2)/PENDING(3) -
OutboxMessage.messageLocalId— Liaison retour versMessageLocalpour mise à jour du statut - Badges de livraison — ✓ Envoyé · 📬 Mailbox · ⏳ En attente · ❌ Échec
- Bouton Renvoyer — Messages
FAILED→OutboxDao.resetRetryForMessage()relance la tentative - Bannière fetch —
fetchBanner+ProgressBardans le chat, input désactivé pendant le fetch Mailbox
- 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,
ConstraintLayout→LinearLayout - Profil — Avatar 108dp, eyebrow « GHOST IDENTITY », caption
Ed25519 · ML-DSA-44 · ML-KEM-1024en monospace - Profil contact — Eyebrow « NODE INFO », badge E2E pill avec fond
bg_key_box
- Fix messages orphelins —
getPendingMessages()inclutSTATUS_SENDINGbloqués (récupération après crash/reboot) - Fix
resolveRecipientEd25519— Fallback surpublicKeysisigningPublicKeyabsent - Fix
sendContactRequest— RetourneBoolean, logs complets - Fix
killOrphanedTor— Lecture du cookie auth AVANT suppression du fichier
- Room v24 —
deliveryStatussurMessageLocal,messageLocalId+fallbackOnionsurOutboxMessage, migrations v18→v24 - MailboxDatabase v1 — Entités
MailboxBlob,MailboxMember,MailboxInvite(mode MAILBOX uniquement) - Version 4.0 —
versionCode 8,versionName "4.0"
Remplacement de
security-cryptoparFialkaSecurePrefs(Keystore direct), correction crash SQLCipher 4.14.1, correction NPEDurationSelectorBottomSheet, fiabilité complète du transport (5 corrections).
- Suppression de
security-crypto—androidx.security:security-crypto:1.1.0-alpha06etMasterKey.Builder/EncryptedSharedPreferencesentièrement retirés -
FialkaSecurePrefs— Nouvelle implémentationobjectutilisant 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 fichiers —
CryptoManager,FialkaDatabase,MailboxDatabase,AppMode,AppLockManager,MailboxClientManagermigrés versFialkaSecurePrefs.open() - AGP 8.9.1 + compileSdk 36 + Gradle 8.13 — Mise à niveau de la chaîne de build ; zéro avertissement en release
-
System.loadLibrary("sqlcipher")—sqlcipher-android:4.14.1supprime l’initialiseur statique ;FialkaApplication.onCreate()charge la bibliothèque native en premier - Appels défensifs —
FialkaDatabase.getInstance()etMailboxDatabase.buildDatabase()appellent égalementloadLibraryen garde défensive
- Paramètre
contextsupprimé —DurationSelectorBottomSheetn’accepte plus deContextexterne ;BottomSheetDialogFragmentdispose de son propre contexte -
show()simplifié — Suppression defragmentManager.findFragmentById(R.id.nav_host_fragment)?.requireContext()!!qui retournaitnulldepuischildFragmentManager
- Réduction du délai de retry —
RETRY_INTERVAL_MS60 s → 15 s ; plafondMAX_RETRY_DELAY_MS30 min → 3 min (backoff : 15 s / 30 s / 1 min / 2 min / 3 min) - Statut
DELIVERY_FAILEDsur messages épuisés — Les messages atteignant 50 tentatives reçoivent le statutDELIVERY_FAILEDAVANT 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 versDELIVERY_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
- 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
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.
- 30 fonctions JNI implémentées dans
Fialka-Core/src/ffi/mod.rsvia thejni = 0.21crate -
FialkaNative.kt— Kotlin bridge object,System.loadLibrary("fialka_core"), 30external fun -
libfialka_core.so— compilée aveccargo-ndkforarm64-v8a(906 KB) andx86_64(984 KB) - git submodule —
Fialka-Core/intégré comme submodule dans Fialka-Android
-
CryptoManager.kt— 100% migré : tous les appels BouncyCastle remplacés parFialkaNativeidentityDerive→ 8704-octets bundle (Ed25519, X25519, ML-KEM-1024, ML-DSA-44)encryptAes/decryptAes→ FialkaNative.encryptAes / decryptAesencryptChaCha/decryptChaCha→ FialkaNative (nonce 12 octets, tag 16 octets)encryptFile/decryptFile→ FialkaNative (format : key[32] || iv[12] || CT)hmacSha256→ FialkaNative.hmacSha256hkdfZeroSalt/ dérivation de clés → FialkaNative.hkdfZeroSalted25519Sign/ed25519Verify→ FialkaNativex25519Dh→ FialkaNative (suppression préfixes ASN.1 JCA : X509 12 octets, PKCS8 16 octets)mlkemEncaps/mlkemDecaps→ FialkaNativemldsaSign/mldsaVerify→ FialkaNativederiveRootKeyPqxdh→ FialkaNativecomputeOnion/ed25519ToX25519Raw→ FialkaNative
-
TorTransport.kt—signEd25519/verifyEd25519migrés vers FialkaNative -
build.gradle.kts—org.bouncycastle:bcprov-jdk18on:1.83dépendance supprimée - Tests Robolectric + JVM supprimés (incompatibles avec JNI) ; tests migrés vers
androidTest
- Même bibliothèque Rust utilisée sur Android (JNI) et toute autre cible (Windows/Linux/iOS via FFI)
- Version V4.0.2 —
versionCode 10
versionCode 11·versionName "4.1.0-alpha"· Correction sécurité + couverture tests + protection UX
-
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 canoniques —
senderPubKey(UTF-8) || 0x00 || conversationId(UTF-8) || createdAt(big-endian 8 octets)— séparé par domaine, déterministe -
sendContactRequest()— Signe maintenant le payload avecFialkaNative.ed25519Sign()et inclut le champrequestSignature - Rétrocompatible — Les anciens clients sans
requestSignaturesont encore acceptés (fenêtre de migration progressive)
- Robolectric 4.13 ajouté comme dépendance de test
-
CryptoManagerPureTest— 20 tests : déterminisme/commutativité/unicité dederiveConversationId, encodage timestampbuildSignedData, pseudonymat cross-conversationhashSenderUid -
RatchetSimulationTest— 16 tests : ratchet bidirectionnel, unicité 500 clés, intervalle SPQR=10, correctionpqRatchetStep, symétrie initiator/responder -
DoubleRatchetTest— 2 tests JNI marqués@Ignore(nécessitentlibfialka_core.so— à migrer en tests instrumentés) - 45 tests unitaires au total, 0 échec
-
FialkaDatabase.needsDestructiveMigration()— Détecte quand une mise à jour de schéma Room déclencheraitfallbackToDestructiveMigration(DROP ALL TABLES) -
MainActivity— Affiche unAlertDialogbloquant 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 desSharedPreferencessimples après ouverture confirmée
-
version.properties— Source unique de vérité pourVERSION_CODE+VERSION_NAME;build.gradle.ktsle lit automatiquement — modifier uniquementversion.propertiespour bumper la version - Version V4.1.0-alpha —
versionCode 11
versionCode 12·versionName "4.2.0-alpha"· Wallet Monero non-custodial local, paiements XMR in-chat, améliorations Tor
- 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)
- 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-alpha —
versionCode 12
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
-
WalletPreferences— constantesMAINNET = 0/STAGENET = 2,getNetworkType(),setNetworkType(),getNetworkLabel(),isStagenet() - Defaults intelligents par réseau — node
127.0.0.1:38081(stagenet) vs127.0.0.1:18081(mainnet), restore height adaptée -
WalletRepository— suppression duNETWORK_TYPE = 2codé en dur, tout passe parWalletPreferences.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
- Fix label "Données" dans les Paramètres —
SettingsAdapter.getCategoryTitle()manquait le caseCATEGORY_DATA, affichait la clé brute"data"au lieu de"💾 Données" - Fix
validateAddress(context, address)— signature mise à jour dansChatViewModelaprès refactoringWalletRepository
- Format
.fialka— Magic bytes0xF1A15A5E+ 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
-
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 DAO —
getTotalMessageCount,getFileMessageCount,deleteFileMessages,deleteAllMessages,getTotalConversationCount,deleteAllConversations
- Nouvelle catégorie "Données" (
chipData) dans les Paramètres — regroupe stockage, export backup, import backup - Stockage migré de type
ACTION→NAVIGATEversstorageFragment - Navigation —
action_settings_to_storage+ nodestorageFragmentdansnav_graph.xml
-
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.xml —
terms_section_wallet_title/body,terms_section_backup_title/bodyajoutés - Version V4.3.0-alpha —
versionCode 13
-
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 viaPackageManager -
CoverCalculatorActivity.kt— Fausse calculatrice fonctionnelle (couverture réaliste) -
CoverSecretSetupBottomSheet.kt— Configuration du code secret d'accès au vrai chat - Icônes de déguisement —
ic_disguise_calculator,ic_disguise_clock,ic_disguise_notes,ic_disguise_weather
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.
-
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
- 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:contentDescriptionhardcodé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 i18n —
menu_*,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
- KSP 2.3.6 → 2.3.7
- swiperefreshlayout 1.1.0 → 1.2.0
- actions/upload-artifact v4 → v7 (CI GitHub Actions)