Skip to content

Réversibilité

Pour prévoir les cas ou vous auriez besoin d'arrêter d'utiliser le SDK Seald, et de récupérer les données de votre application dans un état déchiffré, nous avons prévu un outil de réversibilité.

Cet outil utilise un export des données Seald pour votre application, venant de nos serveurs API et SSKS, ainsi qu'un export de certaines données venant de votre "backend", pour pouvoir déchiffrer les données chiffrées avec le SDK Seald.

Attention, l'usage de cet outil casse le chiffrement de bout-en-bout. Il est prévu pour les cas exceptionnels où vous avez besoin d'arrêter d'utiliser le SDK Seald, et aucunement pour un usage courant.

Si vous êtes intéressés par cet outil, nous vous recommandons fortement de tester la procédure de réversibilité par avance sur votre environnement de Staging.

WARNING

Cette procédure de réversibilité nécessite que vous ayez accès aux identités de chaque utilisateur. Ce n'est pas toujours possible, par exemple si vous utilisez seulement la protection par mot de passe, avec un mot de passe qui n'est connu qu'aux utilisateurs.

Si vous utilisez le mécanisme de 2-man-rule pour stocker les identités des utilisateurs, vous devriez pouvoir suivre cette procédure et déchiffrer les identités des utilisateurs avec les exports SSKS de Seald plus l'export de votre serveur.

Si vous n'utilisez pas le 2-man-rule, vous devrez peut-être deployer du code coté client pour récupérer les identités de vos utilisateurs.

Export des données Seald

Pour obtenir cet export, vous devez contacter le support Seald, qui vous fournira ces fichiers.

Nous pouvons également mettre en place un export régulier de ces données vers un Object Storage compatible S3 sous votre contrôle, si vous le souhaitez. Dans ce cas, nous exporterons périodiquement ces données vers vos serveurs.

Ces données sont chiffrées pour une clé privée. Cette clé privée peut être sous votre contrôle ; dans ce cas nous recommandons de la stocker hors-ligne, sur un ou plusieurs supports physiques (clé USB, disque dur, etc.), stockés dans un lieu sur. La clé privée peut également être mise sous séquestre chez un tiers de confiance, tel que l'Agence de Protection des Programmes (APP), qui pourra vous la fournir en cas de cloture de votre contrat, ou de défaillance contractuelle de Seald (des frais supplémentaires pour cette séquestre peuvent s'appliquer).

Export des données de votre backend

Vous devez également exporter certaines données de votre backend, pour pouvoir déchiffrer les données chiffrées avec le SDK Seald. Ces données sont optionnelles, selon les fonctionnalités du SDK Seald que vous utilisez dans votre application.

Ces données, et le format de l'export attendu, sont décrites dans la section Utilisation de l'outil de réversibilité ci-dessous.

Vous devez bien entendu également vous assurer d'avoir accès aux données chiffrées à déchiffrer.

Installation de l'outil de réversibilité

L'outil de réversibilité est une librairie JavaScript, disponible en tant que paquet npm : https://www.npmjs.com/package/@seald-io/reversibility-tools.

Vous pouvez l'installer dans votre projet en utilisant la commande suivante :

bash
npm install @seald-io/reversibility-tools

Vous pouvez ensuite l'utiliser dans votre code JavaScript.

Utilisation de l'outil de réversibilité

L'outil de réversibilité est une librairie Node.JS, destinée à être utilisée dans des scripts JavaScript que le développeur écrit pour réaliser ce processus.

Ce processus est fait en 3 étapes :

  • Obtention d'une base de données d'identités déchiffrées
  • Obtention d'une base de données de clés de session déchiffrées
  • Déchiffrement des données elles-mêmes

Obtention d'une base de données d'identités déchiffrées

Une base de données d'identités déchiffrées (le résultat de cette étape) est un fichier JSONLines, contenant :

{ sealdId: string, deviceId: string, identity: string }

Le champ identity contient l'encodage Base64 du buffer d'identité.

Ce fichier peut être construit de plusieurs manières.

Premièrement, cela peut être fait directement par le développeur, en appelant sealdSdk.exportIdentity() sur ses clients, puis en renvoyant ces identités à son serveur, et en construisant ce fichier manuellement.

Sinon, cette base de données peut être obtenue via la fonction decryptSsksExport(ssksExportPath, privateKey, outputPath, { appId, ssksTmrKeysPath, ssksStrictPasswordsPath }) des outils de réversibilité.

