为啥我的 pbkdf2 实现这么慢(与 SQLCipher 相比)?

Posted

技术标签:

【中文标题】为啥我的 pbkdf2 实现这么慢(与 SQLCipher 相比)?【英文标题】:why is my pbkdf2 implementation so slow (vs. SQLCipher)?为什么我的 pbkdf2 实现这么慢(与 SQLCipher 相比)? 【发布时间】:2013-02-22 12:22:27 【问题描述】:

我在我的 Xoom 平板电脑上编写了一个简单的 android 应用程序,它只是将一些字符串注释存储在 SQLCipher 数据库中。

提示用户输入密码短语,SQLCipher 库将使用该密码短语。到目前为止,这工作正常且非常顺利。

现在我还实现了一个用于身份验证的小型 PBKDF2 算法 (事实上​​,我想在将来加密一些其他文件,这些文件不能存储在数据库中)。 但就目前而言,我只是来检查我的 pbkdf2 算法是否正确。 我只使用了 javax.crypto 和 java.security 库。

代码sn-p如下:

int derivedKeyLength = 128;
int iterations = 500;
KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), salt, iterations, derivedKeyLength);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] derivedKey = f.generateSecret(spec).getEncoded();    

salt 是一个 16 字节的随机数,由 SecureRandom 生成。

所以我硬编码了密钥和盐,并比较了派生密钥进行身份验证(只是一个测试用例!)

我现在的问题是,在我的 Xoom 上,它持续大约 5 秒直到派生函数完成,尽管迭代设置为 500。

AFAIK SQLCipher 默认使用 4000 的迭代次数,如果密钥错误或正确,它会立即响应。 (如果我将迭代设置为4000,至少需要15秒)

问题是,我是否实现了效率低下或者是因为 SQLCipher 的性能非常好(本机 NDK 函数等)?

提前谢谢你 p.s: 对不起,我的英语还不是很好!

编辑:

对不起,我不够清楚:-)

我知道 PBKDF2 应该很慢(特别是迭代量,以减慢蛮力攻击),这正是我要问的原因!我想将迭代次数设置为 5000(这是不可接受的,超过 15 秒)

我只是想知道,因为正如我所说,SQLCipher 还使用 PBKDF2(迭代 = 4k,而我使用 500)从给定密码派生密钥。最后我不是在谈论使用 AES 加密,它只是关于派生密钥的差异。

当然,SQLCipher 似乎比自制的密钥导出函数快得多,但我不认为会有这么大的不同,因为 SCLCipher 的 PBKDF2 确实可以即时运行!

您好!

【问题讨论】:

欢迎来到 IT 安全 StackExchange!我投票结束了这个问题,因为它似乎是一个编程问题而不是安全问题!如果某个模组同意我的观点,它将为您迁移到 ***。 好吧,谢谢你,对不起! :) 【参考方案1】:

好的,这(见下文)不完全是您的问题,PBKDF2 很慢,但应该没有那么慢,正如硬件上的这些参数所描述的那样。 这里有一些关于 Android PBE/KDF 性能的统计数据(和提示):http://nelenkov.blogspot.com/2012/04/using-password-based-encryption-on.htmlSecretKeyFactory 性能问题不是未知数:Any way around awful SecretKeyFactory performance with LVL and AESObfuscator?。

SecretKeyFactory 可能使用纯 Java 实现。 SQLCipher 有两个相关的特性:

它使用 OpenSSL,编译后的本机代码(在我的 桌面OpenSSL 的 PBKDF2 比 一个 JVM6 SecretKeyFactory 版本,用于 2000 次迭代,不包括 JVM 启动时间。我没有 比较 AES 速度,似乎其他人在 Android 上也觉得它很慢) 4000 次迭代 PBKDF2 仅在数据库打开时完成,之后最多 2 次迭代 用于页面 HMAC 机密(假设默认配置,如文档所述)

您的代码似乎是正确的,当您增加迭代次数时,不应该出现如此大的(线性?)性能下降。 Xoom 应该是用 JIT 运行一个非古代 JVM,你能用other code 验证性能问题吗?


由于预期的key stretching 操作,PBKDF2 设计很慢(请参阅此问题的答案https://security.stackexchange.com/questions/7689/clarification-needed-for-nists-whitepaper-recommendation-for-password-based-ke)。迭代计数器可让您以速度换取安全性。

AES 一直是 intended to be fast 并且是 快速(speed comparison PDF,所选的 AES 候选者在该论文中以其原始名称 Rijndael 引用)。

我假设您将 PBKDF2 计算时间直接与在您的 SQLCipher 数据库上执行 SQL 操作所花费的时间进行比较,几乎可以肯定该数据库的设计速度很快。

您实际上是在比较具有不同要求的两种不同操作,因此速度差异。

【讨论】:

感谢您的回答!我想我不够清楚,请检查我的编辑:) 好的,明白了,将更新答案。我做了一些快速测试,我可以看到在我的 x86 桌面上,Java (1.6.x) 实现似乎比 OpenSSL 的 PKCS5_PBKDF2_HMAC_SHA1() 慢了 100 倍左右。 +1 非常感谢 Mr.spuratic。你把我带到了正确的方向!我想通了,我会上传我的答案。【参考方案2】:

好的,我知道问题出在哪里了。

如果我断开设备与我的 PC 的连接,它会立即工作。另外,如果我在那之后重新连接它。

现在即使迭代量5000及以上,求导函数也只需要不到一秒!!这很棒,因为我的 Xoom 不是所有设备中最新的!

可能是调试模式的原因还是什么,我真的不知道!

无论如何,感谢 mr.spuratic。希望这对将来的某人有所帮助:-)

【讨论】:

我在摩托罗拉 Android 手机上遇到了奇怪的性能问题(高 CPU)。它是通过通过 USB 连接到 PC 来触发的,即使只是为了充电。解决方法是启用 USB 调试:code.google.com/p/android/issues/detail?id=13130

以上是关于为啥我的 pbkdf2 实现这么慢(与 SQLCipher 相比)?的主要内容,如果未能解决你的问题,请参考以下文章

为啥与完全没有 JavaScript 相比,通过 AJAX 的 GET 请求替换 div 会导致我的网站变慢这么多?

为啥 Moose 代码这么慢?

为啥我的代码这么慢?

为啥我的 MySQL 组这么慢?

为啥我的 MongoDB 聚合查询这么慢

为啥我的解决方案这么慢,如何提高查询的性能?