【问题标题】:Nodejs crypto md5 hash gives me digest of size 24 bytes, instead of expected 16Nodejs 加密 md5 哈希给了我 24 字节大小的摘要,而不是预期的 16
【发布时间】:2017-01-08 15:56:45
【问题描述】:
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 字节的摘要吗?

【问题讨论】:

  • 输出看起来不像MD5输出,看起来不是随机的,0xc2出现7次可能是console.log导致了意外输出。

标签: node.js encryption hash cryptography md5


【解决方案1】:

hash.digest(encoding) docs

计算所有传递给哈希的数据的摘要(使用 hash.update() 方法)。编码可以是'hex''latin1''base64'。如果提供了编码,将返回一个字符串;否则返回一个 Buffer。

'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 了吗?那是统一码。如果您没有使用正确的digest 参数,您可以轻松地将缓冲区转换为hex 字符串(或base64

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

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

【讨论】:

  • binary 输出是不言自明的,没有编码。
  • 'binary''?' 编码方法被视为相同。您的反对票无效。
  • 是时候学习一下什么是编码了,二进制就是,字节数没有意义。
  • 感谢@naomik 的建议,更新了我的问题。请忽略缓冲区,我只是用于调试。
  • @Prabhat 你现在有什么问题?我刚刚告诉过你,16 字节缓冲区的字符串表示的长度不会改变缓冲区长度为 16 的事实。缓冲区的“十六进制”字符串长 32 个字符,但它代表 16 个字节。
【解决方案2】:

Buffer 构造函数(已被弃用)需要第二个编码参数。如果您不指定一个,它会将输入解释为 UTF-8。

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

110000xx 10xxxxxx

xs 是它正在编码的字节的位。在您的情况下,这种情况发生了八次,这总是导致 c2c3 后跟另一个字节。所有在第一个位置有0 的字节都被正常编码。你最终得到了八个额外的字节,16 + 8 = 24:

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

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

而且,由于不推荐使用 Buffer 构造函数,您应该切换到Buffer.from

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

【讨论】:

    猜你喜欢
    • 2015-03-15
    • 1970-01-01
    • 2016-10-29
    • 1970-01-01
    • 1970-01-01
    • 2021-01-11
    • 1970-01-01
    • 2018-11-04
    • 1970-01-01
    相关资源
    最近更新 更多