消息摘要(哈希)是字节数组输入和字节数组输出
消息摘要被定义为一个函数,它接受一个原始的字节数组并返回一个原始的字节数组(也称为byte[]
)。例如SHA-1(安全哈希算法1)的摘要大小为160位或20个字节。原始的字节数组通常不能被解释为字符编码,如UTF-8,因为不是每个字节按照每个顺序都是合法的编码。所以将它们转换为String
的方法是:
new String(md.digest(subject), StandardCharsets.UTF_8)
可能会创建一些非法序列或具有指向未定义Unicode映射的代码指针:
[�a�ɹ??�%l�3~��.
二进制到文本编码
为此,使用二进制到文本编码。在哈希中,最常用的是十六进制编码或Base16。基本上,一个字节可以具有从0
到255
(或-128
到127
有符号)的值,这相当于0x00
-0xFF
的十六进制表示。因此,十六进制将使输出所需的长度加倍,这意味着20个字节的输出将创建一个40个字符长的十六进制字符串,例如:
2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
请注意,不一定需要使用十六进制编码。您也可以使用类似于
base64的东西。十六进制通常更受欢迎,因为它更容易被人类阅读,并且具有定义的输出长度,无需填充。
您可以仅使用JDK功能将字节数组转换为十六进制:
new BigInteger(1, token).toString(16)
请注意,BigInteger
将把给定的字节数组解释为一个数字而不是一个字节字符串。这意味着前导零将不会被输出,结果字符串可能比40个字符短。
使用库将其编码为十六进制
您现在可以从Stack Overflow复制并粘贴未经测试的字节到十六进制方法,或者使用大量依赖项,如Guava。
为了解决大多数字节相关问题,我实现了一个实用程序来处理这些情况:bytes-java (GitHub)。
要转换您的消息摘要字节数组,您只需执行以下操作:
String hex = Bytes.wrap(md.digest(subject)).encodeHex();
或者你可以直接使用内置的哈希功能
String hex = Bytes.from(subject).hashSha1().encodeHex();
getBytes()
时指定字符编码是一个好的实践,例如使用toSHA1("password".getBytes("UTF-8"))
。 - Qwerky