Chiffrement des sauvegardes
QuietGuard\Monitor\Backup\BackupCipher fournit les primitives de chiffrement hybride en flux derrière le coffre de sauvegarde à connaissance nulle. Il est agnostique vis-à-vis du framework et entièrement bâti sur libsodium (ext-sodium). Le serveur ne stocke jamais que le résultat opaque ; il ne détient jamais la clé, et ne peut donc jamais lire une sauvegarde.
Le schéma
Une sauvegarde est chiffrée avec une clé symétrique aléatoire fraîche, et cette clé est ensuite scellée vers la clé X25519 publique de l'équipe :
- L'archive est chiffrée avec le secretstream de libsodium (XChaCha20-Poly1305) en chunks de texte clair de 64 Kio (AEAD par morceaux).
- La clé symétrique aléatoire est scellée vers la clé publique de l'équipe avec
crypto_box_seal. - La restauration nécessite la clé privée de l'équipe, déscellée localement à partir de la passphrase de l'équipe: en miroir du scellement du serveur (Argon2id MODERATE →
secretbox) afin que l'opérateur ne soit jamais dans la boucle.
La disposition du blob résultant est :
Chiffrer un fichier
encryptFile() génère une clé secretstream à usage unique, la scelle vers la clé publique encodée en base64, écrit la clé scellée, le header du flux et les chunks AEAD (le dernier chunk porte le marqueur TAG_FINAL), en effaçant la clé symétrique de la mémoire à la fin. Il traite l'entrée en flux, de sorte que l'usage mémoire reste borné quelle que soit la taille de l'archive.
Déchiffrer un fichier
Le déchiffrement nécessite à la fois la clé publique et les octets bruts de la clé privée :
decryptFile() lit la clé scellée, récupère la clé symétrique avec la paire de clés X25519, puis tire et vérifie chaque chunk. Il lève une RuntimeException si la paire de clés ne peut pas ouvrir la clé scellée (« Unable to recover the backup key (wrong key pair) ») ou si un chunk échoue à sa vérification d'authentification (« Backup is corrupted or has been tampered with »).
Désceller la clé privée
La clé privée nécessaire ci-dessus est obtenue à partir du matériel de clé scellé par le serveur plus la passphrase de l'équipe :
unwrapPrivateKey() dérive une clé de chiffrement de clé à partir de la passphrase et du sel avec Argon2id aux limites ops/mem MODERATE (ALG_ARGON2ID13), puis ouvre la trame secretbox (nonce | ciphertext). Il lève une RuntimeException en cas de matériel corrompu ou de mauvaise passphrase. Cela reflète intentionnellement le scellement du TeamCipher du serveur afin que la clé puisse être reconstruite côté client et que le serveur ne la voie jamais.
Où c'est utilisé
Les clients bâtissent leurs commandes monitor:backup / monitor:restore sur ces primitives. Le SDK Laravel expose une fine sous-classe Support\BackupCipher de cette classe ; le bundle Symfony et le plugin WordPress réutilisent le cœur directement. Le flux côté serveur correspondant (stockage de blob opaque, quota en Go, API de matériel de clé) fait partie du coffre de sauvegarde Quiet Guard.
Vous lisez la documentation PHP Core v1.0.