Transparence E2EE — leggit

Comment leggit protège vos données dans les coffres post-mortem.

Le modèle simple

Quand vous écrivez un mot de passe ou ajoutez un fichier dans un coffre personnel, leggit applique le pattern envelope encryption : le contenu lui-même n'est chiffré qu'une seule fois, avec une clé éphémère ; cette petite clé est ensuite "emballée" (wrappée) pour chaque destinataire séparément.

  1. Écriture (E2EE) : votre navigateur génère une DEK (Data Encryption Key) aléatoire de 32 octets, puis chiffre le contenu une fois avec cette DEK (XChaCha20-Poly1305 ; secretstream pour les fichiers chunkés). Tout cela s'exécute dans un Web Worker isolé.
  2. Wraps multi-destinataires : pour chaque destinataire, c'est la DEK (32 octets), pas le contenu, qui est chiffrée avec leur clé publique X25519 via crypto_box_seal. On obtient donc un seul cipher de contenu + N petits "wraps" de la DEK (~80 octets chacun). Pour vous-même, votre DEK est aussi wrappée avec votre KEK (clé maître dérivée de votre mot de passe).
  3. Envoi : le serveur leggit reçoit uniquement le cipher opaque du contenu et la liste des wraps de DEK. Il ne voit jamais le clair ni la DEK elle-même.
  4. Lecture (E2EE aussi) : quand vous re-consultez un item, le serveur vous renvoie le cipher du contenu et votre wrap personnel (celui chiffré pour vous). Votre navigateur déballe la DEK avec votre KEK, puis déchiffre le contenu. Un destinataire procédera pareil avec sa clé privée X25519. Un badge E2EE dans la liste et la modale confirme le mode.

Pourquoi cette dichotomie ? Le chiffrement symétrique (DEK + cipher) est rapide même pour des fichiers de 100 Mo, mais une clé symétrique ne peut pas être partagée telle quelle. Le chiffrement asymétrique (X25519) sait partager une clé entre interlocuteurs sans secret commun préalable, mais il serait trop lent pour chiffrer des Mo de données. On combine donc les deux : symétrique pour le contenu, asymétrique pour la DEK.

Garantie technique : sous réserve d'intégrité du code JavaScript servi (vérifiable via les hashes SRI ci-dessous), nos administrateurs ne peuvent pas accéder à vos données tant qu'ils ne se substituent pas au navigateur.

Périmètre actuel

FonctionnalitéModeCommentaire
Coffres personnels — items texte E2EE actif Chiffrement + déchiffrement dans le navigateur (Phase 2)
Coffres personnels — fichiers chunked E2EE actif Upload chunké 1 MiB chiffré navigateur, download chunké déchiffré navigateur (Phase 3)
Ajout destinataire (E2EE) avec rewrap E2EE actif Modale re-auth + rewrap immédiat browser-side pour chaque item du coffre (Phase 4)
Migration auto items legacy → E2EE E2EE actif Migration progressive en arrière-plan au login, transactions atomiques (Phase 5)
Audit logs sensibles (titres, previews) E2EE actif Détails sensibles chiffrés par votre KEK — seul vous pouvez les lire (Phase 6)
Export RGPD self-service E2EE manifest Manifest fourni au navigateur, déchiffrement local pour le ZIP (Phase 6)
Coffres familiaux — items texte E2EE actif Phase 9 livrée : les items texte des coffres familiaux sont chiffrés dans le navigateur du proprio avec une clé éphémère ; chaque membre accepté reçoit une copie de cette clé scellée via X25519 box_seal. Le serveur ne voit qu'un cipher opaque + N wraps.
Coffres familiaux — fichiers chunked E2EE actif Phase 10 livrée : les fichiers familiaux jusqu'à 100 Mo sont chiffrés par chunks (1 MiB, secretstream_xchacha20poly1305) dans le navigateur, uploadés vers /api?action=fam_upload_chunk_e2ee, et déchiffrés navigateur-side au download via Blob URL. Chaque membre accepté reçoit son wrap personnel box_seal.
Coffres familiaux — rewrap automatique au login E2EE actif Phase 10 livrée : quand un membre invité accepte tardivement (proprio déconnecté), au prochain login du proprio le handler coffre-familial-rewrap-handler.js détecte les wraps manquants, les produit via le Worker (box_seal pour chaque cible), et les POST au serveur. Transparent pour l'utilisateur.
Coffres familiaux — migration items legacy E2EE actif Phase 10 livrée : les items texte créés avant Phase 9 (en server-v1) sont migrés en E2EE au prochain login du proprio. Pattern identique à Phase 5 pour les coffres personnels, adapté pour les wraps multi-membres famille_member.
Crypto-wallets (seed BIP-39 + image table substitution) E2EE actif Phase 8 livrée : la seed (24 mots) et l'image de table de substitution sont chiffrées dans le navigateur via le Web Worker (XChaCha20-Poly1305 pour le texte, secretstream chunked pour l'image). Le serveur ne voit que des cipher blobs opaques. Pour les wallets PARANOIA, la seed était déjà E2EE par design (Shamir M-of-N + box_seal X25519 vers dépositaires) — libsodium est maintenant servi en local au lieu du CDN pour cohérence anti-supply-chain.
Messages programmés post-mortem Serveur (par design) Le serveur DOIT déchiffrer pour envoyer l'email le jour J — pas possible en pur E2EE.
Héritage (post-mortem release) Serveur (par design) Combinaison Shamir + déchiffrement session-side après quorum. Items E2EE encore lisibles via wraps recipient.

