我想使用PBKDF2WithHmacSHA1生成密钥,但在android上计算需要很长时间。我在iOS上使用相同数量的迭代与普通加密,它需要大约6秒,因为在Android上需要100秒。
以下是代码:
public static String generateStorngPasswordHash(String password)
{
try
{
char[] chars = password.toCharArray();
byte[] salt = getSalt();
PBEKeySpec spec = new PBEKeySpec(chars, salt, 1010101, 32 * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = skf.generateSecret(spec).getEncoded();
return toHex(salt) + ":" + toHex(hash);
} catch (Exception e)
{
Logger.e("Exception: Error in generating password" + e.toString());
}
return "";
}
private static byte[] getSalt() throws NoSuchAlgorithmException
{
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[32];
sr.nextBytes(salt);
return salt;
}
如果此代码有任何问题,请与我们联系?
修改
还有一件事,我也在我的应用程序中使用sqlCipher。他们使用openssl来计算PKDF2,我已经读过某个地方,openssl实现比java实现快得多,可以找到PKDF2。所以我的问题是:
答案 0 :(得分:3)
是的,关于在循环中执行SHA,Java明显慢于(Objective)C。与编译语言相比,Java对于加密并不是特别快。另一方面,它允许相对安全的代码。所以你的结果不会让我感到震惊。除非您可以使用另一个使用本机代码的更快的提供程序,否则您应该得到这样的结果。
然而,有一些方法可以缓解正在发生的事情。例如,您可以降低迭代次数。更高的数字更安全,但它们只能帮助您线性增加攻击者的工作量。采取其他措施,例如有限次数的尝试,更安全的DB或需要更好的密码短语可以提供比仅增加迭代计数更好的安全性。如果可能,不要过分依赖PBKDF2提供的关键强化。
此外,您从PBKDF2请求32个字节。由于PBKDF2内部循环的单次运行的输出仅产生20字节输出(SHA-1创建160位哈希),该循环运行两次,一次用于初始20字节,然后再次用于剩下的12个字节。如果攻击者只需要最初的16个字节来验证密码,那么攻击者的工作量就会增加两倍。如果您只是将它用作密码哈希,那么只需要输出20个字节。如果密钥或IV需要32个字节,则在PBKDF的输出上使用KBKDF。或者,如果需要快捷方式,请在输出上执行SHA-256。
以下最后一部分的代码:
/**
* Same security, twice the speed.
*/
public static String generateStorngPasswordHashWithSHA256(String password) {
try {
char[] chars = password.toCharArray();
byte[] salt = getSalt();
PBEKeySpec spec = new PBEKeySpec(chars, salt, 1010101,
20 * Byte.SIZE);
SecretKeyFactory skf = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = skf.generateSecret(spec).getEncoded();
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
hash = sha256.digest();
return toHex(salt) + ":" + toHex(hash);
} catch (Exception e) {
System.out.println("Exception: Error in generating password"
+ e.toString());
}
return "";
}