在JavaScript中复制php openssl_encrypt

Enu*_*uff 2 javascript php encryption aes

我正在尝试使用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="
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试在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"
Run Code Online (Sandbox Code Playgroud)

我不知道如何让它给出相同的输出.有任何想法吗?

dsp*_*els 5

有些事情出错了:

首先,JavaScript代码的输出实际上是字符串的base64编码172,2,60,159,71,10,183,8,1,…,而不是原始字节缓冲区的编码.我不知道如何解决这个问题,但通过使用aes.js十六进制编码实用程序函数,我们可以将其转换为base64:

var hex = aesjs.utils.hex.fromBytes(encryptedBytes);
var buf = Buffer.from(hex, 'hex');

console.log(buf.toString('base64'));
// rAI8n0cKtwiu1N5hfDWs3g==
Run Code Online (Sandbox Code Playgroud)

第二问题是,在aes.js使用的是AES128加密(aaaaaaaaaaaaaaaa是128位长),但使用的是AES256加密在PHP代码.我们应该更新PHP代码(或JS代码):

$encrypted = openssl_encrypt($input, "AES-128-CBC", $key, 0, $iv);
echo $encrypted;
// rAI8n0cKtwiu1N5hfDWs3rPbz0UmvlbW+LJliYox03c=
Run Code Online (Sandbox Code Playgroud)

我们几乎有相同的输出.但是等等,PHP输出是两倍长.发生了什么?

好吧,OpenSSL 使用PKCS#7填充.但是,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='
Run Code Online (Sandbox Code Playgroud)

这是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='
Run Code Online (Sandbox Code Playgroud)

PS我个人更喜欢使用CTR模式,因为PKCS#7实现有时会暴露破坏加密的填充特征.(我检查了提到的pkcs#7库应该是好的,但请不要尝试自己实现.)