如何在Python中使用scrypt生成密码和盐的哈希值

10

我想使用scrypt为我的用户密码和盐值创建哈希值。我找到了两个参考资料,但其中有些问题我不理解。

它们使用scrypt加密和解密函数。其中一个将随机字符串加密,另一个将盐(看起来不对,因为只有密码而不是盐用于解密)加密。似乎解密函数用于通过解密的副作用验证密码/盐。

根据我所了解的一点信息,我需要的是密钥派生函数(KDF),而不是加密/解密,并且KDF很可能由scrypt用于加密/解密而生成和使用。实际的KDF在幕后使用,我担心盲目跟随这些示例会导致错误。如果scrypt加密/解密函数用于生成和验证密码,我不理解被加密的字符串的作用。其内容或长度是否重要?

2个回答

11

你说得对 - 这两个链接处理的是 scrypt 文件加密实用工具,而不是底层的 kdf。我一直在努力创建一个基于独立的 scrypt 的密码哈希算法,也遇到了这个问题。

scrypt 文件实用工具的功能如下:选择特定于您的系统的 scrypt 的 n/r/p 参数和“最小时间”参数。然后生成一个 32 字节的盐,并调用 scrypt(n,r,p,salt,pwd) 创建一个 64 字节的密钥。该工具返回的二进制字符串由以下内容组成:1) 包含 n、r、p 值的头文件,以及以二进制编码的盐;2) 头文件的 sha256 校验和;3) 使用密钥的前 32 个字节对校验和进行 hmac-sha256 签名的副本。接下来,它使用密钥的剩余 32 个字节对输入数据进行 AES 加密。

我可以看到其中有几个含义:

  1. 输入数据是无意义的,因为它实际上不会影响使用的盐,而且每次加密()都会生成一个新的盐。

  2. 你不能手动配置 n、r、p 工作负载,也不能通过任何方式除了笨拙的最小时间参数。这并不是不安全的,但这是一个非常笨拙的控制工作因素的方法。

  3. 在解密调用重新生成密钥并将其与 hmac 进行比较之后,如果你的密码不正确,它将在那里拒绝所有内容 - 但如果正确,它将继续“同时”解密数据包。这是攻击者不必执行的大量额外工作 - 他们甚至不需要推导出 64 个字节,只需要推导出检查签名所需的 32 个字节。这个问题并不使它“不安全”,但做一些攻击者不需要的工作是绝不可取的。

  4. 没有办法配置盐密钥、派生密钥大小等。目前的值还不错,但仍然不是理想的。

  • 解密工具的“最大时间”限制在密码哈希方面是错误的 - 每次调用解密时,它都会估计您系统的速度,并根据此进行一些“猜测”,以确定是否可以在最大时间内计算出密钥 - 这比攻击者多做了更多额外的工作(见#3),但这也意味着在系统负载过重时,解密可能会开始拒绝密码。

  • 我不确定为什么Colin Percival没有将kdf和参数选择代码作为公共API的一部分,但实际上,在源代码中明确将其标记为“私有”-甚至不导出链接。这使我不敢直接访问它,需要进行更多的研究。

  • 总之,需要一个可以存储scrypt的良好哈希格式,以及一个公开底层kdf和参数选择算法的实现。我目前正在为passlib自己开发,但它还没有得到太多关注:(

    总的来说,那些网站的说明是“可以”的,我只会将空字符串用作文件内容,并注意额外的开销和问题。


    谢谢。我计时了一些解密过程,它们似乎高度不稳定且即使对于一个字符的字符串也很耗时。其他问题我可以接受,但是不知道应该放什么值才能避免解密返回“解密文件需要太长时间”错误,让它对我来说无法使用。bcrypt看起来更友好,对我来说可能会很好。 - Mitch

    6
    那两个参考资料完全错了。不要动encryptdecrypt:直接使用hash
    KDF没有直接暴露,但hash足够接近。(实际上,我认为它甚至更好,因为它将填充PBKDF2三明治的混合物。) 这个示例代码适用于python2.7和python3.2。它使用PyCrypto、passlib和py-scrypt,但只需要py-scrypt
    您将希望使用像passlib.utils.consteq这样的恒定时间比较函数来减轻时间攻击。
    您还将希望仔细选择参数。默认值logN=14,r=8,p=1表示使用16 MiB内存的1“轮”。在服务器上,您可能需要像10,8,8这样的东西--更少的RAM,更多的CPU。您应该在您的硬件下,在您的预期负载下计时它。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接