Шифрование AES PHP для NodeJS?

Я в процессе переноса небольшого проекта с PHP на NodeJS, который включает небольшую часть шифрования AES.

Поскольку код PHP работает нормально, он выглядит как

  function decysek($data, $app_key) {
    $output = openssl_decrypt(base64_decode($data), 'AES-256-ECB', $app_key, OPENSSL_RAW_DATA);
    return $output;
  }

  function decyGetBillData($rek , $data , $decrypted_sek){
    $decrypted_rek =  openssl_decrypt(base64_decode($rek), 'AES-256-ECB', $decrypted_sek, OPENSSL_RAW_DATA);

    $decrypted_data =  openssl_decrypt(base64_decode($data), 'AES-256-ECB', $decrypted_rek, OPENSSL_RAW_DATA);
    return $decrypted_data;
  }

  $sekdec = decysek($request['sek'], $request['appKey']);
  $data = decyGetBillData($response['rek'], $response['data'], $sekdec);

  echo json_decode($data, true);

Преобразование того же NodeJS происходит следующим образом

var aes256 = require("aes256");
var js_base64_1 = require("js-base64");

function decysek(data, app_key) {
    var cipher = aes256.createCipher(app_key);
    var output = cipher.decrypt(js_base64_1.Base64.decode(data));
    return output;
}
function decyGetBillData(rek, data, decrypted_sek) {
    var cipher = aes256.createCipher(decrypted_sek);
    var decrypted_rek = cipher.decrypt(js_base64_1.Base64.decode(rek));
    var cipher2 = aes256.createCipher(decrypted_rek);
    var decrypted_data = cipher2.decrypt(js_base64_1.Base64.decode(data));
    return decrypted_data;
}
var sekdec = decysek(request["sek"], request["appKey"]);
var data = decyGetBillData(response["rek"], response["data"], sekdec);
console.info(data);

Что-то не так с версией NodeJS, поскольку она не дает мне вывода, скорее выдает ошибку.

Provided "encrypted" must decrypt to a non-empty string.

Вы можете разобраться в проблеме?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
1 104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Модуль Node.js aes256 не поддерживает ваш алгоритм шифрования PHP, AES-256-ECB. Он использует AES-256-CTR для шифрования и SHA256 в качестве функции получения ключа. IV генерируется случайным образом и добавляется к зашифрованному тексту.

Если вы хотите использовать этот модуль, у вас должна быть возможность зашифровать - расшифровать свои данные на PHP, используя функции, указанные ниже.

/**
 * Encrypts data with the supplied passphrase, using AES-256-CTR.
 * 
 * @param string $plaintext the plaintext data.
 * @param string $passphrase a passphrase/password.
 * @return string|false encrypted data: iv + ciphertext or `false` on error.
 */
function encrypt($plaintext, $passphrase) {
    $key = hash('SHA256', $passphrase, true);
    $iv = openssl_random_pseudo_bytes(16);
    $ct = openssl_encrypt($plaintext, 'AES-256-CTR', $key, 1, $iv);

    return base64_encode($iv.$ct);
}

/**
 * Decrypts data with the supplied passphrase, using AES-256-CTR.
 * 
 * @param string $ciphertext encrypted data.
 * @param string $passphrase a passphrase/password.
 * @return string|false plaintext data or `false` on error.
 */
function decrypt($ciphertext, $passphrase) {
    $data = base64_decode($ciphertext);
    $ciphertext = substr($data, 16);
    $key = hash('SHA256', $passphrase, true);
    $iv = substr($data, 0, 16);

    return openssl_decrypt($ciphertext, 'AES-256-CTR', $key, 1, $iv);
}

Модуль aes256 использует внутри crypto, который является встроенным модулем и поддерживает AES-256-ECB. Таким образом, вы все равно можете перенести свой PHP-код на JS, но я бы не рекомендовал этого. AES-256-ECB - очень слабый алгоритм шифрования, не обеспечивающий аутентификации.


И PHP7, и crypto поддерживают алгоритмы аутентифицированного шифрования, поэтому вы можете, например, использовать GCM. Также для создания ключа лучше всего использовать KDF, например PBKDF2 (который также поддерживается PHP и crypto).

Шифрование PHP с помощью AES-256-GCM, PBKDF2 с SHA256:

/**
 * Encrypts data with the supplied passphrase, using AES-256-GCM and PBKDF2-SHA256.
 * 
 * @param string $plaintext the plaintext data.
 * @param string $passphrase a passphrase/password.
 * @return string|false encrypted data: salt + nonce + ciphertext + tag or `false` on error.
 */
