Шифрование AES PHP для NodeJS? - PullRequest
0 голосов
/ 09 сентября 2018

Я в процессе переноса небольшого проекта с 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.log(data);

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

При условии, что «зашифрованные» должны расшифровываться до непустой строки.

Можете ли вы выяснить проблему?

1 Ответ

0 голосов
/ 10 сентября 2018

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

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

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);
}

function decrypt($ciphertext, $passphrase) {
    $data = base64_decode($ciphertext);
    $ciphertext = substr($data, 16);
    $key = hash('SHA256', $passphrase, true);
    $iv = substr($data, 0, 16);
    $pt = openssl_decrypt($ciphertext, 'AES-256-CTR', $key, 1, $iv);
    return $pt;
}

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

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

PHP-шифрование с AES-256-GCM, PBKDF2 с SHA256:

function encrypt($plaintext, $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);
}

function decrypt($ciphertext, $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);
    $plaintext = openssl_decrypt($ciphertext, 'aes-256-gcm', $key, 1, $nonce, $tag);
    return $plaintext;
}

JS-шифрование с AES-256-GCM, PBKDF2 с SHA256:

var crypto = require('crypto');

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');
}

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, и наоборот.

...