Dans cet appel de fonction :

  • ssksExportPath est le chemin vers le fichier d’export SSKS fourni par Seald
  • privateKey est une instance de SSCrypto contenant votre clé privée avec laquelle les exports ont été chiffrés
  • outputPath est le chemin vers lequel écrire le fichier de sortie (le dossier doit déjà exister). Si le fichier existe déjà, il sera écrasé.
  • appId est votre App ID Seald
  • ssksTmrKeysPath est un argument optionnel, si vous souhaitez récupérer les identités depuis SSKS 2MR. C’est le chemin vers un fichier exporté depuis votre base de données, contenant le twoManRuleKey ou le rawTwoManRuleKey pour chaque utilisateur de votre app, sous forme de fichier JSONLines, au format suivant :
{ userId: string, sealdId?: string, deviceId?: string, rawTwoManRuleKey?: string, twoManRuleKey?: string }

Chaque ligne doit contenir une seule, et une seule, des clés rawTwoManRuleKey ou twoManRuleKey. Les champs sealdId et deviceId sont optionnels, et servent à vérifier que l’identité déchiffrée correspond bien à ce qui est attendu.

  • ssksStrictPasswordsPath est un argument optionnel, si vous souhaitez récupérer les identités depuis SSKS Password. C’est le chemin vers un fichier exporté depuis votre base de données, contenant le password ou le rawEncryptionKey utilisé pour stocker son identité sur SSKS Password pour chaque utilisateur de votre app, sous forme de fichier JSONLines, au format suivant :
{ userId: string, sealdId?: string, deviceId?: string, password?: string, rawEncryptionKey?: string }

Chaque ligne doit contenir une seule, et une seule, des clés password ou rawEncryptionKey. Les champs sealdId et deviceId sont optionnels, et servent à vérifier que l’identité déchiffrée correspond bien à ce qui est attendu.

Obtention d'une base de données de clés de session déchiffrées

Une fois que vous avez la base de données d’identités déchiffrées, vous pouvez utiliser la fonction decryptApiExport(apiExportPath, decryptedIdentitiesPath, privateKey, outputPath, { tmrAccessesOverEncryptionKeysPath?, symEncKeysPath?, appId? }) des outils de réversibilité.

Dans cet appel de fonction :

  • apiExportPath est le chemin vers le fichier d’export de l’API Seald principale fourni par Seald
  • decryptedIdentitiesPath est le chemin vers le fichier obtenu à l’étape précédente
  • privateKey est une instance de SSCrypto contenant votre clé privée avec laquelle les exports ont été chiffrés
  • tmrAccessesOverEncryptionKeysPath est un argument optionnel, si vous souhaitez récupérer les clés de session à partir des TMR Accesses. Il s’agit du chemin vers un fichier exporté depuis votre base de données, contenant les rawOverEncryptionKey pour chaque TMR Access, sous forme de fichier JSONLines, au format suivant :
{ sessionId: string, tmrAccessId: string, rawOverEncryptionKey: string }
  • groupTmrTemporaryKeysOverEncryptionKeysPath est un argument optionnel, si vous souhaitez récupérer les clés de session depuis les "Group TMR Temporary Keys". Il s’agit du chemin vers un fichier exporté depuis votre base de données, contenant les rawOverEncryptionKey pour chaque Group TMR Temporary Key, sous forme de fichier JSONLines, au format suivant :
{ gTMRTKId: string, rawOverEncryptionKey: string }
  • symEncKeysPath est un argument optionnel, si vous souhaitez récupérer les clés de session depuis SymEncKeys. Il s’agit du chemin vers un fichier exporté depuis votre base de données, contenant les Sym Enc Keys, sous forme de fichier JSONLines, au format suivant :
{ sessionId: string, symEncKeyId: string, rawSecret?: string, rawSymKey?: string, password?: string }

Chaque ligne doit contenir soit password, soit le couple rawSecret et rawSymKey, mais pas les deux.

  • appId est l’ID de votre application Seald. Il est requis uniquement si vous fournissez symEncKeysPath.

Cela produira un fichier JSONLines au format suivant :

{ sessionId: string, key: string }

Déchiffrement des données elles-mêmes

