Шифрование PHP AES в NodeJS с использованием модуля шифрования

Моя задача — следовать заданному и работающему шифрованию PHP в node.js. используя любые пакеты модулей узлов. Мне не нужно делать расшифровку, потому что она уже существует в их API, и мне просто нужно передать зашифрованное значение в их API для расшифровки, которая находится в PHP. Я попытался использовать node-crypto и отдельный модуль md5. вот псевдокод:

  • Data Encryption Algorithm
    1. Create a 16-byte random salt and hash. The salt is newly created every time you call the API.
    2. Хэшируйте предоставленный ключ шифрования.
    3. Зашифруйте с помощью «AES-128-CBC» и используйте хешированное значение соли в качестве вектора и хешированного ключа шифрования.
    4. Префикс соли и добавьте зашифрованные данные.
    5. Сделайте кодировку Base64.
    6. Кодирование JSON и отправка запроса

Я думаю, что я почти сделал всего несколько шагов, чтобы получить успешный ответ, вот мой текущий код node.js

Узел:

const reqBody = {
    "username": "jCpVyf3VEt",
    "password": "eGD6TWKmnn",
    "account_no": "0030300155398",
    "tran_date": "08/06/2019 10:30:45",
    "reference_no": "12328ALHYGZC20",
    "area": "JENRA DAU"
};
const Serialize = require('php-serialize')
const md5 = require('md5');
//encrypt
const crypto = require('crypto'),
  algorithm = 'aes-128-cbc',
  key = 'IfZDGbVDHTxlJIkK',
  inputEncoding = 'utf8',
  outputEncoding = 'base64';

function encrypt(data, key) {
  let salt = crypto.randomBytes(16);
  let hKey = md5(key);
  let iv = md5(salt);
  let serialized = Serialize.serialize(data);
  let cipher = crypto.createCipheriv(algorithm, Buffer.from(hKey, 'hex'), Buffer.from(iv, 'hex'));
  let crypted = cipher.update(serialized, inputEncoding, outputEncoding);

  crypted += cipher.final(outputEncoding);

  let encrypted = salt.toString('base64') + crypted.toString();

  return encrypted;
}
encrypt(JSON.stringify(reqBody), key);

вот рабочий php-код:

$data = json_encode([
  'username' => "jCpVyf3VEt",
  'password' => "eGD6TWKmnn",
  'account_no' => "0030300155398",
  'tran_date' => "08/06/2019 10:30:45",
  'reference_no' => "12328ALHYGZC20",
  'area' => "JENRA DAU"]);

function encrypt( $data) {
  $key = md5("IfZDGbVDHTxlJIkK", true);
  $cipher = "aes-128-cbc";
  $salt = openssl_random_pseudo_bytes(16);
  $iv = md5( $salt, true);
  $encrypted_bin =  $salt . openssl_encrypt( serialize( $data ), $cipher, $key, true, $iv);
  $encrypted_str = base64_encode( $encrypted_bin);

  return $encrypted_str;

}

echo encrypt($data);

для целей тестирования вот код PHP из их API для расшифровки:

$data = 'LI5BJJw1PEhWellnjKEt3g9oaHs8uDDknBT2qDNI7Rfs644+IjobOaFxlrIrOvDm7dkASRsOTu4Yuxzi4I5q29QoE5huH6y4/XZXsResZjLPidv1ToTnhB2UKXH5rX/g/8Od7ljO6VLVAS7zx+94xeOgtpP/idkkpDi1fRNGvnOkl1c6fcyVhwl2Pv+ijKSK9+ou+54dfQrCng2uBzKC6RrHY3lvP7ktsSvtnkXFqksrpjfJ2gnMH6sMIMzru1+D';

function decrypt($encrypted) {
 $cipher = "aes-128-cbc";
 $key = md5("IfZDGbVDHTxlJIkK", true);
    $data = base64_decode($encrypted);
    $salt = substr($data, 0, 16);
    $iv = md5($salt, true);
    $decrypted_bin = openssl_decrypt(substr($data, 16, strlen($data)), $cipher, $key, true, $iv);

    if($decrypted_bin === false) {
    return json_encode([ -102 => "Authentication Failed"]);
    }

    return unserialize( $decrypted_bin);
}
echo decrypt($data);

Запуск кода шифрования PHP приводит к успешному ответу от расшифровки PHP. Но когда я запускаю шифрование Node.js, я могу получить зашифрованные данные, но когда я проверяю зашифрованные данные из моего Node.js и отправляю зашифрованное значение в код расшифровки PHP, результатом является ошибка аутентификации. кажется, я не могу перевести алгоритм шифрования PHP в Node.js


person Makopa    schedule 13.08.2019    source источник


Ответы (1)


Это очень интересно. Я думаю, что основная проблема заключается в методе объединения нашей соли и зашифрованных данных в Node.js.

Я обнаружил, что следующий код работает хорошо, он дает нам тот же результат, что и код PHP.

Обратите внимание, что здесь я использую фиксированную соль (декодирование из фиксированной строки base64), так как это дает нам детерминированный вывод. Вероятно, вам следует переключиться на использование crypto.randomBytes для этого в производстве.

Кроме того, PHP кодирует «/» как «\/» в выводе json, см. json_encode. Конечно, это можно настроить в PHP (используя флаг JSON_UNESCAPED_SLASHES в json_encode), но я подозреваю, что в вашем случае это нельзя изменить. Вот почему я заменяю «/» на «\/» в открытом тексте json.

const reqBody = {
    "username": "jCpVyf3VEt",
    "password": "eGD6TWKmnn",
    "account_no": "0030300155398",
    "tran_date": "08/06/2019 10:30:45",
    "reference_no": "12328ALHYGZC20",
    "area": "JENRA DAU"
};
const Serialize = require('php-serialize')
const md5 = require('md5');
//encrypt
const crypto = require('crypto'),
algorithm = 'aes-128-cbc',
key = 'IfZDGbVDHTxlJIkK',
inputEncoding = 'utf8',
outputEncoding = 'base64';

function encrypt(input, key, salt) {
    let serialized = Serialize.serialize(input);
    let iv = md5(salt);
    let hKey = md5(key);

    let cipher = crypto.createCipheriv(algorithm, Buffer.from(hKey, 'hex'), Buffer.from(iv, 'hex'));
    let crypted = cipher.update(serialized, inputEncoding);
    let encrypted = Buffer.concat([salt, crypted, cipher.final()]);
    return encrypted.toString(outputEncoding);
}

// We must escape forward slashes here, since this is how PHP will behave. 
let data = JSON.stringify(reqBody).replace(/\//ig, "\\/");

// We can use any random salt here, e.g. crypto.randomBytes For this example we'll use the same as the existing encrypted data. 
let salt = Buffer.from('LI5BJJw1PEhWellnjKEt3g==', 'base64');
console.log("Encrypted data: ", encrypt(data, key, salt));
person Terry Lennox    schedule 13.08.2019
comment
спасибо, Терри, теперь он работает даже со случайно сгенерированной солью 16 байт. Интересно, почему вам так легко разобраться в моей проблеме? работал для этого не менее 8 часов. методом проб и ошибок - person Makopa; 13.08.2019
comment
Это было непросто :-) это трудная задача. Я только что сравнил различные промежуточные этапы между PHP и Node.js, и я уже работал над подобными проблемами раньше! - person Terry Lennox; 13.08.2019
comment
хорошо! Теперь я могу спать очень хорошо и уверен, что смогу уложиться в сроки завтра! Спасибо Терри большое уважение! - person Makopa; 13.08.2019