109 votes

Comment chiffrer les données qui doivent être déchiffrées en node.js ?

Nous utilisons bcrypt pour hacher les mots de passe et les données qui ne doivent jamais être décryptées. Que devrions-nous faire pour protéger les autres informations utilisateur qui nécessitent d'être décryptées ?

Par exemple, supposons que nous ne voulions pas que le vrai nom d'un utilisateur soit en texte brut au cas où quelqu'un obtiendrait un accès à la base de données. Il s'agit de données quelque peu sensibles mais qui doivent également être consultées de temps en temps et affichées en texte brut. Existe-t-il un moyen simple de faire cela ?

177voto

mak Points 5715

Vous pouvez utiliser le module crypto :

var crypto = require('crypto');
var assert = require('assert');

var algorithm = 'aes256'; // ou tout autre algorithme pris en charge par OpenSSL
var key = 'motdepasse';
var text = 'J\'aime les chatons';

var cipher = crypto.createCipher(algorithm, key);  
var encrypted = cipher.update(text, 'utf8', 'hex') + cipher.final('hex');
var decipher = crypto.createDecipher(algorithm, key);
var decrypted = decipher.update(encrypted, 'hex', 'utf8') + decipher.final('utf8');

assert.equal(decrypted, text);

Édition

Maintenant, createCipher et createDecipher sont obsolètes, utilisez plutôt createCipheriv et createDecipheriv

34voto

Bhumij Gupta Points 169

Une mise à jour de la réponse de @mak, crypto.createCipher et crypto.createDecipher ont été obsolètes. Le dernier code fonctionnel serait :

var crypto = require("crypto");
var algorithm = "aes-192-cbc"; // algorithme à utiliser
var secret = "votre-clé-secrète";
const key = crypto.scryptSync(secret, 'sel', 24); // créer la clé
var text = "voici le texte à crypter"; // texte à crypter

const iv = crypto.randomBytes(16); // générer un texte chiffré différent à chaque fois
const cipher = crypto.createCipheriv(algorithm, key, iv);
var encrypted = cipher.update(text, 'utf8', 'hex') + cipher.final('hex'); // texte chiffré

const decipher = crypto.createDecipheriv(algorithm, key, iv);
var decrypted = decipher.update(encrypted, 'hex', 'utf8') + decipher.final('utf8'); // texte déchiffré
console.log(decrypted);

26voto

expelledboy Points 471

Alors que cela a été répondu correctement, un bon modèle à utiliser avec la bibliothèque crypto est à l'intérieur d'une classe wrapper, que j'ai copiée/collée au fil des ans dans divers projets.

const crypto = require("crypto");

class Encrypter {
  constructor(encryptionKey) {
    this.algorithm = "aes-192-cbc";
    this.key = crypto.scryptSync(encryptionKey, "salt", 24);
  }

  encrypt(clearText) {
    const iv = crypto.randomBytes(16);
    const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);
    const encrypted = cipher.update(clearText, "utf8", "hex");
    return [
      encrypted + cipher.final("hex"),
      Buffer.from(iv).toString("hex"),
    ].join("|");
  }

  dencrypt(encryptedText) {
    const [encrypted, iv] = encryptedText.split("|");
    if (!iv) throw new Error("IV not found");
    const decipher = crypto.createDecipheriv(
      this.algorithm,
      this.key,
      Buffer.from(iv, "hex")
    );
    return decipher.update(encrypted, "hex", "utf8") + decipher.final("utf8");
  }
}

// Utilisation

const encrypter = new Encrypter("secret");

const clearText = "adventure time";
const encrypted = encrypter.encrypt(clearText);
const dencrypted = encrypter.dencrypt(encrypted);

console.log({ worked: clearText === dencrypted });

6voto

Amir Achhodi Points 94

La réponse acceptée était correcte mais il y a quelques changements car createCipher et createDecipher sont obsolètes.

Dans les nouvelles méthodes createCipheriv et createDecipheriv, une valeur iv est requise et la longueur de la valeur iv doit être de 128 bits et la clé doit être de 256 bits.

4voto

LogicalBranch Points 3584

