# Démarrage rapide

Pour démarrer rapidement, nous allons intégrer les fonctionnalités de chiffrement & déchiffrement directement dans le projet exemple, en protégeant l'identité par mot de passe.

La branche sur laquelle est basée cette étape est master (opens new window), le résultat final est 1-quick-start (opens new window).

# Installation

Nous allons utiliser la version "web" du SDK @seald-io/sdk-web avec le module de protection de l'identité par mot de passe @seald-io/sdk-plugin-ssks-password :

cd frontend
npm install @seald-io/sdk-web @seald-io/sdk-plugin-ssks-password

Pour le moment, il n'y a aucune modification à apporter à la partie backend.

# Configuration

Pour configurer le SDK, il faut se connecter à votre tableau d'administration et récupérer les 3 éléments suivants :

  • appId : UUID unique pour votre application ;
  • validationKeyId : UUID unique de la clé de validation ;
  • validationKey : clé de validation secrète correspondant à la validationKeyId utilisée pour générer des jetons de licence hors-ligne.

TIP

Pour créer un compte développeur, suivez les premiers pas.

Pour instancier le SDK, on procède comme suit :

TIP

Étant donné que l'instance du SDK est partagée à travers toute une application en React, il est préférable de la stocker dans une variable dans un fichier de service seald.js et d'exposer un getter plutôt que de l'enregistrer dans une variable immutable.

# Gestion des identités Seald

Lors de la création d'une identité Seald, il faut l'associer d'une part au compte développeur, et d'autre part à l'utilisateur (dont l'identifiant est noté userId) dans l'application dans laquelle on intègre le SDK.

Pour cela, il faut générer un jeton de licence utilisateur appelé userLicenseToken à partir de la validationKeyId, la validationKey et le userId et l'utiliser lors de la création de l'identité.

# Génération d'un userLicenseToken

La génération d'un userLicenseToken se fait hors ligne, et est décrite dans ce guide dédié.

Cette opération doit être effectuée depuis le backend, mais dans un premier temps nous effectuerons cette opération côté frontend pour arriver plus vite à un prototype fonctionnel. On peut utiliser la fonction utils.generateUserLicenseToken comme suit :

WARNING

En production, il ne faut pas donner au frontend la connaissance de la clé de validation. Si c'était le cas, elle pourrait être utilisée par un attaquant pour créer de nouveaux comptes associés à votre compte développeur, et notamment utiliser votre volumétrie.

Vous pouvez vous référer au guide dédié aux jetons de validation.

# Création d'une identité

Une fois le jeton généré, on peut créer une nouvelle identité de la façon suivante :

Une fois cette fonction exécutée, l'instance du SDK est prête pour chiffrer et déchiffrer, et les clés propres à l'identité sont en mémoire.

# Protection de l'identité par mot de passe

Une fois l'identité créée, elle n'existe qu'en mémoire, il faut la sauvegarder pour pouvoir l'utiliser dans une session ultérieure.

Pour cela nous allons utiliser le module @seald-io/sdk-plugin-ssks-password qui permet de protéger les clés d'identité par un mot de passe password.

Une fois cette fonction exécutée, l'identité est sauvegardée et pourra être récupérée en utilisant la fonction équivalente sealdSDKInstance.ssksPassword.retrieveIdentity depuis une instance nouvellement instanciée.

Pour plus de détails sur ce mécanisme, référez-vous au guide dédié à la protection des identités par mot de passe.

# Exposer des fonctions createIdentity et retrieveIdentity

Si on rassemble tous les éléments étudiés dans les parties précédentes, on peut exposer deux fonctions :

# Intégrer à la création de compte et à la connexion

L'étape suivante consiste à appeler ces fonctions lors de la création du compte dans l'application et lors de la connexion.

Pour la créer lors de la création de compte :

Pour la récupérer à la connexion :

Comme l'identité n'est conservée qu'en mémoire dans le navigateur, si vous ouvrez un nouvel onglet, vous devrez retaper le mot de passe. Pour contourner ce problème, nous n'essayons pas d'obtenir du serveur le profil de l'utilisateur connecté :

