2017-08-16 114 views
2

我想重复使用JavaScript的PHP字符串加密。这里是PHP代码:在JavaScript中重复PHP openssl_encrypt

<?php 

$iv = "123456789"; 
$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("123456789"); 
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

'MTcyLDIsNjAsMTU5LDcxLDEwLDE4Myw4LDE ...'解码为'172,2,60,159,71,10,183,8,1 ...'。它看起来像'base64.Base64.encode()'编码'encryptedBytes'的*字符串表示*。 如果你尝试'console.log(encryptedBytes.toString('base64'));'? – dsprenkels

+0

只是一个想法:在PHP中,您明确使用了一个256位密钥。使用aesjs时,密钥长度似乎取决于密钥变量的字节数/位数 - 在您的情况下,它是16 * 8 = 128位而不是256位。 – gus27

回答

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代码是未打包的。要解决这个问题,你应该为JavaScript文本使用PKCS#7填充。为此,您可以使用pkcs7模块。另一种选择是在计数器(CTR)模式下使用AES而不是CBC模式,如果这是您的选择。

这是PHP代码,我到底有:

<?php 
$iv = "123456789"; 
$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("123456789"); 
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我个人比较喜欢使用CTR模式,因为PKCS# 7个实现有时会暴露padding oracles,这会破坏加密。 (我检查了提到的pkcs#7库应该是好的,但是please don't try to implement this yourself。)