function encrypt(string $plaintext, string $passphrase) {
    $salt = openssl_random_pseudo_bytes(16);
    $nonce = openssl_random_pseudo_bytes(12);
    $key = hash_pbkdf2("sha256", $passphrase, $salt, 40000, 32, true);
    $ciphertext = openssl_encrypt($plaintext, 'aes-256-gcm', $key, 1, $nonce, $tag);

    return base64_encode($salt.$nonce.$ciphertext.$tag);
}

/**
 * Decrypts data with the supplied passphrase, using AES-256-GCM and PBKDF2-SHA256.
 * 
 * @param string $ciphertext encrypted data.
 * @param string $passphrase a passphrase/password.
 * @return string|false plaintext data or `false` on error.
 */
function decrypt(string $ciphertext, string $passphrase) {
    $input = base64_decode($ciphertext);
    $salt = substr($input, 0, 16);
    $nonce = substr($input, 16, 12);
    $ciphertext = substr($input, 28, -16);
    $tag = substr($input, -16);
    $key = hash_pbkdf2("sha256", $passphrase, $salt, 40000, 32, true);

    return openssl_decrypt($ciphertext, 'aes-256-gcm', $key, 1, $nonce, $tag);
}

JS-шифрование с использованием AES-256-GCM, PBKDF2 с SHA256:

const crypto = require('crypto');

/**
 * Encrypts data with the supplied passphrase, using AES-256-GCM and PBKDF2-SHA256.
 * 
 * @param {String} $plaintext the plaintext data.
 * @param {String} $passphrase a passphrase/password.
 * @return {String} encrypted data: salt + nonce + ciphertext + tag.
 */
function encrypt(plaintext, passphrase) {
    var salt = crypto.randomBytes(16);
    var nonce = crypto.randomBytes(12);
    var key = crypto.pbkdf2Sync(passphrase, salt, 40000, 32, 'sha256');

    var cipher = crypto.createCipheriv('aes-256-gcm', key, nonce);
    var ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
    var output = Buffer.concat([salt, nonce, ciphertext, cipher.getAuthTag()]);

    return output.toString('base64');
}

/**
 * Decrypts data with the supplied passphrase, using AES-256-GCM and PBKDF2-SHA256.
 * 
 * @param {String} $ciphertext encrypted data.
 * @param {String} $passphrase a passphrase/password.
 * @return {String} plaintext data.
 */
function decrypt(ciphertext, passphrase) {
    var input = new Buffer(ciphertext, 'base64');
    var salt = input.slice(0, 16);
    var nonce = input.slice(16, 28);
    ciphertext = input.slice(28, -16);
    var tag = input.slice(-16);
    var key = crypto.pbkdf2Sync(passphrase, salt, 40000, 32, 'sha256');

    var cipher = crypto.createDecipheriv('aes-256-gcm', key, nonce);
    cipher.setAuthTag(tag);
    var plaintext = Buffer.concat([cipher.update(ciphertext), cipher.final()]);

    return plaintext.toString('utf-8');
}

Эти функции дают совместимые результаты, поэтому зашифрованный текст, созданный с помощью encrypt в PHP, можно расшифровать с помощью decrypt в JS и наоборот. Конечно, это всего лишь базовый пример, производственный код будет иметь больше функций, обработку исключений и, возможно, настройки для шифра и KDF.

Вы можете сказать, что это за кодовая фраза?

Tushar Kale 06.01.2021 21:48

@TusharKale passphrase - это просто строка, пароль. Я добавил несколько комментариев, чтобы было понятнее.

t.m.adam 07.01.2021 00:42

наоборот шифрование не работает. Бывший. encrypt in node js, но этот cipertext не работает для дешифрования в PHP .. На той же платформе работает. @ t.m.adam

Kishan Patel 01.07.2021 10:42

@KishanPatel Вы используете тот же пароль и зашифрованный текст? Потому что у меня нет этой проблемы в ответах, которые я создал - Js, replit.com/@tasos_py/MutedHotpinkClasses#index.js и PHP, replit.com/@tasos_py/PassionateCheapTag#main.php (не стесняйтесь использовать их для тестов, BTW).

t.m.adam 02.07.2021 02:13

Спасибо @ t.m.adam. Это была опечатка в парольной фразе PHP. Еще раз спасибо за демо ..: +1

Kishan Patel 02.07.2021 05:36

Другие вопросы по теме