docs(android): the cache chain is verified on device
Write with no prompt, read under the device credential, cache surviving a cold start with no derivation, and a silent 304. Records the three traps that hid behind it, none of which the compiler could see. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -222,6 +222,47 @@ adb reverse tcp:8080 tcp:80
|
||||
> — `404` signifie que la chaîne est bonne (c'est la réponse voulue sans jeton),
|
||||
> `000` que rien n'écoute.
|
||||
|
||||
## Le cache : écrire sans invite, lire sous authentification
|
||||
|
||||
Validé sur appareil le 2026-08-15, sur un téléphone protégé par un **schéma**
|
||||
et aucune empreinte enrôlée :
|
||||
|
||||
```
|
||||
cache ecrit - protege par biometrie/code (aucune invite à l'écriture)
|
||||
--- redémarrage à froid, saisie du schéma ---
|
||||
4 entrees, 2 en corbeille (pas de ligne « dechiffre en … ms »)
|
||||
HTTP 304 en 136 ms · 304 : inchange, coffre deja ouvert
|
||||
```
|
||||
|
||||
Une clé AES du Keystore ne pouvait pas convenir : `setUserAuthenticationRequired`
|
||||
exige une authentification récente **pour chiffrer autant que pour déchiffrer**,
|
||||
et l'écriture suit une synchronisation silencieuse. Le cache ne s'écrivait donc
|
||||
jamais, sauf dans les secondes suivant un déverrouillage — un test qui passe,
|
||||
puis ne passe plus.
|
||||
|
||||
C'est une **paire RSA** : la partie publique enveloppe une clé AES jetable sans
|
||||
invite, la partie privée — protégée — la déballe. L'authentification n'est
|
||||
exigée qu'à la lecture.
|
||||
|
||||
Trois pièges, aucun visible à la compilation :
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `USE_BIOMETRIC` absente de la liste Delphi | `CanAuthenticate` **lève** au lieu de répondre `False` |
|
||||
| L'invite vit dans `BiometricFragmentActivity` | à déclarer au manifeste, sinon `ActivityNotFoundException` |
|
||||
| `setDigests()` n'autorise que le digest **du message** | celui du MGF1 est distinct, défaut SHA-1 |
|
||||
|
||||
Le troisième est le plus retors : le chiffrement passe, parce que la clé
|
||||
publique reconstruite est servie par le fournisseur logiciel qui accepte
|
||||
n'importe quel MGF1. On produit un chiffré valide que le matériel refuse de
|
||||
lire, et le symptôme n'apparaît qu'au lancement suivant.
|
||||
|
||||
> **Aucune routine de lecture n'efface le cache.** `LoadVault` triait
|
||||
> « clé perdue » contre « pas authentifié » sur le texte de l'exception et
|
||||
> supprimait le fichier quand il penchait pour la première. Un tri erroné
|
||||
> détruisait le cache *en emportant la seule trace de sa cause*. Elle rapporte
|
||||
> désormais via `LastStoreError` ; l'appelant décide.
|
||||
|
||||
## Le piège de la porte sans clé
|
||||
|
||||
`USE_BIOMETRIC` **ne fait pas partie de la liste de permissions par défaut de
|
||||
|
||||
Reference in New Issue
Block a user