PBKDF2WithHmacSHA1密钥生成在Android上花费太长时间

Nau*_*aal 5 android cryptography pbkdf2 sqlcipher

我想使用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;
}
Run Code Online (Sandbox Code Playgroud)

如果此代码有任何问题,请告诉我?

编辑

还有一件事,我也在我的应用程序中使用sqlCipher.他们使用openssl来计算PKDF2,我已经读过某个地方,openssl实现比java实现快得多,可以找到PKDF2.所以我的问题是:

  1. 这是真的,openssl可以给我更好的Android性能吗?
  2. 我可以使用sqlCipherg中使用的openssl实现吗?
  3. 如果是,我如何使用openssl使用caclulate PKDF2?
  4. 如果否,那么如何使用openssl 在android中找到PBKDF2WithHmacSHA1.我
    在网上搜索过但没有找到任何例子.

Maa*_*wes 4

是的,在循环执行 SHA 方面,Java 比(目标)C 慢得多。与编译语言相比,Java 对于加密来说并不是特别快。另一方面,它允许相对安全的代码。所以你的结果不会让我感到震惊。除非您可以使用另一个使用本机代码的更快的提供程序,否则您应该期望这样的结果。

然而,有一些方法可以缓解正在发生的情况。例如,您可以减少迭代次数。数字越大越安全,但它们只会帮助您线性增加攻击者的工作量。采取其他措施(例如有限的尝试次数、更安全的数据库或要求更好的密码短语)可能会比仅仅增加迭代计数提供更好的安全性。如果可能,不要过度依赖 PBKDF2 提供的密钥强化。

此外,您正在向 PBKDF2 请求 32 个字节。由于 PBKDF2 内部循环的单次运行输出仅产生 20 字节输出(SHA-1 创建 160 位哈希值),因此循环运行两次,一次针对最初的 20 字节,然后再次针对剩余的 12 字节。如果攻击者只需要最初的 16 个字节来验证密码,那么攻击者的工作量是攻击者的两倍。如果您只是将其用作密码哈希,则只需要求 20 个字节的输出。如果您需要 32 个字节的密钥或 IV,请在 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 "";
}
Run Code Online (Sandbox Code Playgroud)