Node.js `crypto.final` 使加密结果不同于 PHP `mcrypt_encrypt`
Node.js `crypto.final` make the encrypted result is different to PHP `mcrypt_encrypt`
起初,Node.js加密。
// Both of key and IV are hex-string, but I hide them in Whosebug.
var secretKey = new Buffer('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'), // 48 chars
iv = new Buffer('bbbbbbbbbbbbbbbb', 'hex'); // 16 chars
var str = 'This string will be encrypted.';
var cipher = crypto.createCipheriv('des-ede3-cbc', secretKey, iv),
cryptedStr = cipher.update(str, 'utf8', 'base64') + cipher.final('base64');
然后,PHP mcrypt.
$key = pack('H*', "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
$iv = pack('H*', "bbbbbbbbbbbbbbbb");
$string = 'This string will be encrypted.';
$text = mcrypt_encrypt(MCRYPT_3DES, $key, $string, MCRYPT_MODE_CBC, $iv);
$text_base64 = base64_encode($text);
问题。
在相同的字符串中,相同的算法和相同的编码。
还有一小部分不匹配就是cipher.final()
.
下面是真实的示例输出。
// Node.js output.
UKBI17EIHKNM2EU48ygsjil5r58Eo1csByAIFp9GhUw=
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Same part
// PHP output.
UKBI17EIHKNM2EU48ygsjil5r58Eo1csAY4C0JZoyco=
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Same part
为什么 cipher.final()
使结果不同?
在不修改 PHP 代码的情况下,如何在 Node.js 中得到相同的结果。
由于您无法更改 PHP 代码,因此您需要修改 node.js 代码。
问题是 node.js' 加密模块仅使用 PKCS#7 填充,而 PHP 仅使用零填充。但是,您可以在 node.js (setAutoPadding(false)
) 中禁用填充以实现您自己的零填充:
function zeroPad(buf, blocksize){
if (typeof buf === "string") {
buf = new Buffer(buf, "utf8");
}
var pad = new Buffer((blocksize - (buf.length % blocksize)) % blocksize);
pad.fill(0);
return Buffer.concat([buf, pad]);
}
并像这样使用它:
var secretKey = new Buffer('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'), // 48 chars
iv = new Buffer('bbbbbbbbbbbbbbbb', 'hex'); // 16 chars
var str = 'This string will be encrypted.';
var cipher = crypto.createCipheriv('des-ede3-cbc', secretKey, iv);
cipher.setAutoPadding(false);
var cryptedStr = cipher.update(zeroPad(str, 8), 'utf8', 'base64') + cipher.final('base64');
console.log(cryptedStr);
输出:
UKBI17EIHKNM2EU48ygsjil5r58Eo1csAY4C0JZoyco=
下面是一个匹配的 unpad 函数的实现:
function zeroUnpad(buf, blocksize){
var lastIndex = buf.length;
while(lastIndex >= 0 && lastIndex > buf.length - blocksize - 1) {
lastIndex--;
if (buf[lastIndex] != 0) {
break;
}
}
return buf.slice(0, lastIndex + 1).toString("utf8");
}
起初,Node.js加密。
// Both of key and IV are hex-string, but I hide them in Whosebug.
var secretKey = new Buffer('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'), // 48 chars
iv = new Buffer('bbbbbbbbbbbbbbbb', 'hex'); // 16 chars
var str = 'This string will be encrypted.';
var cipher = crypto.createCipheriv('des-ede3-cbc', secretKey, iv),
cryptedStr = cipher.update(str, 'utf8', 'base64') + cipher.final('base64');
然后,PHP mcrypt.
$key = pack('H*', "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
$iv = pack('H*', "bbbbbbbbbbbbbbbb");
$string = 'This string will be encrypted.';
$text = mcrypt_encrypt(MCRYPT_3DES, $key, $string, MCRYPT_MODE_CBC, $iv);
$text_base64 = base64_encode($text);
问题。
在相同的字符串中,相同的算法和相同的编码。
还有一小部分不匹配就是cipher.final()
.
下面是真实的示例输出。
// Node.js output.
UKBI17EIHKNM2EU48ygsjil5r58Eo1csByAIFp9GhUw=
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Same part
// PHP output.
UKBI17EIHKNM2EU48ygsjil5r58Eo1csAY4C0JZoyco=
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Same part
为什么 cipher.final()
使结果不同?
在不修改 PHP 代码的情况下,如何在 Node.js 中得到相同的结果。
由于您无法更改 PHP 代码,因此您需要修改 node.js 代码。
问题是 node.js' 加密模块仅使用 PKCS#7 填充,而 PHP 仅使用零填充。但是,您可以在 node.js (setAutoPadding(false)
) 中禁用填充以实现您自己的零填充:
function zeroPad(buf, blocksize){
if (typeof buf === "string") {
buf = new Buffer(buf, "utf8");
}
var pad = new Buffer((blocksize - (buf.length % blocksize)) % blocksize);
pad.fill(0);
return Buffer.concat([buf, pad]);
}
并像这样使用它:
var secretKey = new Buffer('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'), // 48 chars
iv = new Buffer('bbbbbbbbbbbbbbbb', 'hex'); // 16 chars
var str = 'This string will be encrypted.';
var cipher = crypto.createCipheriv('des-ede3-cbc', secretKey, iv);
cipher.setAutoPadding(false);
var cryptedStr = cipher.update(zeroPad(str, 8), 'utf8', 'base64') + cipher.final('base64');
console.log(cryptedStr);
输出:
UKBI17EIHKNM2EU48ygsjil5r58Eo1csAY4C0JZoyco=
下面是一个匹配的 unpad 函数的实现:
function zeroUnpad(buf, blocksize){
var lastIndex = buf.length;
while(lastIndex >= 0 && lastIndex > buf.length - blocksize - 1) {
lastIndex--;
if (buf[lastIndex] != 0) {
break;
}
}
return buf.slice(0, lastIndex + 1).toString("utf8");
}