我想使用scrypt为用户的密码和盐创建哈希。我找到了two references,但有一些我不了解的事情。
他们使用scrypt加密和解密函数。一个加密随机字符串,另一个加密盐(看起来不对,因为只有密码而不是盐用于解密)。看起来解密函数用于验证密码/ salt是解密的副作用。
基于我所理解的一点点,我想要的是密钥派生函数(KDF)而不是加密/解密,并且KDF很可能由scrypt生成并用于加密/解密。实际的KDF在幕后使用,我担心盲目跟随这些例子会导致错误。如果scrypt加密/解密函数用于生成和验证密码,我不明白加密字符串的作用。它的内容或长度是否重要?
答案 0 :(得分:10)
你是对的 - 这两个链接正在使用的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)使用密钥的前32个字节的校验和的hmac-sha256签名副本。之后,它使用密钥的剩余32个字节来加密输入数据。
我可以看到这有几个含义:
输入数据没有意义,因为它实际上不会影响正在使用的salt,而encrypt()每次都会生成一个新的salt。
您不能手动配置n,r,p工作负载,也不能以任何其他方式配置笨拙的min-time参数。这不是不安全的,但是控制工作因素是一种相当尴尬的方式。
在解密调用重新生成密钥并将其与hmac进行比较后,如果密码错误,它将拒绝所有内容 - 但如果正确,它将继续 解密数据包。这是攻击者不必执行的大量额外工作 - 他们甚至不需要派生64个字节,只需要检查签名所需的32个字节。这个问题并不能完全解决不安全,但攻击者的工作并不可取。
无法配置salt密钥,派生密钥大小等。当前值并不是那么糟糕,但仍然不理想。
解密实用程序的“最长时间”限制对于密码散列是错误的 - 每次调用解密时,它都会估算系统的速度,并对是否可以在最大时间内计算密钥进行“猜测” - 这是攻击者不必做的更多开销(参见#3),但这也意味着解密可能会在繁重的系统负载下开始拒绝密码。
我不确定为什么 Colin Percival没有制作kdf&参数选择公共API的代码部分,但它在源代码中明确标记为“私有” - 甚至不导出用于链接。这让我在没有更多研究的情况下直接访问它会犹豫不决。
总而言之,我们需要的是一个可以存储scrypt的漂亮哈希格式,以及一个公开底层kdf和参数选择算法的实现。我目前正在为passlib做自己的工作,但它没有引起太多关注:(
虽然只是为了底线 - 这些网站的说明是'好',我只是使用空字符串作为文件内容,并注意额外的开销和问题。
答案 1 :(得分:4)
这两个引用都完全错了。不要与encrypt
和decrypt
混淆:只需使用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“round”。在服务器上,您可能需要更像10,8,8的内存 - 更少的内存,更多的CPU。您应该在 预期负载下的 硬件上计时。