RSA шифрование по Modulus и Exp с node-rsa

324
25 июля 2022, 19:40

Делаю авторизацию на сайте, пароль шифруется публичным RSA mod+e.

Ключ HEX:

d3bcef1f00424f3261c89323fa8cdfa12bbac400d9fe8bb627e8d27a44bd5d59dce559135d678a8143beb5b8d7056c4e1f89c4e1f152470625b7b41944a97f02da6f605a49a93ec6eb9cbaf2e7ac2b26a354ce69eb265953d2c29e395d6d8c1cdb688978551aa0f7521f290035fad381178da0bea8f9e6adce39020f513133fb

Exp HEX: 10001 или же DEC 65537

При шифровании на сайте онлайн - все работает и зашифированный текст валиден

Но, как только я пробую сделать тоже самое на node-rsa - итоговый шифр неверный.

const NodeRSA = require('node-rsa');
let key = new NodeRSA();
key = key.importKey({
    n: Buffer.from('d3bcef1f00424f3261c89323fa8cdfa12bbac400d9fe8bb627e8d27a44bd5d59dce559135d678a8143beb5b8d7056c4e1f89c4e1f152470625b7b41944a97f02da6f605a49a93ec6eb9cbaf2e7ac2b26a354ce69eb265953d2c29e395d6d8c1cdb688978551aa0f7521f290035fad381178da0bea8f9e6adce39020f513133fb', 'hex'),
    e: 65537
}, 'components-public');
const encrypted = key.encrypt('qwerty', 'hex');
console.log(encrypted);
Answer 1

Обновление ответа Быстрый ответ: в node-rsa нужно установить режим шифрования 'pkcs1'

key.setOptions({encryptionScheme: 'pkcs1'})
const encrypted = key.encrypt('qwerty', 'hex');

Развернутый ответ.

В RSA есть несколько способов дополнить открытый текст до полного блока (padding). Причина, по которой текст, зашифрованный в node-rsa, не проходил в веб-сайте, заключается в различных схемах паддинга. В node-rsa по-умолчанию используется схема pkcs1-oaep, а в библиотеке crypts/rsa, используемой на сайте, - схема pkcs1-pad2.

В node-rsa такая схема тоже поддерживается, называется 'pkcs1'. Устанавливается вызовом функции key.setOptions({encryptionScheme: 'pkcs1'}).

С сайтом я тоже разобрался. "Открытым ключом" они называют n, "закрытым ключом" - d, а экспонента e у них фиксирована 65537.

Для проверки я сгенерировал на сайте пару n и d, в node-rsa строку qwerty, а на сайте благополучно расшифровал.

const NodeRSA = require('node-rsa');
let key = new NodeRSA();
n = Buffer.from("817d1e54c65d819ab659285c14742a7aa3ea0e94e37dc73594ce52fdb2d932281583dd3309e45498ec86a82de9a43d76998cc20c588073d664e464ddf37314a3", "hex");
d = Buffer.from("24b7ee19ec0627f24f330916d355fd95b9556dbd1aa55810019a603e40b1065f9dbc447d3a363dca4f2c1c87c1f204429088aaa5865c9f7de89bf0e114a228c1", "hex")
e = 65537
key = key.importKey({n: n, e: e}, "components-public")
key.setOptions({encryptionScheme: 'pkcs1'})
const encrypted = key.encrypt('qwerty', 'hex');
console.log(encrypted.toString("hex"))

Результат шифрования

1ed253c66f41658fb37c3f2386ed9507079d063816c4297a10af89d7e77cb5d525a72678b55e0d75cb6dfaec88bcd6179171d6bb8f6b3f41975d98138bdf8d3c

Проверка на сайте:

Исходный ответ

Если коротко, то ваш метод проверки шифрования неверен.

Если же более развёрнуто, то в вашем вопросе я вижу несколько странных вещей.

Можно ли сравнивать два шифртекста?

node-rsa реализует схему шифрования pkcs1_oaep, которая определена в RFC 3447. Этой схеме сообщение перед шифрованием дополняется случайным паддингом. Поэтому каждый каждый раз, когда вы шифруете одну и ту же строку одним и тем же ключом, вы будете получать разные результаты. То есть невозможно проверить правильность шифрования, сравнивая с шифртекстом, полученном где-то в другом месте.

Правильность шифрования проверяется не сравнением с эталоном, а правильностью расшифрования. То есть вам нужно зашифровать в своей программе публичным ключом, а потом расшифровать где-то в другом месте приватным ключом. Если результат расшифрования совпадёт с результатом шифрования, то всё пучком.

Но! Не имея приватный ключ, вы не сможете проверить правильность вашего шифрования.

Формат ключа на выбранном вами сайте

Само понятие "RSA ключ в формате hex" неоднозначно. Повсеместно для представления ключа используются несколько разных форматов: PKCS1, PKCS8, OpenSSH. Какой из этих форматов ожидает тот сайт, который вы показали?

На указанном вами сайте я нажал кнопку "генерировать" и получил пару публичный ключ - приватный ключ. Публичный ключ начинался с байтов "8f25". Но такие байты в начале не соответствуют ни форматам PKCS1/8-DER, ни OpenSSH. Ключи PKCS в кодировке DER должны начинаться с 0x30, а ключ OpenSSH в бинарном представлении начинается с байтов 00 00 00 07.

Странный сайт, одним словом.

То, как вы им пользуетесь, добавляет странности. Вы вводите n в поле "Открытый ключ", а экспоненту в поле "Длина ключа". Но это неверно! Открытый ключ сам должен содержать и n и экспоненту. И длина ключа не должна использоваться - длину ключа (количество битов в числе n) программа должна сама извлекать из правильно закодированного публичного ключа.

READ ALSO
Не подключается jQuery к сайту

Не подключается jQuery к сайту

Пытаюсь подключить jQuery к html сайтуПодключаю google CDN

306
Подождать выполнение запроса sqlite на node.js

Подождать выполнение запроса sqlite на node.js

Хочу чтобы результатом выполнения функции был массив массивов с объектами, которые получены из БД

327
Запуск jar архива двойным щелчком JDK 14, WIN 10

Запуск jar архива двойным щелчком JDK 14, WIN 10

Я только начал изучать создание исполняемого jar архива из командной строкиС помощью команды jar создал файл app

323
NullPointerException при вызове OnClick из Фрагмента

NullPointerException при вызове OnClick из Фрагмента

При нажатии на кнопку, определенную во фрагменте выкидывает NullPointerExceptionСам фрагмент:

339