Шифрование данных открытым ключом в Node.js

Мне нужно зашифровать строку с помощью открытого ключа (файл .pem), а затем подписать ее с помощью закрытого ключа (также .pem).

Я нормально загружаю файлы .pem:

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

Но после нескольких часов изучения Google я не могу найти способ зашифровать данные с помощью открытого ключа. В PHP я просто вызываю openssl_public_encrypt (), но я не вижу соответствующей функции ни в Node.js, ни в каких-либо модулях.


person Clint    schedule 05.01.2012    source источник


Ответы (6)


Библиотека не нужна. Введите крипто.

Вот маленький дрянной модуль, который можно использовать для шифрования / дешифрования строк с помощью ключей 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
}

Я бы рекомендовал не использовать синхронные методы fs там, где это возможно, и вы могли бы использовать promises, чтобы сделать это лучше, но для простых случаев использования это подход, который, как я видел, работает и который я бы выбрал.

person Jacob McKay    schedule 25.06.2015
comment
Спасибо за решение. @JacobMcKay Сэкономил мне пару часов. - person uzyn; 13.09.2016
comment
Стоит упомянуть, что вы можете зашифровать только небольшие объемы (до 245 байт) данных с помощью открытого ключа, а для больших объемов вы должны использовать AES256 с закрытым ключом, зашифрованным с использованием пары общедоступный-частный. См. Этот ответ: security.stackexchange.com/questions/33434/ - person jmc; 17.05.2017
comment
crypto.publicEncrypt не работает в node.js, как и многие функции из 'crypto' - person croraf; 23.10.2017
comment
Потрясающе: D Еще одна вещь, ключевой файл должен быть в формате .pem: openssl rsa -in ~/.ssh/id_rsa -outform pem > id_rsa.pem - person Bodhi Hu; 26.04.2018
comment
что, если у меня есть ключ в файле .der? - person Sourav Prem; 05.06.2018
comment
А что, если privateKey зашифрован и зашифрован с помощью парольной фразы? Я не могу найти правильный вызов метода crypto.privateDecrypt () - person maroodb; 07.01.2019
comment
@maroodb генерирует ваши открытые и закрытые ключи с помощью генератора ключей openssl (sourceforge.net/p/gnuwin32 ) и запустите эти команды (rietta.com / blog / 2012/01/27 /), чтобы создать пару файлов public.pem и private.pem и передать эти файлы в функцию crypto.privateDecrypt (). - person Prabhat Mishra; 03.03.2019
comment
@Prabhat Mishra Я не спрашиваю, как генерировать ключи;) - person maroodb; 05.03.2019
comment
Пожалуйста, любой поможет, если вы хотите добиться использования криптовалюты. Я могу зашифровать с помощью crypto.publicEncrypt(key, buffer), но расшифровка вывода с помощью crypto.publicDecrypt(key, buffer) не работает. - person Abhishek Kumar; 04.09.2019
comment
@AbhishekKumar, просто глядя на ваш код, похоже, вы могли использовать один и тот же ключ для шифрования и дешифрования. Убедитесь, что вы выполняете шифрование с помощью publicKey и расшифровываете с помощью privateKey - person Jacob McKay; 05.09.2019
comment
Да @jacobmckay, ты прав. Я использую тот же открытый ключ - person Abhishek Kumar; 06.09.2019
comment
В вашем примере используется RSA, который эксперты по безопасности возражают против дальнейшего использования. - person Scott Arciszewski; 22.10.2019

Я тестировал это в Node.js 10, вы можете использовать функции шифрования / дешифрования (небольшие изменения в Ответ Джейкоба):

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)

