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

Posted

技术标签:

【中文标题】如何在 Python 中使用 scrypt 生成密码和盐的哈希值【英文标题】:How to use scrypt to generate hash for password and salt in Python 【发布时间】:2012-11-19 05:18:37 【问题描述】:

我想使用 scrypt 为我的用户密码和盐创建哈希。我找到了tworeferences,但有些地方我不明白。

他们使用 scrypt 加密和解密功能。一个加密一个随机字符串,另一个加密盐(这看起来是错误的,因为只有密码而不是盐用于解密)。看起来解密功能正在用于验证密码/盐作为解密的副作用。

根据我的了解,我想要的是密钥派生函数 (KDF) 而不是加密/解密,并且 KDF 可能由 scrypt 生成并用于加密/解密。实际的 KDF 在幕后使用,我担心盲目地遵循这些示例会导致错误。如果使用 scrypt 加密/解密函数来生成和验证密码,我不明白被加密字符串的作用。它的内容或长度重要吗?

【问题讨论】:

【参考方案1】:

这两个引用都完全错误。不要乱用encryptdecrypt:只需使用hash

KDF 没有直接暴露,但是hash 已经足够接近了。 (事实上​​,在我看来更好,因为它混合了 PBKDF2 三明治的馅料。)

This example code 适用于 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。您应该在 您的 硬件上在您的 预期负载下计时。

【讨论】:

【参考方案2】:

你是对的 - 这两个链接正在使用的 scrypt 函数是 scrypt 文件加密实用程序,而不是底层的 kdf。我一直在慢慢地为 python 创建一个基于 scrypt 的独立密码哈希,我自己也遇到了这个问题。

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

我可以看到这有几个含义:

    输入数据没有意义,因为它实际上并不影响正在使用的盐,并且 encrypt() 每次都会生成一个新的盐。

    您不能手动配置 n,r,p 工作负载,或者除了笨拙的 min-time 参数之外的任何其他方式。这不是不安全的,而是控制工作因素的一种相当尴尬的方式。

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

    没有办法配置盐键,派生键大小等。当前值还不错,但仍然不理想。

    1234563这是更多您的攻击者不必做的开销(参见#3),但这也意味着解密可能会在繁重的系统负载下开始拒绝密码。

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

总而言之,我们需要一个可以存储 scrypt 的良好哈希格式,以及一个公开底层 kdf 和参数选择算法的实现。我目前正在为passlib 做这件事,但它并没有引起太多关注:(

不过,最重要的是——那些网站的说明是“好的”,我只是使用一个空字符串作为文件内容,并注意额外的开销和问题。 p>

【讨论】:

谢谢。我对一些解密进行了计时,即使对于一个字符串,它们似乎也是高度可变且耗时的。我可以忍受的其他问题,但不知道要设置什么值以使解密不会返回“解密文件将花费太长时间”错误,这使我无法使用它。 bcrypt 看起来更友好,可能对我来说没问题。

以上是关于如何在 Python 中使用 scrypt 生成密码和盐的哈希值的主要内容,如果未能解决你的问题,请参考以下文章

如何在 VSCode 中运行 SCrypt [重复]

使用预定义的 scrypt 文件通过 Spring 自动生成 sql 表

sCrypt 合约中如何使用优化版 OP_PUSH_TX

如何快速调试 sCrypt 单元测试错误

如何在 sCrypt 合约中实现浮点数运算

针对 Scrypt 组合哈希验证 python 密码:(设置+盐+哈希)