javascript - 使用加密模块将 PHP AES 加密到 NodeJS 中
问题描述
我的任务是在 node.js 中遵循给定且有效的 PHP 加密。使用任何节点模块包。我不需要进行解密,因为它已经存在于他们的 API 中,我只需要将加密的值传递给他们的 API 以在 PHP 中进行解密。我尝试使用 node-crypto 和单独的 md5 模块。这是伪代码:
- 数据加密算法
- 创建一个 16 字节的随机盐和哈希。每次调用 API 时都会新创建盐。
- 散列提供的加密密钥。
- 使用 'AES-128-CBC' 加密,并使用散列盐值作为向量和散列加密密钥。
- 前缀 salt 并附加加密数据。
- 做 Base64 编码。
- JSON 编码和发布请求
我想我几乎完成了几个步骤来获得成功的响应这里是我当前的 node.js 代码
节点:
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));
推荐阅读
- nix - NixOS 服务 systemd 单元的 $PATH 不包含预期的依赖项
- javascript - 当我返回选项卡时,为什么 useQuery 使我的组件重新呈现?
- after-effects - 如何在 adobe 中循环修剪路径?
- php - Laravel Eloquent - 延迟加载因选择约束而失败
- android - 从 figma 为任何图标添加完整的活动阴影
- docker - Harbor:如何将图像直接加载到远程注册表?
- abap - 对 BAPI_GOODSMVT_CREATE 和滚动区域的序列化调用
- php - 如何“创建一个以根路径中的 $cfg['install_key'] 变量命名的文件;”
- pyspark - 使用 pyspark 执行存储在数据框中的 SQL
- lua - 如何从 LUA 表中选择多个随机元素?