Aller au contenu

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...
};

Liens