Nodejs crypto md5 hash给出了大小为24字节的摘要,而不是预期的16字节

时间:2016-08-31 22:41:34

标签: node.js encryption hash cryptography md5

var crypto = require('crypto');
var key1 = crypto.createHash('md5').update('abcdefgh').digest();
var key2 = crypto.createHash('md5').update('abcdefgh').digest('base64');
var key3 = crypto.createHash('md5').update('abcdefgh').digest('hex');
var key4 = crypto.createHash('md5').update('abcdefgh').digest('latin1');
console.log('Key sizes :', key1.toString().length, key2.toString().length, key3.toString().length, key4.toString().length ); 
//Key sizes : 16 24 32 16

不是md5应该总是返回16字节的摘要吗?

2 个答案:

答案 0 :(得分:2)

<强> hash.digest(encoding) docs

  

计算要散列的所有数据的摘要(使用hash.update()方法)。编码可以是'hex''latin1''base64'。如果提供编码,则返回一个字符串;否则返回缓冲区。

'binary'不是digest的可识别编码类型。默认情况下,使用类型为'buffer'的编码。

相反,请使用'hex''base64'

var key1 = crypto.createHash('md5').update('abcdefgh').digest('hex');

key1.length
// => 16

key1.toString()
// => 'e8dc4081b13434b45189a720b77b6818'

注意输出是32个字符,其中每个2个字符代表十六进制格式的单个字节。

所以哈希大小实际上是(32/2 = 16) 16字节

  

binary输出是自解释的,没有编码

不,这不是不言自明的。这是一个未记录的参数值。但是,请注意encoding可选参数。

如果在调用digest时不使用参数,则仍会得到16字节的结果

var key1 = crypto.createHash('md5').update('abcdefgh').digest()

key1.length
// => 16

key1.toString()
// => '��@��44�Q�� �{h\u0018'

key1.toString().length
// => 16

请注意,使用'buffer'类型时,Buffer的默认编码为'utf8'。因此,当我们调用buffer.toString时,我们会得到这个令人讨厌的输出。你看到那里的\u了吗?那是unicode。如果您没有使用正确的hex参数,则可以轻松地将缓冲区转换为base64字符串(或digest

// digest defaults to 'buffer' for unrecognized type
var key1 = crypto.createHash('md5').update('abcdefgh').digest('')

key1.length
// => 16

key1.toString()
// => '��@��44�Q�� �{h\u0018'

key1.toString('hex')
// => 'e8dc4081b13434b45189a720b77b6818'

无论传递给摘要的参数如何,缓冲区中的结果字节都是相同的。编码只是传递给缓冲区,只要您选择将缓冲区转换为字符串,就可以对其进行更改。

答案 1 :(得分:2)

Buffer构造函数(已弃用)需要第二个参数用于编码。如果您没有指定,则将输入解释为UTF-8。

您的md5哈希值无效UTF-8,但Buffer构造函数尝试从中构造有效的UTF-8字符串。在我看来,它应该用replacement characters替换无效字节,但它最终做的事情如下:对于每个字节都有0作为第一位,没有任何改变(它们已经有效),对于每个字节都有1作为第一位,它将字节编码为以下两个字节:

110000xx 10xxxxxx

x s是其编码的字节的位。在您的情况下,这种情况会发生八次,这会导致c2c3后跟另一个字节。在第一个位置具有0的所有字节都被正常编码。最终会有8个额外字节,16 + 8 = 24

您应该指定您希望缓冲区接受二进制文件:

console.log(new Buffer(key1, 'binary'));

并且,由于不建议使用Buffer构造函数,因此应切换到Buffer.from

console.log(Buffer.from(key1, 'binary'));