Voici une version simplifiée de la réponse fournie par Saptarshi Basu :

Modifications :

  • Importer explicitement Buffer depuis le module buffer
  • Supprimer les déclarations de variables inutiles
  • Convertir une fois modifiées les variables let en variables const (ou les omettre complètement)
  • Convertir module.exports en un seul objet
  • Déplacer les déclarations exports.x = x = (...) vers l'objet module.exports
  • Simplifier et/ou réduire la documentation pour l'objet ALGORITHM

Code :

const crypto = require("crypto");
const { Buffer } = require("buffer");

const ALGORITHM = {
  // GCM est un mode de chiffrement authentifié qui assure la confidentialité et l'intégrité de façon sécurisée
  BLOCK_CIPHER: "aes-256-gcm",
  // Il est recommandé d'utiliser un tag d'authentification de 128 bits pour GCM
  AUTH_TAG_BYTE_LEN: 16,
  // Le NIST recommande un IV de 96 bits ou 12 octets pour GCM afin de favoriser l'interopérabilité, l'efficacité et la simplicité de conception
  IV_BYTE_LEN: 12,
  // REMARQUE : 256 (dans le nom de l'algorithme) est la taille de la clé (la taille de bloc pour AES est toujours de 128)
  KEY_BYTE_LEN: 32,
  // pour prévenir les attaques par table arc-en-ciel
  SALT_BYTE_LEN: 16
};

module.exports = {
  getRandomKey() {
    return crypto.randomBytes(ALGORITHM.KEY_BYTE_LEN);
  },

  // pour prévenir les attaques par table arc-en-ciel
  getSalt() {
    return crypto.randomBytes(ALGORITHM.SALT_BYTE_LEN);
  },

  /**
   *
   * @param {Buffer} password - Le mot de passe à utiliser pour générer la clé
   *
   * À utiliser lorsque la clé doit être générée en fonction du mot de passe.
   * L'appelant de cette fonction est responsable de vider
   * le tampon après la génération de la clé pour empêcher le mot de passe
   * de rester en mémoire
   */
  getKeyFromPassword(password, salt) {
    return crypto.scryptSync(password, salt, ALGORITHM.KEY_BYTE_LEN);
  },

  /**
   *
   * @param {Buffer} messagetext - Le message en clair à chiffrer
   * @param {Buffer} key - La clé à utiliser pour le chiffrement
   *
   * L'appelant de cette fonction est responsable de vider
   * le tampon après le chiffrement pour empêcher le texte du message
   * et la clé de rester en mémoire
   */
  encrypt(messagetext, key) {
    const iv = crypto.randomBytes(ALGORITHM.IV_BYTE_LEN);
    const cipher = crypto.createCipheriv(ALGORITHM.BLOCK_CIPHER, key, iv, {
      authTagLength: ALGORITHM.AUTH_TAG_BYTE_LEN
    });
    let encryptedMessage = cipher.update(messagetext);
    encryptedMessage = Buffer.concat([encryptedMessage, cipher.final()]);
    return Buffer.concat([iv, encryptedMessage, cipher.getAuthTag()]);
  },

  /**
   *
   * @param {Buffer} ciphertext - Texte chiffré
   * @param {Buffer} key - La clé à utiliser pour le déchiffrement
   *
   * L'appelant de cette fonction est responsable de vider
   * le tampon après le déchiffrement pour empêcher le texte du message
   * et la clé de rester en mémoire
   */
  decrypt(ciphertext, key) {
    const authTag = ciphertext.slice(-16);
    const iv = ciphertext.slice(0, 12);
    const encryptedMessage = ciphertext.slice(12, -16);
    const decipher = crypto.createDecipheriv(ALGORITHM.BLOCK_CIPHER, key, iv, {
      authTagLength: ALGORITHM.AUTH_TAG_BYTE_LEN
    });
    decipher.setAuthTag(authTag);
    const messagetext = decipher.update(encryptedMessage);
    return Buffer.concat([messagetext, decipher.final()]);
  }
};

N'oubliez pas que bien que simplifié, ce code est censé être fonctionnellement identique à celui de Saptarshi Basu.

Bonne chance.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X