Node.js`crypto.final`使加密结果与PHP`mcrypt_encrypt`不同 [英] Node.js `crypto.final` make the encrypted result is different to PHP `mcrypt_encrypt`

查看:164
本文介绍了Node.js`crypto.final`使加密结果与PHP`mcrypt_encrypt`不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,Node.js加密



  // key和IV都是hex-string,但是我隐藏他们在Stackoverflow。 

var secretKey = new Buffer('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','hex'),// 48 chars
iv = new Buffer('bbbbbbbbbbbbbbbb','hex'); // 16 chars
var str ='此字符串将被加密'。
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 ='此字符串将被加密'。
$ text = mcrypt_encrypt(MCRYPT_3DES,$ key,$ string,MCRYPT_MODE_CBC,$ iv);
$ text_base64 = base64_encode($ text);



问题。



,相同的算法和相同的编码。



仍然有一点不匹配是 cipher.final()



以下是实例输出。

  // Node .js输出。 
UK b b b b b
$ b // PHP输出。
UK b b b b b b $ b

为什么 cipher.final()使结果不同?



如果在不修改PHP代码的条件下,如何在Node.js 中获得相同的结果。

解决方案

由于您不能更改PHP代码,您需要修改node.js代码。



问题是node.js的crypto模块只使用PKCS#7填充,而PHP只使用零填充。然而,您可以在node.js中禁用填充( setAutoPadding(false) )来实现自己的零填充:

 函数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 ='此字符串将被加密'。
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);

输出:

 code> 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);
}


At first, Node.js crypto.

// Both of key and IV are hex-string, but I hide them in Stackoverflow.

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');

Then, 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);

Problem.

In the same string, same algorithm and same encoding.

Still there is a little part not match that is cipher.final().

Below is the real sample output.

// Node.js output.
UKBI17EIHKNM2EU48ygsjil5r58Eo1csByAIFp9GhUw=
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Same part

// PHP output.
UKBI17EIHKNM2EU48ygsjil5r58Eo1csAY4C0JZoyco=
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Same part

Why cipher.final() make results different?

How could make the same results in Node.js on condition that don't modify PHP code.

解决方案

Since you can't change your PHP code, you will need to modify the node.js code.

The problem is that node.js' crypto module uses only PKCS#7 padding, whereas PHP uses only zero padding. You can however disable padding in node.js (setAutoPadding(false)) to implement your own zero padding:

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]);
}

And use it like this:

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);

Output:

UKBI17EIHKNM2EU48ygsjil5r58Eo1csAY4C0JZoyco=

Here is an implementation of a matching unpad function:

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`crypto.final`使加密结果与PHP`mcrypt_encrypt`不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