为什么Node.js中的散列给出了相同字符的不同结果?

时间:2018-02-21 05:03:28

标签: javascript node.js

所以我尝试使用此函数在节点js中散列¤字符 crypto.createHash('md5').update('¤', 'ascii').digest('hex') 给md5哈希

  

f37c6f3896b2c85fbbd01ae32e47b43f

并使用Buffer

crypto.createHash('md5').update(new Buffer('¤', 'ascii').toString()).digest('hex')

给出这样的结果:

  

9b759040321a408a5c7768b4511287a6

我尝试调试Hash.update()以查看内部但我似乎无法编译。

为什么crypto编码方法与Buffer不同?是什么让它与众不同?

1 个答案:

答案 0 :(得分:3)

crypto的编码方式与缓冲区的编码方式相同,所以让我们暂时忽略它。这是问题的简化:

const text = '¤';
const b1 = Buffer.from(text, 'ascii');
const b2 = Buffer.from(b1.toString());

b1和b2不是相同的字节。 b1是[0xa4],由于0xa4不是ASCII的一部分,所以没有多大意义; Node is using the same code to encode strings as ASCII and Latin-1 here。我不知道这是出于兼容性或性能原因还是什么,但似乎是一个坏主意,导致Buffer.from(s, 'ascii')Buffer.from(Buffer.from(s, 'ascii').toString('ascii'), 'ascii')不同的值,并且似乎没有记录在任何地方

在现代版本的Node中,默认编码为UTF-8,因此b1.toString()将尝试将0xa4解释为UTF-8,失败并生成替换字符( ),编码如[0xef,0xbf,0xbd]。在Node的非现代版本中,它将执行依赖于环境的错误而不是一致的错误。

您可以通过传递缓冲区而不是缓冲区的UTF-8编码来使您的操作得到相同的结果:

crypto.createHash('md5').update(new Buffer('¤', 'ascii')).digest('hex')

(请注意.toString()如何删除)

但正确的代码,能够散列任何Unicode代码点序列,将改为使用UTF-8。

crypto.createHash('md5').update('¤', 'utf8').digest('hex')
crypto.createHash('md5').update(Buffer.from('¤', 'utf8')).digest('hex')