是否有使用PBKDF2作为密码哈希的标准?

时间:2009-09-24 18:19:36

标签: security hash pbkdf2

和我一起打击弱密码哈希。

PBKDF2密码哈希应包含salt,迭代次数和哈希本身,以便以后验证。对于PBKDF2密码哈希,是否有标准格式,如RFC2307的{SSHA}? BCRYPT很棒,但PBKDF2更容易实现。

显然,没有规格。所以这是我的规格。

>>> from base64 import urlsafe_b64encode
>>> password = u"hashy the \N{SNOWMAN}"
>>> salt = urlsafe_b64decode('s8MHhEQ78sM=')
>>> encoded = pbkdf2_hash(password, salt=salt)
>>> encoded
'{PBKDF2}1000$s8MHhEQ78sM=$hcKhCiW13OVhmLrbagdY-RwJvkA='

更新:http://www.dlitz.net/software/python-pbkdf2/定义crypt()替换。我更新了我的小规格以匹配他,除了他的$p5k2$而不是{PBKDF2}。 (我需要远离其他LDAP风格的{SCHEMES})。

那是{PBKDF2},以小写十六进制,$urlsafe_base64编码的盐,$urlsafe_base64编码的PBKDF2输出的迭代次数。 salt应为64位,迭代次数应至少为1000,具有HMAC-SHA1输出的PBKDF2可以是任意长度。在我的实现中,默认情况下总是20个字节(SHA-1哈希的长度)。

在通过PBKDF2发送之前,密码必须编码为utf-8。没有关于是否应该将其归一化为Unicode的NFC的说法。

这个计划应该比{SSHA}的蛮力成本高iterations倍。

2 个答案:

答案 0 :(得分:4)

PBKDF2的参数(盐和迭代)有一个规范,但它不包括散列。这包含在PKCS #5 version 2.0中(见附录A.2)。某些平台内置支持对此ASN.1结构进行编码和解码。

由于PBKDF2实际上是一个密钥派生函数,因此指定一种方法将“哈希”(实际上是派生密钥)与派生参数捆绑在一起是没有意义的 - 在正常使用中,密钥必须保密,永远不会存储。

但是作为单向密码哈希的用法,哈希可以存储在带有参数的记录中,但是在它自己的字段中。

答案 1 :(得分:4)

我会和你一起抗击弱哈希。

OWASP有一个密码存储备忘单(https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet),并附有一些指导;他们建议截至2012年最少64,000次PBKDF2迭代,每两年翻一番(即2012年为90,510次)。

请注意,每个用户ID存储长的加密随机盐始终是基本的。

请注意,具有广泛可变的每用户标识迭代次数并将迭代次数与盐一起存储将增加破解软件的一些复杂性,并可能有助于排除某些优化。例如,“bob”使用135817次迭代加密,而“alice”使用95,121次迭代,即2013年的最小值(90510 + RAND(90510))。

另请注意,如果允许用户选择“密码”,“密码1!”,“P @ $$ w0rd”和“P @ $$ w0rd123”等弱密码,则所有这些都无用确实很快就会发现基于规则的字典攻击(后者只是“密码”,具有以下规则:大写第一个字母,1337-说话,在末尾添加一个三位数字)。拿一个基本的词典列表(phpbb,一个好的,小的入门词表)并应用这样的规则,你会破解很多密码,人们会尝试“聪明”的技巧。

因此,在检查新密码时,不要只应用“全部四个上,下,数字,数字,至少11个字符”,因为“P @ $$ w0rd123”符合这个看似非常严格的规则。相反,使用该基本字典列表,看看基本规则是否会破解它(它比实际尝试破解简单得多 - 你可以小写你的列表和他们的单词,然后简单地写代码,如果“如果最后4个字符是一个普通的年份,检查除了单词列表中的最后四个字符以外的所有字符“,并且”如果最后3个字符是数字,则检查除了单词列表之外的所有除了最后3个字符之外的所有字符“并且”检查除了单词列表之外的所有除了最后两个字符之外“并且“De-1337密码 - 将@转换为a,将3转换为e,依此类推,然后根据wordlist检查它并尝试其他规则。”

就密码而言,一般来说都是一个好主意,特别是如果将其他一些字符添加到单词的中间,但是当且仅当它们足够长时,因为你放弃了很多可能组合

请注意,即使在2012年,拥有GPU的现代机器每秒也会达到数百亿次哈希迭代(MD5,SHA1,SHA-256,SHA-512等)。至于单词组合“正确的马”电池订书钉“类型密码,这个密码至多是一个非常适度的密码 - 它只有4个长度为7或更小的英文单词,带有空格。所以,如果我们去寻找XKCD风格的密码,用180亿次猜测第二次设置:一个现代的小美国英语词典有:6k字长5或更少21k字长7或更少36k字长9或更少46k字长度为11或更少49k字长度为13或更短

使用XKCD风格的密码短语,并且无需按照受欢迎程度来过滤单词(“正确”与“主席”对比“排骨”与“出血”),我们有21k ^ 4,这只是2E17的可能性。凭借180亿/秒的设置(如果我们面对单个SHA1迭代,单个机器具有8个GPU),那么大约需要4个月才能彻底搜索密钥空间。如果我们有十个这样的设置,那大约两周。如果我们排除了像“dumpier”这样的不太可能的词,那么快速的第一次传球就会快得多。

现在,如果你从一个“巨大的”linux美国英语单词列表中得到的话,比如“Balsamina”或“Calvinistically”(两者都是通过使用“go to row”功能选择的话),那么我们就有30k字的话长度5或以下115k字长7或以下231k字长9或以下317k字长11或以下362k字长13或以下

即使有7个最大长度限制,以这个庞大的字典作为基础和随机选择的单词,我们有115k ^ 4~ = 1.8E20的可能性,或者如果设置保持最新的约12年(功率加倍)每18个月一次)。这非常类似于13个字符,小写+仅限密码。大多数估计会告诉你“300年”,但他们没有考虑到摩尔定律。