AES Encryption PHP to NodeJS?

*爱你&永不变心* 提交于 2019-12-24 10:23:01

问题


I am in process of moving a small project from PHP to NodeJS that includes a small part of AES Encryption.

As PHP code works fine, it goes as

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

The NodeJS Conversion of the same goes as follows

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

There is Some thing wrong with NodeJS version as it fails to give me the output, rather throws an error.

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

Can you figure out the issue?


回答1:


The NodeJS aes256 module doesn't support your PHP encryption algorithm. It uses AES-256-CTR for encryption, and SHA256 as a key derivation function. The IV is generated randomly, and prepended to the ciphertext.

If you want to use this module, you should be able to encrypt - decrypt your data in PHP using the functions below.

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

The aes256 module is using crypto internally. crypto is a built-in module and it supports AES-256-ECB, so you could still port your PHP code to JS, but I wouldn't recommend that. AES-256-ECB is a very weak encryption algorithm, and it doesn't provide authentication.

Both PHP7 and crypto support authenticated encryption algorithms, so you could use GCM for example. Also it's best to use PBKDF2 (which is also supported by PHP and crypto) for creating the key.

PHP encryption with AES-256-GCM, PBKDF2 with 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 encryption with AES-256-GCM, PBKDF2 with 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');
}

Those functions produce compatible results, so ciphertext that is created with encrypt in PHP can be decrypted with decrypt in JS, and vice versa.



来源:https://stackoverflow.com/questions/52243344/aes-encryption-php-to-nodejs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!