Le protocole du relais

Tout ce qu'un relais Zolde reçoit et doit faire, en entier. De quoi vérifier qu'il ne voit rien de vos données, et de quoi écrire le vôtre.

Le relais est une boîte aux lettres. Vos appareils y déposent des lots scellés et viennent y chercher ceux des autres ; il ne les ouvre jamais, et il n'a aucune clé pour le faire. Le protocole tient en quatre routes HTTP. Version décrite : v1, celle de Zolde 0.1.

1. Ce qu'un relais doit faire

Toutes les routes sont sous /v1, en HTTPS. Le corps des lots est opaque pour le relais : il le garde et le rend tel quel.

Déposer un lot

POST/v1/mailboxes/{boîte}/batches

En-têteContenu
AuthorizationBearer {jeton} : le jeton de la boîte.
X-Zolde-DeviceIdentifiant de l'appareil qui dépose (un UUID tiré au hasard).

Le corps est le lot, en octets (de l'ordre de quelques kilo-octets ; prévoir au moins 10 Mo pour le premier lot d'un appareil). Réponses :

Une boîte n'existe pas avant son premier dépôt. Le premier jeton présenté pour une boîte inconnue devient le sien ; ensuite, seul ce jeton y donne accès. L'identifiant de boîte (18 octets) et le jeton (32 octets) sont tirés au hasard par le premier appareil : ils ne désignent personne.

Relever les lots

GET/v1/mailboxes/{boîte}/batches?after={curseur}

Même en-tête Authorization. Réponse 200 : les lots dont le curseur est strictement supérieur à after, dans l'ordre croissant, le corps encodé en base64 (standard, avec remplissage).

{
  "batches": [
    {"cursor": 43, "device_id": "3f9c…", "body": "eyJ2IjoxLCJlcG9jaCI6M…"}
  ],
  "more": false
}

more vaut true si le relais a coupé la liste : l'appareil redemande alors à partir du dernier curseur reçu. Une boîte inconnue répond une liste vide. Un mauvais jeton : 401.

Un nouvel appareil relit la boîte depuis after=0 : le relais garde donc les lots aussi longtemps que la boîte sert. Quand vous retirez un appareil, vos appareils passent à une nouvelle boîte. Gardez l'ancienne quelques mois : un appareil resté éteint y trouvera le message qui lui donne la nouvelle clé.

Appairage : écrire et lire une case

PUT/v1/pairings/{appairage}/{case}

GET/v1/pairings/{appairage}/{case}

Pour relier un appareil, les deux appareils s'échangent deux messages scellés par des cases à usage unique : offer (le nouvel appareil) et answer (l'appareil déjà relié). Pas d'authentification : l'identifiant d'appairage (16 octets aléatoires) n'est connu que des deux appareils.

Une case peut être effacée au bout d'une heure : une invitation ne vaut que dix minutes.

2. Ce que le relais voit

Un lot déposé est un petit document JSON. Ses champs en clair servent aux appareils à le ranger ; tout le reste est dans sealed.

{
  "v": 1,
  "epoch": 1,
  "device_id": "3f9c…",
  "from": 41,
  "to": 57,
  "sealed": "IdEn6XvDkUNFmTJ5blhmf5wY…"
}
Le relais voitLe relais ne voit pas
  • L'identifiant de la boîte et son jeton
  • L'identifiant aléatoire de chaque appareil
  • Combien de changements contient un lot (from, to), sa taille, l'heure du dépôt
  • L'adresse réseau des appareils qui se connectent
  • Montants, libellés, catégories, comptes, banques
  • Les noms des appareils
  • Les identifiants bancaires
  • La moindre clé

Quand un appareil est retiré, la boîte reçoit aussi des messages de nouvelle clé, un par appareil restant : {"v":1, "type":"rekey", "for": appareil, "ephemeral": …, "sealed": …}. Le relais les garde comme des lots ordinaires.

3. Ce qu'il y a dans l'enveloppe

Cette partie ne concerne pas le relais : elle sert à vérifier pourquoi il ne peut rien lire ni falsifier. Toute la cryptographie est celle d'OTP (:crypto) ; les champs binaires sont en base64 « URL » sans remplissage.

Un lot

  1. Les changements, en JSON : {"device_id", "from", "to", "ops"}, puis compressés (zlib).
  2. Scellés avec la clé du foyer (32 octets) par ChaCha20-Poly1305. sealed = nonce (12 octets) ‖ chiffré ‖ étiquette (16 octets).
  3. Les données authentifiées lient le lot à sa boîte, à son appareil, à ses numéros et à l'époque de la clé :
    zolde/1|{boîte}|{appareil}|{from}|{to}|{époque}. Un lot recopié dans une autre boîte, attribué à un autre appareil ou modifié ne s'ouvre plus.
  4. Chaque changement est en plus signé par l'appareil qui l'a fait (Ed25519), sur une forme canonique : ["zolde/op/1", appareil, numéro, horloge, ressource, ligne, nature, champs triés]. Un changement attribué à un appareil absent de la liste du foyer est refusé.

L'appairage

  1. L'appareil relié affiche une invitation : zolde1.{adresse du relais}.{appairage}.{secret}, en QR code. Le secret (16 octets) ne passe jamais par le relais.
  2. Le nouvel appareil tire une paire X25519 et écrit dans offer son identifiant, son nom et sa clé publique, scellés avec HKDF-SHA256(secret, "zolde/pair/offer").
  3. Les deux écrans affichent un code à six chiffres : SHA-256(secret ‖ clé publique), réduit à six chiffres. S'il est identique, c'est bien cette clé publique qui a été reçue.
  4. Après confirmation, l'appareil relié écrit dans answer une clé publique éphémère et les secrets du foyer (adresse, boîte, jeton, clé du foyer, époque, clé du coffre des identifiants), scellés avec HKDF-SHA256(X25519 partagé ‖ secret, "zolde/pair/answer").

Le retrait d'un appareil

L'appareil qui retire tire une nouvelle boîte, un nouveau jeton, une nouvelle clé du foyer et une nouvelle clé du coffre. Il les scelle pour chaque appareil restant avec HKDF-SHA256(X25519(éphémère, clé publique de l'appareil), "zolde/rekey"), données authentifiées zolde/rekey|{boîte}|{appareil}, et les dépose dans la boîte actuelle. L'appareil retiré ne peut ouvrir aucun de ces messages.

4. Écrire votre relais

  1. Les quatre routes de la partie 1, en HTTPS.
  2. Un stockage durable : les lots d'une boîte doivent survivre à un redémarrage.
  3. Le jeton d'une boîte fixé à son premier dépôt, et vérifié ensuite.
  4. Des cases d'appairage qui ne s'écrivent qu'une fois.
  5. Aucun journal du contenu des lots ; idéalement, aucun journal des adresses réseau.

Ensuite, dans Zolde : Réglages › Appareils, saisissez l'adresse de votre relais au moment d'activer la synchronisation. Tous les appareils que vous reliez ensuite l'utilisent.