Для ключей вы можете сгенерировать их с помощью

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)
}
person BrunoLM    schedule 06.12.2018
comment
Мне потребовалось несколько дней, но я наконец нашел объяснение, почему это не работает на русском языке, поэтому я подумал добавить, что здесь qaru.site/questions/16043509/ в нем говорится, что publicEncrypt использует openssl и только RSA, поэтому НЕТ, используя crypto.createECD secp384r1 вызовет ошибку unhandledRejection Ошибка: ошибка: 0906D06C: подпрограммы PEM: PEM_read_bio: нет стартовой строки в publicEncrypt какие-либо советы, как использовать эллиптические ключи с более высоким разрядом? также отметил, что Chrome не перейдет на 512 с EC. Это с nodejs 11.6 nodejs.org/api/crypto.html - person Master James; 18.01.2019
comment
Также при попытке передать в браузер что-то зашифрованное из узла, ключи должны быть сгенерированы в браузере, а открытый ключ импортируется в node. - person Master James; 28.01.2019
comment
спасибо за этот ответ, это научило меня использовать объект JSON для передачи ключевой фразы в функцию privateDecrypt. - person kaushalop; 28.07.2020

Обновленный общедоступный / частный модуль дешифрования и шифрования - это URSA. Модуль node-rsa устарел.

Этот модуль Node предоставляет довольно полный набор оболочек для крипто-функциональности открытого / закрытого ключа RSA OpenSSL.

npm install ursa
person Louie Miranda    schedule 09.07.2013
comment
Урса давно не обслуживается. Могут помочь эти новые реализации: github.com/tracker1/cryptico-js и github.com/rzcoder/node-rsa - person Andrew Eddie; 20.08.2014
comment
Спасибо за обновление, в 2020 году ответу исполнилось 7 лет. - person Louie Miranda; 18.09.2020

Используйте модуль node-rsa. Вот ссылка на файл test.js, демонстрирующий использование .

person Peter Lyons    schedule 06.01.2012
comment
Может быть, мне нужно поближе познакомиться с шифрованием RSA. Я десятки раз читал документацию по криптографии, пытаясь понять, как сделать то, что мне нужно, но ничего не нашел. Вы говорите, что createCipheriv () будет делать то, что мне нужно, но я даже не знаю, что такое iv. Я предполагаю, что это потому, что он более абстрактен в PHP и других языках. Я поиграю с этой функцией и посмотрю, смогу ли я заставить ее работать. - person Clint; 06.01.2012
comment
Прочитав больше о createCipheriv, похоже, что это не асимметричное шифрование (шифрование с открытым / закрытым ключом). Я не думаю, что это удовлетворит мои потребности. У Crypto есть возможность подписать зашифрованную строку закрытым ключом, что заставляет меня задаться вопросом, почему я не могу зашифровать с помощью открытого ключа. Кажется странным, иначе я чего-то совсем упускаю. - person Clint; 06.01.2012
comment
Я не видел, чтобы вы отредактировали свой ответ. Похоже, это действительно может сработать! Я протестирую и посмотрю. - person Clint; 11.01.2012
comment
Пожалуйста, проверьте новый ответ ниже. - person Louie Miranda; 09.07.2013

TL; DR: URSA - ваш лучший выбор. Действительно забавно, что это не входит в стандартную комплектацию crypto Node.js.

Все остальные найденные мной решения либо не работают в Windows, либо на самом деле не являются библиотеками шифрования. URSA, рекомендовано Луи, похоже, лучший вариант. Если вам наплевать на Windows, вы станете еще более счастливым.

Примечание по Ursa: мне пришлось установить OpenSSL вместе с чем-то, что называется Visual C ++ 2008 Redistributables, чтобы установка npm работала. Получите этот мусор здесь: http://slproweb.com/products/Win32OpenSSL.html

Разбивка:

Не библиотеки шифрования

Это буквально все, что я смог найти.

person B T    schedule 10.07.2013
comment
node-rsa больше не полагается на node-waf. Он совместим с браузером. - person 131; 03.09.2015

Это изначально не поддерживается Node.js версии v0.11.13 или ниже, но похоже, что следующая версия Node.js (также известная как v0.12) будет поддерживать это.

Вот подсказка: https://github.com/joyent/node/blob/v0.12/lib/crypto.js#L358

См. crypto.publicEncrypt и crypto.privateDecrypt

Вот будущая документация для этого /github.com/joyent/node/blob/7c0419730b237dbfa0ec4e6fb33a99ff01825a8f/doc/api/crypto.markdown#cryptopublicencryptpublic_key-buffer

person Etienne    schedule 17.09.2014
comment
Время для обновления (без Update :, Edit: и т. Д.)? - person Peter Mortensen; 03.09.2020