javascript - 使用加密模块将 PHP AES 加密到 NodeJS

标签 javascript php node.js encryption node-crypto

我的任务是遵循给定的和有效的 PHP 加密到 node.js 中。使用任何 Node 模块包。我不需要进行解密,因为它已经存在于他们的 API 中,我只需要将加密值传递给他们的 API 进行解密,这是在 PHP 中。我尝试使用 node-crypto 和单独的 md5 模块。这是伪代码:

  • 数据加密算法
    1. 创建一个 16 字节的随机盐和散列。每次调用时都会新创建盐 API。
    2. 散列提供的加密 key 。
    3. 使用“AES-128-CBC”加密并使用散列盐值作为向量和散列 加密 key 。
    4. 前缀盐并附加加密数据。
    5. 进行Base64编码。
    6. JSON 编码并发布请求

我想我几乎完成了几个步骤来获得成功的响应这里是我当前的 node.js 代码

Node :

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

出于测试目的,这里是用于解密的 API 中的 PHP 代码:

$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

最佳答案

这是一个非常有趣的问题。我认为主要问题是在 Node.js 中连接盐和加密数据的方法。

我发现以下代码运行良好,它为我们提供了与 PHP 代码相同的结果。

请注意,我在这里使用固定盐(从固定 base64 字符串解码),因为这为我们提供了确定性输出。您可能应该在生产中切换到使用 crypto.randomBytes。

此外,PHP 在 json 输出中将“/”编码为“\/”,参见 json_encode .这当然可以在 PHP 中配置(使用 json_encode 中的 JSON_UNESCAPED_SLASHES 标志),但我怀疑在您的情况下无法更改。这就是为什么我将 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));

关于javascript - 使用加密模块将 PHP AES 加密到 NodeJS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57477574/

相关文章:

node.js - 带有 Node.js 的 Typescript baseUrl

javascript - ExpressJS + 智威汤逊。获取授权数据的正确方法是什么?

javascript - 使用 AWS SDK for JavaScript v3 完成分段上传到 S3 时出现 XML 错误

php - 无法导入wordpress数据库出现错误

php - 为什么这个正则表达式在 PHP 中不起作用?

javascript - 检测移动震动加速度计5秒钟,然后发出警报消息

javascript - 使用剧作家导航后元素不可见

javascript - 使用子字符串更改数组元素值

javascript - 长值发生正则表达式停止脚本错误

javascript - 错误 : getaddrinfo EAI_AGAIN api. spotify.com:443