密码哈希字符串编码的标准是什么?

Tim*_*Tim 6 storage portability glibc go password-hash

我询问密码经过哈希处理并准备存储后使用的格式。美元符号$注释似乎很普遍。标准中是否有描述(包括算法的标识符)?

\n

例如,当使用 Go with 时golang.org/x/crypto/bcrypt,它给出这样一个编码字符串(playground):

\n
func main() {\n    h, err := bcrypt.GenerateFromPassword([]byte("foo"), bcrypt.DefaultCost)\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Printf("%s", h)\n    // Output: $2a$10$g1d5KuvDIrRoUyWL2BQs7uLOWCzlM.zqbRm8o364u20p20YNmJ.Ve\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但是,其他散列包scrypt例如argon2仅返回结果散列。使用argon2shell 命令,返回一个编码字符串:

\n
echo "foo" | argon2 saltsalt\nType:           Argon2i\nIterations:     3\nMemory:         4096 KiB\nParallelism:    1\nHash:           d9e4f94546b9e5b0cfb2dbf9dad81d41371845d8b6a8c25ce7caf23e13f1ef72\nEncoded:        $argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHQ$2eT5RUa55bDPstv52tgdQTcYRdi2qMJc58ryPhPx73I\n0.005 seconds\nVerification ok\n
Run Code Online (Sandbox Code Playgroud)\n

我找到了一篇 Go/argon2特定的博客文章解释了这种编码,到目前为止还不错

\n

我发现的变体

\n

我的麻烦在于美元分隔字符串的定义、我发现的可移植性和变化。

\n

glibc

\n

man 3 crypt页面给出了一些指示。有一个标识符表:

\n
              ID   Method\n              \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n              1    MD5\n              2a   Blowfish (not in mainline glibc; added in some Linux\n                   distributions)\n              5    SHA-256 (since glibc 2.7)\n              6    SHA-512 (since glibc 2.7)\n
Run Code Online (Sandbox Code Playgroud)\n

但这不包括较新的类型,例如argon2ior scrypt

\n

然后是示例字符串:

\n
$id$salt$encrypted\n$id$rounds=yyy$salt$encrypted\n
Run Code Online (Sandbox Code Playgroud)\n

后者仅在 Glibc 2.7 之后才被支持。

\n

密码

\n

虽然bcrypt使用2aGlibc 中的 (blowfish) 标识符,但其编码似乎与上面的示例略有不同:

\n
$2a$10$g1d5KuvDIrRoUyWL2BQs7uLOWCzlM.zqbRm8o364u20p20YNmJ.Ve\n$id$cost$<dot seperated line of what exactly?>\n
Run Code Online (Sandbox Code Playgroud)\n

氩气2

\n

Argon2 使用 5 个字段和一个全名标识符,例如argon2

\n
$argon2i$v=19$m=4096,t=3,p=1$c2FsdHNhbHQ$2eT5RUa55bDPstv52tgdQTcYRdi2qMJc58ryPhPx73I\n$id$version$parameters$salt$encrypted\n
Run Code Online (Sandbox Code Playgroud)\n

为什么?

\n

我想编写一个包,以与算法无关的方式散列和验证密码。允许消费者更改参数和算法而无需重构其代码。因此,在验证过程中,包应该能够断言存储密码时使用的算法。如果存储的参数或算法版本与当前使用的版本不同,则将重新散列密码并返回新的编码字符串。

\n

作为奖励,我希望该包能够重新散列可能由较旧(不可用)应用程序存储的“旧”密码。例如,md5。为了做到这一切,我想对存储格式本身有更深入的了解。

\n

Jör*_*tag 4

\n

密码哈希字符串编码的标准是什么?

\n
\n

空无一人。

\n

嘿,这是一个简单的答案!单击“发布您的答案”

\n

好吧,虽然不幸的是上述陈述是正确的,但值得庆幸的是,有些人已经费尽心思收集了有关所有使用变化的大量信息。

\n

特别是,Python 的Passlib库的作者(它基本上做你想做的事情)已经写了一篇关于他们所谓的模块化加密格式的页面,他们称之为“一个不是 \xe2\x80\x99t 的标准” ”。以下是该页面的一些选择引用[粗体斜体强调我的]:

\n
\n

然而,\xe2\x80\x99s没有官方规范文档描述这种格式。也不存在标识符的中央注册表或实际规则。模块化的 crypt 格式更多的是一个临时的想法,而不是一个真正的标准。

\n
\n

[模块化加密格式\xc2\xa0\xe2\x80\x93 概述]

\n
\n

不幸的是,没有这种格式的规范文档。相反,它仅以事实上的形式存在

\n
\n
\n

当 MCF 首次引入时,大多数方案选择单个数字作为其标识符(例如$1$md5_crypt 。因此,一些较旧的系统只查看第一个字符在尝试区分哈希值时

\n
\n
\n

大多数模块化 crypt 格式哈希都遵循此约定,尽管有些(如bcrypt省略了$配置和摘要之间的分隔符。

\n
\n
\n

[T]这里没有关于配置字符串是否应该在末尾包含尾随的固定标准$

\n
\n

[模块化加密格式\xc2\xa0\xe2\x80\x93 要求]

\n

请注意,模块化加密格式不是规范或标准。它是对野外使用的各种不同格式的描述。密码哈希竞赛 (PHC)的组织者尝试制定一种规范,称为PHC字符串格式。然而,PHC 并不是具有任何权威的正式标准组织。它只是一群松散的密码学家。虽然他们建议每个新的密码哈希函数都应使用 PHC 字符串格式,但他们只能对提交给密码哈希竞赛的密码哈希函数强制使用该格式。

\n

无论哪种方式,PHC 字符串格式仅适用于新的密码哈希函数,不适用于现有的密码哈希函数。

\n

虽然我强烈建议您应该对生成的任何输出使用 PHC 字符串格式,但您仍然需要处理各种不同格式的输入,包括一些像这样的宝石

\n
\n

cta_pbkdf2_sha1dlitz_pbkdf2_sha1都使用相同的标识符。虽然还存在其他内部差异,但可以通过以下事实快速区分两者:cta 哈希值始终以 结尾=,而 dlitz 哈希值不包含=根本不包含结尾。

\n
\n