4NK_env/docs/PROCESS_ENCRYPTION_AND_DECRYPTION.md

6.4 KiB
Raw Permalink Blame History

Chiffrement des données de processus et déchiffrement (4NK)

Ce document décrit comment les données privées dun processus sont chiffrées, stockées et déchiffrées côté client dans lécosystème 4NK, en salignant sur les composants existants (ihm_client, service worker/IndexedDB, relays, wasm sdk_client).

Principes

  • Séparation public/privé: lors de la création/mise à jour dun process, le client sépare explicitement les champs privés des champs publics.
  • Encodage: les objets JSON simples et binaires sont encodés via le wasm (encode_json, encode_binary).
  • Chiffrement & Clés: le wasm chiffre les champs privés et associe des clés par attribut dans state.keys[attribute] pour les membres autorisés (déterminés par roles + règles de validation).
  • Stockage:
    • Les données chiffrées sont référencées par un hash (pcd_commitment[attribute]) et stockées localement en IndexedDB (store data) via handleApiReturn.
    • Les clés partagées (confirmées ou en attente) sont stockées dans shared_secrets / unconfirmed_secrets et injectées dans le wasm via set_shared_secrets.
  • Rôle du relay: les pairs publient/échangent ciphers, diffs, clés via les connections relay. Au moins un « handshake » relay doit avoir eu lieu pour récupérer/échanger les clés.

Séquence — Création dun processus avec données privées

  1. Lapp sépare privateData et publicData.
  2. Encodage des deux jeux de données via wasm.
  3. create_new_process (wasm) produit updated_process avec:
    • current_process.states[*].pcd_commitment[attribute] (hash → blob chiffré)
    • current_process.states[*].keys[attribute] pour les membres autorisés
  4. handleApiReturn:
    • Sauvegarde des blobs dans IndexedDB (data), des diffs, et du process dans processes.
    • Alimente shared_secrets/unconfirmed_secrets et set_shared_secrets → wasm mémorise les secrets.
  5. checkConnections sassure que les pairs nécessaires sont connectés (fonds « faucet » si besoin), puis request_data peut être utilisé pour obtenir des clés/manquants.

Pseudo-code (TypeScript, côté ihm_client)

const { jsonCompatibleData, binaryData } = splitData(privateData);
const encodedPrivate = {
  ...sdk.encode_json(jsonCompatibleData),
  ...sdk.encode_binary(binaryData)
};
const encodedPublic = encode(publicData);

const res = sdk.create_new_process(encodedPrivate, roles, encodedPublic, relayAddress, feeRate, services.getAllMembers());
await services.handleApiReturn(res); // stocke blobs + diffs + process + secrets
await services.checkConnections(res.updated_process.current_process);

Séquence — Récupération et déchiffrement des données privées

Objectif: obtenir les champs déchiffrés dun état particulier.

  1. Préconditions:
    • Appareil pairé (is_paired() et services.isPaired() → true)
    • Au moins un handshake relay reçu (liste des membres non vide)
    • restoreSecretsFromDB() exécuté (injecte les secrets en wasm)
  2. Côté hôte, appeler liframe via RETRIEVE_DATA { processId, stateId, accessToken }.
  3. Routeur ihm_clienthandleDecryptState:
    • Vérifie validateToken(accessToken, origin)
    • Charge le processservices.getProcess(processId)
    • Vérifie/établit les connexions (checkConnections(process, stateId)) pour récupérer clés manquantes
    • Pour chaque attribut privé: decryptAttribute(processId, state, attribute)
  4. decryptAttribute:
    • Si clé absente mais rôle autorisé → requestDataFromPeers(processId, [stateId], [roles]) puis retries
    • Lit le blob chiffré en IndexedDB via pcd_commitment[attribute]
    • Déchiffre avec sdk.decrypt_data(key, cipher) puis sdk.decode_value(clear)
  5. Réponse DATA_RETRIEVED avec les champs déchiffrés.

Pseudo-code déchiffrement (extrait)

async function decryptAttribute(processId: string, state: ProcessState, attribute: string) {
  const hash = state.pcd_commitment[attribute];
  let key = state.keys[attribute];
  if (!key && rolesContainUs(state.roles, getPairingProcessId())) {
    await services.checkConnections(await services.getProcess(processId), state.state_id);
    await services.requestDataFromPeers(processId, [state.state_id], [state.roles]);
    await retryDelay();
    key = state.keys[attribute];
  }
  if (!hash || !key) return null;
  const blob = await services.getBlobFromDb(hash);
  if (!blob) return null;
  const cipher = new Uint8Array(await blob.arrayBuffer());
  const clear = sdk.decrypt_data(hexToU8(key), cipher);
  return sdk.decode_value(clear);
}

Séquence — Mise à jour avec nouveaux champs privés

  1. Lapp calcule privateData/publicData du delta.
  2. update_process (wasm) produit updated_process et, si nécessaire, de nouvelles clés par attribut.
  3. handleApiReturn met à jour blobs/diffs/process/secrets.
  4. Les pairs reçoivent ciphers/keys via relay; request_data sert à combler les manquants.

Bonnes pratiques et diagnostics

  • Toujours valider le token (VALIDATE_TOKEN) avant des opérations sensibles.
  • Attendre un handshake relay au démarrage avant de tenter dobtenir des clés.
  • Vérifier que rolesContainsUs(roles) est vrai pour les attributs visés — sinon pas daccès aux clés.
  • Confirmer quIndexedDB contient:
    • data[hash] (blob chiffré)
    • shared_secrets[...] utiles → restoreSecretsFromDB() doit tourner à linit
  • En cas déchec de déchiffrement:
    • Absence de blob → handleApiReturn na pas été invoqué sur un updated_process contenant encrypted_data
    • Absence de clé → relancer checkConnections + requestDataFromPeers, vérifier la connectivité relay/fonds

Exemple de flux hôte ↔ iframe (postMessage)

// 1) Lhôte liste les processus (publique) puis demande les privés dun état
postMessage({ type: 'GET_PROCESSES', messageId, accessToken });
// ... reçoit PROCESSES_RETRIEVED
postMessage({ type: 'RETRIEVE_DATA', messageId, processId, stateId, accessToken });
// ... reçoit DATA_RETRIEVED { data: { monChampPrive: '...' } }

Résumé

  • Les données privées ne sont jamais renvoyées en clair par GET_PROCESSES.
  • Le déchiffrement seffectue côté client via RETRIEVE_DATA et decryptAttribute, avec clés/ blobs provenant du relay + IndexedDB.
  • La disponibilité des clés dépend des rôles, du pairing, de la connectivité et des secrets chargés.