簡體   English   中英

AES 加密 PHP 到 NodeJS?

[英]AES Encryption PHP to 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.log(data);

NodeJS 版本有一些問題,因為它沒有給我輸出,而是拋出一個錯誤。

提供“加密”必須解密為非空字符串。

你能弄清楚問題嗎?

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也支持)來創建密鑰。

使用 AES-256-GCM 的 PHP 加密,使用 SHA256 的 PBKDF2:

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

使用 AES-256-GCM 的 JS 加密,使用 SHA256 的 PBKDF2:

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

這些函數產生兼容的結果,所以在 PHP 中用encrypt創建的密文可以在 JS 中用decrypt來解密,反之亦然。 當然,這只是一個基本的例子,生產代碼會有更多的特性、異常處理以及可能的密碼和 KDF 設置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM