1

我正在为针对 Linux 的 MD5 散列方案编写一个基本的密码破解程序/etc/shadow file。当我使用commons.codec'sDigestUtilsCrypt库时,它们的哈希长度是不同的(除其他外)。

当我使用时Crypt.crypt(passwordToHash, "$1$Jhe937$"),输出是一个 22 个字符的字符串。当我使用DigestUtils.md5[Hex](passwordToHash + "Jhe937")(或 JavaMessageDigest类)时,输出是一个 32 个字符的字符串(转换后)。这对我来说毫无意义。


另外:没有简单的方法可以将DigestUtils.md5(passwordToHash)'s转换byte[]为字符串。我已经尝试了所有*方法,我得到了所有无效的输出:Nz_èJÓ_µù[î¬y

*all being:new String(byte[], "UTF-8")并转换为 char 然后转换为 String

4

1 回答 1

2

执行摘要是,虽然它们将执行相同的散列,但两者之间的输出格式不同,因此长度会有所不同。请继续阅读以了解详细信息。

MD5 是一种消息摘要算法,它始终生成 16 字节的哈希值(假设输入有效等)。这些字节并非都是可打印的字符,它们可以为任何字节取 0-255 之间的任何值,而可打印的ASCII 中的字符在 32-126 范围内。

DigestUtils.md5(String) 生成字符串的 MD5 并返回一个 16 元素字节数组。DigestUtils.md5Hex(String) 是 DigestUtils.md5 周围的一个便利包装器(我假设,我没有查看源代码,但我就是这样写的:-)),它采用 md5 产生的 16 个元素字节数组base16 对其进行编码(也称为十六进制编码)。这会将每个字节替换为等效的两个十六进制字符,这就是为什么您会从中得到一个 32 个字符的字符串。

Crypt.crypt 使用一种特殊的格式,可以追溯到原始 Unix 存储密码的方法。多年来,它已被扩展以使用不同的哈希/加密算法、更长的盐和附加功能。它还将其输出编码为可打印的文本,这是长度差异的来源。通过使用“$1$...”的盐,您说的是使用 MD5,因此密码和盐将使用 MD5 进行散列,如预期的那样产生 16 个字节,但是因为这些字节不一定是可打印的,哈希是 base64 编码的(使用与标准 base64 编码略有不同的字母表),它将 3 个字节替换为 4 个可打印字符。所以 16 个字节变成 16 / 3 * 4 = 21-1/3 个字符,四舍五入到 22。

在您旁边,DigestUtils.md5 产生 16 个字节,但这些字节可以具有从 0 到 255 的任何值并且(实际上)是随机的。new String(byte[], "UTF-8") 表示字节数组中的字节是 UTF-8 编码,这是一种非常特殊的格式。new String 最好将字节视为 UTF-8 编码的字符串,但因为它们实际上不是,所以通常会出现乱码。如果你想要一些可打印的东西,你必须使用随机字节,而不是特定格式的字节(如 UTF-8)。两个流行的选项是 base16/hex 编码,您可以使用 DigestUtils.md5Hex 获得,或者 base64,您可以使用 Base64.encodeBase64String(DigestUtils.md5(pwd + salt)) 获得。

于 2015-09-25T22:53:32.367 回答