50 votes

Crypter des données avec une clé publique en Node.js

Je dois chiffrer une chaîne de caractères à l'aide d'une clé publique (fichier .pem), puis la signer à l'aide d'une clé privée (également un fichier .pem).

Je charge bien les fichiers .pem :

publicCert = fs.readFileSync(publicCertFile).toString();

Mais après des heures de recherche sur Google, je n'arrive pas à trouver un moyen de chiffrer des données à l'aide de la clé publique. En PHP, j'appelle simplement openssl_public_encrypt(), mais je ne vois aucune fonction correspondante dans Node.js ou dans aucun module.

149voto

moobchunks Points 41

Une bibliothèque n'est pas nécessaire. Entrez dans crypto .

Voici un petit module bizarre que vous pouvez utiliser pour crypter/décrypter des chaînes de caractères avec des clés RSA :

var crypto = require("crypto");
var path = require("path");
var fs = require("fs");

var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey) {
    var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
    var publicKey = fs.readFileSync(absolutePath, "utf8");
    var buffer = Buffer.from(toEncrypt);
    var encrypted = crypto.publicEncrypt(publicKey, buffer);
    return encrypted.toString("base64");
};

var decryptStringWithRsaPrivateKey = function(toDecrypt, relativeOrAbsolutePathtoPrivateKey) {
    var absolutePath = path.resolve(relativeOrAbsolutePathtoPrivateKey);
    var privateKey = fs.readFileSync(absolutePath, "utf8");
    var buffer = Buffer.from(toDecrypt, "base64");
    var decrypted = crypto.privateDecrypt(privateKey, buffer);
    return decrypted.toString("utf8");
};

module.exports = {
    encryptStringWithRsaPublicKey: encryptStringWithRsaPublicKey,
    decryptStringWithRsaPrivateKey: decryptStringWithRsaPrivateKey
}

Je recommanderais de ne pas utiliser le synchrone fs lorsque cela est possible, et vous pourriez utiliser les méthodes promesses pour l'améliorer, mais pour les cas d'utilisation simples, c'est l'approche que j'ai vue fonctionner et que j'adopterais.

1 votes

Merci pour la solution @JacobMcKay J'ai gagné quelques heures.

6 votes

Il convient de mentionner que vous ne pouvez crypter que de petites quantités de données (jusqu'à 245 octets) avec la clé publique et que pour des quantités plus importantes, vous devez utiliser AES256 avec la clé privée cryptée à l'aide d'une paire public-privé. Voir cette réponse : security.stackexchange.com/questions/33434/

0 votes

"crypto.publicEncrypt" ne fonctionne pas dans node.js, comme beaucoup de fonctions de 'crypto'

28voto

BrunoLM Points 26573

J'ai testé cela dans Node.js 10, vous pouvez utiliser des fonctions de cryptage/décryptage (petits changements sur La réponse de Jacob ) :

const crypto = require('crypto')
const path = require('path')
const fs = require('fs')

function encrypt(toEncrypt, relativeOrAbsolutePathToPublicKey) {
  const absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey)
  const publicKey = fs.readFileSync(absolutePath, 'utf8')
  const buffer = Buffer.from(toEncrypt, 'utf8')
  const encrypted = crypto.publicEncrypt(publicKey, buffer)
  return encrypted.toString('base64')
}

function decrypt(toDecrypt, relativeOrAbsolutePathtoPrivateKey) {
  const absolutePath = path.resolve(relativeOrAbsolutePathtoPrivateKey)
  const privateKey = fs.readFileSync(absolutePath, 'utf8')
  const buffer = Buffer.from(toDecrypt, 'base64')
  const decrypted = crypto.privateDecrypt(
    {
      key: privateKey.toString(),
      passphrase: '',
    },
    buffer,
  )
  return decrypted.toString('utf8')
}

const enc = encrypt('hello', `public.pem`)
console.log('enc', enc)

const dec = decrypt(enc, `private.pem`)
console.log('dec', dec)

Pour les clés, vous pouvez les générer avec

const { writeFileSync } = require('fs')
const { generateKeyPairSync } = require('crypto')

