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ête | Contenu |
|---|---|
Authorization | Bearer {jeton} : le jeton de la boîte. |
X-Zolde-Device | Identifiant 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 :
201et{"cursor": 42}: le lot est gardé. Le curseur est un entier qui ne fait que croître ; deux lots n'ont jamais le même.401: le jeton ne correspond pas à la boîte.
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.
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.
PUT:201si la case était vide ;409si elle est déjà écrite (une case ne s'écrit qu'une fois).GET:200et le contenu tel qu'il a été écrit ;404tant qu'elle est vide.
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 voit | Le relais ne voit pas |
|---|---|
|
|
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
- Les changements, en JSON :
{"device_id", "from", "to", "ops"}, puis compressés (zlib). - Scellés avec la clé du foyer (32 octets) par
ChaCha20-Poly1305.sealed= nonce (12 octets) ‖ chiffré ‖ étiquette (16 octets). - 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. - 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
- 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. - Le nouvel appareil tire une paire
X25519et écrit dansofferson identifiant, son nom et sa clé publique, scellés avecHKDF-SHA256(secret, "zolde/pair/offer"). - 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. - Après confirmation, l'appareil relié écrit dans
answerune 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 avecHKDF-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
- Les quatre routes de la partie 1, en HTTPS.
- Un stockage durable : les lots d'une boîte doivent survivre à un redémarrage.
- Le jeton d'une boîte fixé à son premier dépôt, et vérifié ensuite.
- Des cases d'appairage qui ne s'écrivent qu'une fois.
- 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.