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

Kry*_*ian 17 java encryption performance android 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
Run Code Online (Sandbox Code Playgroud)

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

我在网上搜索了有关此的任何细节,但我什么也没找到.我真的很感激有人能够对这个问题有所了解.

我真的希望我在某个地方犯了一个错误,但我找不到它.

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

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

masterAndroid 23配置的master_26分支和Android 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;
}
Run Code Online (Sandbox Code Playgroud)

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

Maa*_*wes 4

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

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

一般来说,当所需的功能在所提供的加密提供程序中不可用时,建议仅使用 Bouncy Castle“轻量级”API(例如您正在使用的软件 AES 实现)。对于 AES/CBC 等算法来说,情况绝对不是这样。

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