Nous verrons plus tard comment faire persister cette identité dans le navigateur.

WARNING

Nous mettons ici de côté un souci majeur de sécurité : le mot de passe d'authentification ne doit pas être utilisé tel quel pour protéger l'identité. Il faut modifier la méthode d'authentification (avec une pré-dérivation du mot de passe) pour que le serveur applicatif ne puisse pas avoir connaissance du mot de passe. Un guide dédié est disponible ici.

# Chiffrer & déchiffrer des messages

Pour effectuer des chiffrements et déchiffrements de messages, il faut :

  • créer une session de chiffrement partagée entre les destinataires ;
  • chiffrer les messages avant envoi ;
  • déchiffrer les messages après réception.

# Session de chiffrement

Pour créer une session de chiffrement partagée entre les utilisateurs userId_1 et userId_2 dans le salon de chat roomId_1, on procède de la façon suivante :

Cela renvoie une EncryptionSession avec un nouveau sessionId unique attribué par le serveur.

Dans le cadre de ce projet, on place dans metadata l'identifiant du salon de chat roomId.

Pour chiffrer un message avec une session, on procède comme suit :

Cela va donner un string de la forme :

'{"sessionId":"0000000000000000000000","data":"8RwaOppCD3uIJVFv2LoP3XGXpomj0xsMv4qmMVy30Vdqor2w0+DVCXu3j13PEyN2KfJm6SiSrWDRMDziiiOUjQ=="}'

On peut récupérer une instance de la session, soit avec le sessionId, soit directement avec le message chiffré :

Une fois la session récupérée, on peut l'utiliser pour déchiffrer un message :

On peut aussi ajouter / révoquer des destinataires de la session :

Pour plus de détails sur les sessions, vous pouvez consulter le guide dédié.

# Intégration dans un salon de chat

Pour intégrer ces fonctions dans le chat, il faut modifier trois éléments :

  • l'envoi des messages, qui doit désormais chiffrer pour les destinataires du salon ;
  • la réception de messages, qui doit désormais déchiffrer ;
  • la gestion des membres d'un salon, qui doit désormais transposer les membres d'un salon en droits cryptographiques.

# Chiffrement à l'envoi

Il faut appeler la fonction encrypt à chaque fois qu'un message est posté.

Dans le fichier Chat.jsx se trouve une fonction handleSumbitMessage que l'on va modifier pour y incorporer du chiffrement :

Par ailleurs, lors de la création d'un salon de chat multi-utilisateurs dans ManageDialogRoom.jsx un message 'Hello 👋'est envoyé. Il faut le chiffrer :

# Déchiffrement à la réception

Il faut appeler la fonction decrypt à chaque fois qu'un message est collecté.

Pour cela on va créer quelques fonctions helpers dans Chat.jsx qui serviront à utiliser le même modèle de données partout :

On va modifier l'eventListener de l'évènement room:messageSent :

On va modifier la récupération de l'historique des messages au chargement d'un salon :

# Modifier les droits à l'édition d'un salon

Lorsque le salon est multi-utilisateurs, le créateur du salon peut ajouter / supprimer des membres. Les sessions permettent de gérer ces mouvements.

Pour cela il faut au moment où le créateur du salon effectue ces mouvements sur le salon, effectuer les mêmes mouvements sur la session de chiffrement.

Lorsque l'on déclenche la modification d'un salon, il faut donner la session associée au salon lors du dispatch :

Dans ManageDialogRoom.jsx avant de faire l'appel API au serveur pour effectivement éditer le salon :

# Conclusion

Nous avons pu intégrer rapidement du chiffrement dans ce projet, restent en suspens 3 sujets avant de passer en production :

  • la pré-dérivation du mot de passe ;
  • la persistance de l'identité à l'ouverture d'un nouvel onglet en stockant l'identité en localstorage ;
  • la génération des jetons de licence depuis le backend.