为什么Android 24 +上的AES加密/解密速度会慢3倍?

时间:2017-10-16 06:55:55

标签: java android performance encryption cryptography

您可以跳至TL; DR

我们有一个应用程序,它强烈依赖于AES加密和解密。我们希望尽可能多地支持设备,但其中一些(特别是糟糕的平板电脑,我不仅仅是指中文无名,还有一些来自三星或联想的低端平板电脑)加密和解密速度很慢。

我们在我们的应用程序中使用了Android 23,我们能够确定某种级别,在这种级别之下,我们的应用程序根本不适合最终用户(他们必须等待太长时间才能显示内容)。很多平板电脑我们不得不排除在我们的应用程序中使用,但是,我们能够忍受它。

最近我们的一些依赖项开始需要更新版本的Android。例如,我们想切换到Facebook Core SDK,而不是完整的Facebook SDK以节省一些空间。但这取决于Android支持包v25,我们将无法构建它,因为proguard拒绝处理源。

因此决定将项目转移到更新的Android。除了它对我们的加密/解密机制的性能影响之外,它还是非常顺利。突然间,它慢得多。平板电脑我们认为“工作得足够好”非常慢。

TL; DR

我已经开始调查从Android 23迁移到Android 26期间发生的事情,这会导致AES加密/解密性能大幅下降。

我创建了一个应用程序,它可以作为一种基准。通过简单的改变:

  • compileSdkVersion 23->26
  • targetSdkVersion 23->26
  • compile 'com.android.support:appcompat-v7:VERSION' 23.4.0 -> 26.+

性能下降是巨大的。

以下是其中一款平板电脑的示例结果:

Android 23: 136959 B/s
Android 26: 34419 B/s

这几乎慢了4倍。我可以在我必须测试的所有设备上重现这些结果。当然,在新的高性能设备上它几乎看不到,但在旧设备上,它很明显。

我在网上搜索了有关此内容的任何细节,但我一无所获。我真的很感激有人能够对这个问题有所了解。

我真的希望我在某处犯了错误,但我找不到它。

对于加密/解密,我们使用SpongyCastle库。

我的Crypto Tester应用程序的源代码可在GitHub上找到:https://github.com/krstns/cryptoTester

有{23}配置的master分支和Android 26配置的master_26分支。

为了完整起见,我将在此粘贴用于解密的方法:

/**
 * Decrypt the given data with the given key
 *
 * @param data The data to decrypt
 * @return The decrypted bytes
 */
public static byte[] decrypt(byte[] data, byte[] key, byte[] iv) {
    if (key == null || iv == null) {
        throw new AssertionError("DECRYPT: Key or iv were not specified.");
    }

    // make sure key is AES256
    byte[] bookKeyData = new byte[32];
    byte[] outBuf;
    System.arraycopy(key, 0, bookKeyData, 0, key.length);

    try {
        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
        cipher.init(false, new ParametersWithIV(new KeyParameter(bookKeyData), iv));
        int outputSize = cipher.getOutputSize(data.length);
        outBuf = new byte[cipher.getOutputSize(outputSize)];
        int processed = cipher.processBytes(data, 0, data.length, outBuf, 0);
        if (processed < outputSize) {
            processed += cipher.doFinal(outBuf, processed);
        }
        return Arrays.copyOfRange(outBuf, 0, processed);

    } catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

哦,是的。我知道这是CBC,我知道为什么不应该使用等等。目前,它是故意的。这不是问题的主题,所以我们不要去那里。

2 个答案:

答案 0 :(得分:3)

您似乎直接使用SpongyCastle。 SpongyCastle是BouncyCastle(BC)的Android版本。然而,BC是加密算法和周围实用程序API的仅软件实现。

如果您真的想加快AES计算,那么您应该使用Java Security API,例如:使用javax.crypto.Cipher class。这将允许在支持它的平台上进行硬件加速和本机代码执行。通常,这将是所有平台,因为主要的加密功能是在较新的平台上使用OpenSSL库实现的。

一般情况下,建议只使用Bouncy Castle&#34;轻量级&#34;只要在提供的Cryptography 提供程序中没有所需的功能,API就会使用API​​(例如您正在使用的软件AES实现)。对于诸如AES / CBC之类的算法,这绝对是

目前,您的库依赖于Bouncy Castle实现的字节代码执行,这要慢得多。另请注意,Bouncy Castle不太喜欢调试环境,所以在测试性能时确保它没有延迟运行 - 如果可能的话没有调试器支持。

答案 1 :(得分:2)

我终于找到了解决方案。

当我尝试在SpongyCastle GitHub上创建一个问题时,我注意到有比1.54更新的版本......对于我之前没有对此进行调查,我很傻。

请注意,它在我的主项目中并没有立即发挥作用。加密/解密机制是库项目的一部分,然后包含在我的主项目中。请记住也要更新你的主项目,否则它仍然会很慢。

所以它对我有用:

  • 将海绵城堡版本更改为1.56
  • compileSdkVersion更改为26
  • buildToolsVersion更改为26.0.2
  • targetSdkVersion更改为26

在图书馆项目和主要项目中。