【问题标题】:Node.js `crypto.final` make the encrypted result is different to PHP `mcrypt_encrypt`Node.js `crypto.final` 使加密结果与 PHP `mcrypt_encrypt` 不同
【发布时间】:2015-07-13 12:11:56
【问题描述】:

起初,Node.js 加密。

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

然后,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 中获得相同的结果

【问题讨论】:

  • node.js 示例报错:runnable.com/VUcebtM0NhY3v9v5/output
  • 我明白了,我不知道如何让它可见。无论如何,错误是:“buffer.js:348 ret = this.parent.hexWrite(string, this.offset + offset, length); TypeError: Invalid hex string”。
  • @GergoErdosi,你说得对。我修好了它。因为之前的文章我为 Buffer 写了奇怪的字符。
  • 你知道哪个输出是正确的吗?
  • 我不知道哪个是正确的。但我必须遵循 PHP 结果。我用Node.js连接别人的PHP系统。

标签: php node.js encryption mcrypt


【解决方案1】:

由于您无法更改 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");
}

【讨论】:

  • 我修好了一行。它现在可以工作了。非常感谢!
  • return Buffer.concat([buf, new Buffer(Array((blocksize - (buf.length % blocksize)) % blocksize).join('00'), 'hex')]);
  • 这一行 new Buffer(num) ,似乎得到了随机输出。所以我把它设为 ('00', 'hex')
  • 原来缓冲区需要被填充。不能保证它用零字节填充。我改变了一个更清晰的实现。出于某种原因,它在我第一次测试时就起作用了。我还添加了一个 unpad 功能
猜你喜欢
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 2011-12-28
  • 2014-02-01
  • 2019-02-22
  • 2015-07-12
相关资源
最近更新 更多