我一直在尝试将java密码身份验证复制到python,但是得到的哈希值不同。在
密码:abcd1234
密码令牌(java):$31$16$swy1ddex52vwquswxdymqmztjc39g1\u nmrK384T4-w
生成的密码令牌(python):$pbkdf2$16$c1d5MWRERXg1MnZ3UVVDcw$qpqve4qbrnyjtmrxk0m7wlfh5u
从Java代码来看,迭代是16,SALT应该是sWy1dDEx52vwQUCswXDYMQMzTJC39g1_nmrK384T4-w中的前16个字符,即sWy1dDEx52vwQUCs,散列应该是wXDYMQMzTJC39g1 nmrK384T4-w
但是,将变量应用于python得到了一个不同的hash结果,qpqve4qbrnyjtmrxk0m7wlfh5u,这与Java的hash不同。在
我错过了哪里?在
爪哇语:
private static final String ALGORITHM = "PBKDF2WithHmacSHA1";
private static final int SIZE = 128;
private static final Pattern layout = Pattern.compile("\\$31\\$(\\d\\d?)\\$(.{43})");
public boolean authenticate(char[] password, String token)
{
Matcher m = layout.matcher(token);
if (!m.matches())
throw new IllegalArgumentException("Invalid token format");
int iterations = iterations(Integer.parseInt(m.group(1)));
byte[] hash = Base64.getUrlDecoder().decode(m.group(2));
byte[] salt = Arrays.copyOfRange(hash, 0, SIZE / 8);
byte[] check = pbkdf2(password, salt, iterations);
int zero = 0;
for (int idx = 0; idx < check.length; ++idx)
zero |= hash[salt.length + idx] ^ check[idx];
return zero == 0;
}
Python:
^{pr2}$Java代码的原始链接:How can I hash a password in Java?
java代码的工作方式与passlib的pbkdf2廑sha1哈希器有很多不同之处。在
java哈希字符串包含一个logcost参数,该参数需要通过
1<<cost
来获得轮数/迭代次数。salt+摘要需要进行base64解码,然后将前16个字节作为salt(实际上对应于base64数据的前21个1/3个字符)。
类似地,由于摘要的位是从base64字符的中间开始的,所以当salt+摘要被解码,然后对digest进行单独编码时,base64字符串将是
AzNMkLf2DX-easrfzhPj7A
(明显不同于原始编码字符串)。基于此,下面的代码将java哈希转换为pbkdf1_sha1.verify使用的格式:
结果字符串应该适合传递到
pbkdf2_sha1.verify("abcd1234", hash)
;,除非有一个问题: java代码将sha1摘要截断为16个字节,而不是完整的20个字节;按照passlib哈希器的编码方式,摘要必须是完整的20个字节。在如果将java代码改为使用SIZE=160而不是SIZE=128,那么通过上面的adapt()函数运行散列应该可以在passlib中工作。在
相关问题 更多 >
编程相关推荐