Data Flows Application Mobile¶
Ce document décrit les flux de données spécifiques à l'application mobile. Voir les flux globaux pour la vue d'ensemble.
Flux d'authentification¶
┌─────────────────────────────────────────────────────────────┐
│ LOGIN FLOW │
└─────────────────────────────────────────────────────────────┘
1. User entre password
│
▼
2. SRP-6a avec backend
│
▼
3. Récupérer JWT + Master Envelope
│
▼
4. Dériver K_encryption = Argon2id(password, salt)
│
▼
5. Déchiffrer Master Envelope → K_master_user
│
▼
6. Stocker K_master_user en mémoire (session)
│
▼
7. Navigation vers VaultScreen
// authStore.ts
const login = async (email: string, password: string) => {
// 1. SRP-6a
const { jwt, envelope } = await srpLogin(email, password);
// 2. Stocker JWT
await SecureStore.setItemAsync('jwt', jwt);
// 3. Dériver K_encryption
const salt = base64ToBytes(envelope.kdf.salt);
const kEncryption = await deriveEncryptionKey(password, salt);
// 4. Déchiffrer K_master
const kMaster = await decryptMasterEnvelope(envelope, kEncryption);
// 5. Stocker en mémoire (pas en storage!)
set({ isAuthenticated: true, kMaster });
// 6. Effacer K_encryption
zeroize(kEncryption);
};
Flux de chiffrement document¶
┌─────────────────────────────────────────────────────────────┐
│ ENCRYPT FLOW │
└─────────────────────────────────────────────────────────────┘
1. User sélectionne fichier
│
▼
2. Lire fichier en mémoire
│
▼
3. Calculer hash = SHA3-256(fichier)
│
▼
4. Générer doc_id (UUID)
│
▼
5. Dériver K_doc = HKDF(K_master, doc_id)
│
▼
6. Chiffrer document = AES-GCM(fichier, K_doc)
│
▼
7. Upload vers backend (doc chiffré + hash + metadata)
│
▼
8. Effacer K_doc et fichier clair de la mémoire
// vaultService.ts
const uploadDocument = async (file: FileInfo) => {
// 1. Lire fichier
const fileData = await readFile(file.uri);
// 2. Hash
const hash = sha3_256(fileData);
// 3. Générer doc_id
const docId = uuid();
// 4. Dériver K_doc
const kDoc = await deriveDocumentKey(kMaster, docId);
// 5. Chiffrer
const { ciphertext, iv, tag } = await encryptGCM(fileData, kDoc);
// 6. Upload
const response = await api.post('/documents', {
id: docId,
hashDoc: hash,
encryptedData: base64(ciphertext),
iv: base64(iv),
tag: base64(tag),
metadata: encryptMetadata(file.name, kDoc),
});
// 7. Cleanup
zeroize(kDoc);
zeroize(fileData);
return response.data;
};
Flux de déchiffrement document¶
┌─────────────────────────────────────────────────────────────┐
│ DECRYPT FLOW │
└─────────────────────────────────────────────────────────────┘
1. User demande document
│
▼
2. Télécharger document chiffré
│
▼
3. Dériver K_doc = HKDF(K_master, doc_id)
│
▼
4. Déchiffrer document = AES-GCM-decrypt(ciphertext, K_doc)
│
▼
5. Vérifier hash = SHA3-256(plaintext) == stored_hash
│
▼
6. Afficher document
│
▼
7. Effacer plaintext et K_doc à la fermeture
Flux de synchronisation¶
┌─────────────────────────────────────────────────────────────┐
│ SYNC FLOW │
└─────────────────────────────────────────────────────────────┘
┌─────────┐ ┌─────────┐
│ Local │ │ Backend │
└────┬────┘ └────┬────┘
│ │
│ 1. Get local changes │
│─────────────────────────────>│
│ │
│ 2. Get remote changes │
│<─────────────────────────────│
│ │
│ 3. Merge (local wins) │
│ │
│ 4. Push merged changes │
│─────────────────────────────>│
│ │
│ 5. Update local state │
│ │
Gestion de la mémoire¶
Lifecycle des clés¶
// K_master_user : durée de session
const kMaster = useRef<Uint8Array | null>(null);
// K_doc : durée d'opération
const decryptDocument = async (docId: string) => {
const kDoc = await deriveDocumentKey(kMaster.current!, docId);
try {
return await decrypt(ciphertext, kDoc);
} finally {
zeroize(kDoc); // Effacé immédiatement
}
};
// Logout : tout effacer
const logout = () => {
if (kMaster.current) {
zeroize(kMaster.current);
kMaster.current = null;
}
// Clear stores, navigation reset...
};