我正在尝试使用JavaScript复制PHP字符串加密。这是PHP代码:
<?php
$iv = "1234567890123456";
$key = "aaaaaaaaaaaaaaaa";
$input = "texttexttexttext";
$encrypted = openssl_encrypt($input, "AES-256-CBC", $key, 0, $iv);
echo $encrypted;
// "ZwY1i+vqP3acszeDiscCTx/R4a6d2AtkcInmN9OTCNE="
然而,当我尝试在JavaScript中复制它时,它会提供不同的密文:
var aesjs = require("aes-js");
var base64 = require("js-base64");
var iv = aesjs.utils.utf8.toBytes("1234567890123456");
var key = aesjs.utils.utf8.toBytes("aaaaaaaaaaaaaaaa");
var text = aesjs.utils.utf8.toBytes("texttexttexttext");
var aesCbc = new aesjs.ModeOfOperation.cbc(key, iv);
var encryptedBytes = aesCbc.encrypt(text);
var b64encoded = base64.Base64.encode(encryptedBytes);
console.log(b64encoded);
// "MTcyLDIsNjAsMTU5LDcxLDEwLDE4Myw4LDE…wyMTIsMjIyLDk3LDEyNCw1MywxNzIsMjIy"
我不知道如何让它给出相同的输出。有什么想法吗?
答案 0 :(得分:5)
有些事情出错:
首先,JavaScript代码的输出实际上是字符串172,2,60,159,71,10,183,8,1,…
的base64编码,而不是原始字节缓冲区的编码。我不知道如何解决这个问题,但通过使用aes.js
十六进制编码实用程序函数,我们可以将其转换为base64:
var hex = aesjs.utils.hex.fromBytes(encryptedBytes);
var buf = Buffer.from(hex, 'hex');
console.log(buf.toString('base64'));
// rAI8n0cKtwiu1N5hfDWs3g==
第二个问题是aes.js
中您使用AES128加密(aaaaaaaaaaaaaaaa
长度为128位),但您在PHP代码中使用AES256加密。我们应该更新PHP代码(或JS代码):
$encrypted = openssl_encrypt($input, "AES-128-CBC", $key, 0, $iv);
echo $encrypted;
// rAI8n0cKtwiu1N5hfDWs3rPbz0UmvlbW+LJliYox03c=
我们几乎具有相同的输出。但是等等,PHP输出是两倍长。发生了什么事?
嗯,OpenSSL uses PKCS#7 padding。但是,Javascript代码是未填充的。要解决此问题,您应该使用PKCS#7填充作为javascript文本。为此,您只需使用pkcs7模块即可。另一种选择是在计数器(CTR)模式下使用AES而不是CBC模式,如果这是您的选择。
这是我最终的PHP代码:
<?php
$iv = "1234567890123456";
$key = "aaaaaaaaaaaaaaaa";
$input = "texttexttexttext";
$encrypted = openssl_encrypt($input, "AES-128-CBC", $key, 0, $iv);
echo $encrypted;
// output: 'rAI8n0cKtwiu1N5hfDWs3rPbz0UmvlbW+LJliYox03c='
这是JavaScript代码:
var aesjs = require("aes-js");
var base64 = require("js-base64");
var pkcs7 = require("pkcs7");
var iv = aesjs.utils.utf8.toBytes("1234567890123456");
var key = aesjs.utils.utf8.toBytes("aaaaaaaaaaaaaaaa");
var text = aesjs.utils.utf8.toBytes("texttexttexttext");
var aesCbc = new aesjs.ModeOfOperation.cbc(key, iv);
var encryptedBytes = aesCbc.encrypt(pkcs7.pad(text));
var hex = aesjs.utils.hex.fromBytes(encryptedBytes);
var buf = Buffer.from(hex, 'hex');
console.log(buf.toString('base64'));
// output: 'rAI8n0cKtwiu1N5hfDWs3rPbz0UmvlbW+LJliYox03c='
PS 我个人更喜欢使用点击率模式,因为PKCS#7实施有时会暴露padding oracles,从而破坏加密。 (我检查了提到的pkcs#7库,这应该是好的,但是please don't try to implement this yourself。)