问题
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