Une fois que vous avez la base de données des clés de session déchiffrées, vous pouvez utiliser les fonctions decryptMessage(encryptedMessage, decryptedSessionKeysPath, { raw , sessionId }) et decryptFile(encryptedFileStream, decryptedSessionKeysPath, { sessionId }) pour déchiffrer respectivement les messages et les fichiers.

Dans l’appel de la fonction decryptMessage :

  • encryptedMessage est le message chiffré à déchiffrer
  • decryptedSessionKeysPath est le chemin vers le fichier obtenu à l’étape précédente
  • raw est un booléen optionnel (par défaut à false), à définir à true si le message a été chiffré en mode raw
  • sessionId est l’ID de session correspondant à ce message. Optionnel si le message n’est pas en mode raw. Obligatoire si le message est en mode raw.

Cette fonction retourne le contenu du message déchiffré sous forme de string.

Dans l’appel de la fonction decryptFile :

  • encryptedFileStream est un flux Readable du fichier à déchiffrer
  • decryptedSessionKeysPath est le chemin vers le fichier obtenu à l’étape précédente
  • sessionId est l’ID de session correspondant à ce fichier. Optionnel.

Cette fonction retourne :

  • stream : un stream Readable contenant le contenu du fichier déchiffré
  • promise : une Promise qui se résout une fois le parsing terminé, et qui contient la taille du fichier size, le nom du fichier filename, la version du protocole protocol, et l’ID de session analysé mid

Exemple d'utilisation

Un exemple complet d'utilisation de l'outil de réversibilité est disponible sur GitHub, à l'adresse https://github.com/seald/seald-reversibility-tools-demo.

Voici également un exemple basique d'utilisation de l'outil de réversibilité :

javascript
const { node: sscrypto } = require('sscrypto')
const fs = require('node:fs')
const {
  decryptApiExport,
  decryptFile,
  decryptMessage,
  decryptSsksExport
} = require('@seald-io/reversibility-tools')

// Votre Seald Application Id
const appId = 'YOUR_APP_ID'

const databaseReversibilityDemo = async () => {
  // Crée un dossier de sortie pour les fichiers déchiffrés
  await fs.promises.mkdir('./clear-files', { recursive: true })

  // Charge et instancie une SSCrypto.PrivateKey
  // Ceci est la clé privée utilisée pour chiffrer les exports Seald
  const privateKeyB64 = await fs.promises.readFile('./seald-database-exports/private_key', 'utf8')
  const privateKeyInstance = sscrypto.PrivateKey.fromB64(privateKeyB64)

  // Premièrement, déchiffrer l'export des identités
  // Cela créera un fichier contenant les SealdIds et leurs clés privées associées
  await decryptSsksExport(
    './seald-database-exports/test-ssks.backup',
    privateKeyInstance,
    './clear-files/identities.jsonl',
    {
      appId,
      ssksTmrKeysPath: './exports/ssks-tmr-keys.jsonl',
      ssksStrictPasswordsPath: './exports/ssks-strict-passwords.jsonl'
    }
  )

  // Deuxièmement, déchiffrer l'export de l'API
  // Cela créera un fichier associant les IDs de session et la clé de chiffrement symétrique correspondante.
  await decryptApiExport(
    './seald-database-exports/api.backup',
    './clear-files/identities.jsonl',
    privateKeyInstance,
    './clear-files/sessions.jsonl',
    {
      tmrAccessesOverEncryptionKeysPath: './exports/tmr-accesses-over-encryption-keys.jsonl',
      tmrTemporaryKeysOverEncryptionKeysPath: './exports/group-tmr-temp-key-over-encryption-key.jsonl',
      symEncKeysPath: './exports/sym-enc-keys.jsonl',
      appId
    }
  )

  // Maintenant que la base de données Seald a été entièrement déchiffrée, nous pouvons déchiffrer n'importe quel message

  // Déchiffre un fichier
  const res = decryptFile(
    fs.createReadStream('./encrypted-files/test.txt.seald'),
    './clear-files/sessions.jsonl'
  )
  await fs.promises.writeFile('./clear-files/test.txt', res.stream)

  // Déchiffre un message
  const encrypted = await fs.promises.readFile('./encrypted-files/test-message.bin', 'utf8')
  const decryptedMessage = await decryptMessage(encrypted, './clear-files/sessions.jsonl')
  await fs.promises.writeFile('./clear-files/test-message.txt', decryptedMessage)
}

databaseReversibilityDemo()