Pile cryptographique

Hashes SRI des scripts critiques

Chaque script JS de la chaîne crypto est servi avec un hash SRI (Subresource Integrity). Le navigateur refuse d'exécuter le script si le hash diffère. Vous pouvez recalculer ces hashes localement et les comparer :

openssl dgst -sha384 -binary fichier.js | openssl base64 -A
# ou
shasum -a 384 fichier.js | xxd -r -p | base64
FichierDescriptionSHA-384 (base64)Taille
assets/js/coffre-crypto-bootstrap.js Bootstrap E2EE (détection + chargement) sha384-AfW/aEqir+7svE+/indeiv3ht5Twt9E2qkz0xZ+KvS4r3zdveUTVzZ8KUtnG8JbR 8671 o
assets/js/coffre-crypto.js Interface main thread (postMessage Worker) sha384-yFsAX7p5vk7VogkqrOITcUTOSA+Q+pbDjGNauDxZgoEPDB8y4GDtYBzj9I7nnTbL 23925 o
assets/js/coffre-crypto-worker.js Worker Web — détient les clés en RAM isolée sha384-GFinkrLu5sRiQBeA5RAHub6fvnDfHMBxlL9/Nx+IlrPew9YP2W3r0TQP+NMurmIZ 43785 o
assets/js/coffre-form-handler.js Handler form add_text (Phase 2) sha384-DV4FbZoHzzGn1wmcQfvMd11mmu4DiiUuKx2ncPZdbDP4F7EatWfBWq3qNdLVPVVF 10055 o
assets/js/coffre-file-handler.js Handler upload chunked (Phase 3) sha384-sfPTr6byk+xZoh2kfH2MB8LMFwnhr+XclVNSptceVhiXYX27hRwSVasV5gcUG/p1 24569 o
assets/js/coffre-reauth-handler.js Handler reauth + rewrap (Phase 4) sha384-uZ8kxrxbTrZe3TXrkW7WbaKeAUTr2dS83dypHI0xOu9Tss7TZ2LY8XZxopv8lsCJ 18673 o
assets/js/coffre-migration-handler.js Handler migration lazy (Phase 5) sha384-W9vNv5FKMOjdUx9Dn9xF53bvKCU/pfpW7H/1ziueazEncufJA8XeXaEqod6msx/e 9654 o

Modèle de menace — ce que l'E2EE protège

Modèle de menace — ce que l'E2EE NE PROTÈGE PAS

Vos données — comment les exercer (RGPD)

En mode E2EE, leggit ne peut techniquement pas répondre à un droit d'accès classique : nous n'avons pas accès à vos données.

Le droit d'accès s'exerce via un export self-service depuis votre compte : votre navigateur récupère tous vos coffres + items + fichiers, déchiffre via le Worker, et produit un fichier ZIP local que vous téléchargez. Le serveur ne voit que des blobs chiffrés transiter.

Accéder à mon compte / export RGPD →

Engagements long terme

Manifest généré le 2026-06-01 00:12:36 — version applicative 0.1.0