PasswordHash.java未生成匹配的PBKDF2-HMAC-SHA1哈希
我正在写一个Django应用程序,需要和一个现有的Java Play框架应用程序一起工作。这个Play应用使用了PasswordHash.java来存储密码。它以冒号分隔的格式来存储密码。每个密码的存储格式是iterations
:salt
:pbkdf2_hash
。
比如,密码“test”的存储格式是:
1000:f7fe4d511bcd33321747a778dd21097f4c0ff98f1e0eba39:b69139f51bc4098afc36b4ff804291b0bc697f87be9c1ced
我们可以通过:
来分割这个字符串,得到:
迭代次数: 1000
盐值: f7fe4d511bcd33321747a778dd21097f4c0ff98f1e0eba39
PBKDF2哈希值: b69139f51bc4098afc36b4ff804291b0bc697f87be9c1ced
。
我修改了Django的密码检查机制,以便与这个格式兼容,但发现它认为密码不正确。我使用Django的crypto.py,用Play使用的相同盐值重新生成了“test”的哈希值,结果是:
hash = crypto.pbkdf2('test', 'f7fe4d511bcd33321747a778dd21097f4c0ff98f1e0eba39', 1000, 24)
base64.b16encode(hash)
'9A8725BA1025803028ED5B92748DD61DFC2625CC39E45B91'
Play生成的PBKDF2哈希值和这个哈希值不匹配。(有些人可能会问,我使用24作为第四个参数,因为PasswordHash.java中就是这么用的。)
在我无法让Django生成的哈希值与Java的匹配后,我尝试在一个可以帮你做的网站上进行测试。
我输入了相同的盐值,使用SHA-1进行1000次迭代和24位密钥大小,发现这个网站生成的结果和Django的一致!
我不太确定PasswordHash.java出了什么问题,但我非常需要让Django和Play能够“好好相处”(我忍不住哈哈)。有没有人知道这里面发生了什么?
1 个回答
试试这个:salt = base64.b16decode(salt.upper())
。
我试过了,得到了你最开始例子里的哈希值,虽然是大写的 B69139F5...
。
解释一下:
在你最开始的例子中,哈希值和盐都是以Base16(十六进制)的形式存储的。所以你需要先解码盐,然后再对得到的哈希值进行编码,以便和存储的哈希值进行比较。
使用 upper()
是因为Python的 b16decode
对大写的Base16要求很严格。如果你给它小写的,它会报错。