function generateKeys() {
  const { privateKey, publicKey } = generateKeyPairSync('rsa', {
    modulusLength: 4096,
    publicKeyEncoding: {
      type: 'pkcs1',
      format: 'pem',
    },
    privateKeyEncoding: {
      type: 'pkcs1',
      format: 'pem',
      cipher: 'aes-256-cbc',
      passphrase: '',
    },
  })

  writeFileSync('private.pem', privateKey)
  writeFileSync('public.pem', publicKey)
}

0 votes

Cela m'a pris des jours mais j'ai finalement trouvé une explication pour laquelle cela ne fonctionne pas en russe et j'ai pensé l'ajouter ici. qaru.site/questions/16043509/ il est indiqué que publicEncrypt utilise openssl et que c'est uniquement RSA donc AUCUNE utilisation de crypto.createECDH secp384r1 ne provoquera une erreur de "unhandledRejection Error : error:0906D06C:PEM routines:PEM_read_bio:no start line" dans publicEncrypt un conseil sur la façon d'utiliser des clés elliptiques à bits plus élevés ? j'ai également noté que Chrome n'ira pas à 512 avec EC non plus. Ceci à partir de nodejs 11.6 nodejs.org/api/crypto.html

0 votes

De même, lorsque l'on essaie d'obtenir quelque chose de crypté dans le navigateur à partir d'un nœud, les clés doivent être générées dans le navigateur, la clé publique étant importée dans le nœud.

0 votes

Merci pour cette réponse, cela m'a appris comment utiliser l'objet JSON pour passer la "passphrase" à la fonction privateDecrypt.

8voto

Louie Miranda Points 384

Le module de déchiffrement et de chiffrement public/privé mis à jour est le suivant URSA . Le module node-rsa est périmé.

Ce module Node fournit un ensemble assez complet d'enveloppes pour la fonction fonctionnalité de cryptage des clés publiques/privées RSA d'OpenSSL.

npm install ursa

4 votes

Ursa n'a pas été entretenu depuis un certain temps. Ces implémentations plus récentes pourraient vous aider : github.com/tracker1/cryptico-js y github.com/rzcoder/node-rsa

0 votes

Merci pour la mise à jour, la réponse a maintenant 7 ans en 2020.

7voto

Peter Lyons Points 47794

Utilisez le module node-rsa . Voici un lien vers le fichier test.js qui démontre l'utilisation .

1 votes

Peut-être que je dois me familiariser davantage avec le cryptage RSA. J'ai lu les docs sur la cryptographie une douzaine de fois pour essayer de voir comment faire ce dont j'ai besoin, mais je n'ai rien trouvé. Vous dites que createCipheriv() fera ce dont j'ai besoin, mais je ne sais même pas ce qu'est "iv". Je suppose que c'est parce que c'est plus abstrait en PHP et dans d'autres langages. Je vais jouer avec cette fonction et voir si je peux la faire fonctionner.

1 votes

Après avoir lu davantage sur createCipheriv, il semble que ce ne soit pas un chiffrement asymétrique (chiffrement à clé publique/privée). Je ne pense pas qu'il répondra à mes besoins. Crypto a la possibilité de signer une chaîne cryptée avec une clé privée, ce qui me fait me demander pourquoi je ne peux pas crypter en utilisant une clé publique. C'est étrange, ou alors je rate quelque chose.

0 votes

Iv est un vecteur d'initialisation. fr.wikipedia.org/wiki/Initialization_vector

5voto

B T Points 4868

TL;DR : URSA est votre meilleure option. C'est vraiment funky que cela ne soit pas livré en standard avec Node.js'. crypto .

Toutes les autres solutions que j'ai trouvées ne fonctionnent pas sous Windows ou ne sont pas vraiment des bibliothèques de cryptage. URSA, recommandé par Louie semble être le meilleur choix. Si vous ne vous souciez pas de Windows, vous êtes encore mieux loti.

Note sur Ursa : J'ai dû installer OpenSSL avec quelque chose appelé "Visual C++ 2008 Redistributables" pour que l'installation de npm fonctionne. Obtenez ce truc ici : http://slproweb.com/products/Win32OpenSSL.html

La panne :

Pas de bibliothèques de cryptage

C'est littéralement tout ce que j'ai pu trouver.

1 votes

Node-rsa ne s'appuie plus sur node-waf. Il est compatible avec les navigateurs.

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