Why is AES encryption / decryption more than 3x slower on Android 24+? : <p><strong>You can skip to TL;DR</strong></p>

<p>We have an app, which strongly relies on AES encryption and decryption. We want to support as many devices as possible, but some of them (especially crappy tablets and I don't only mean Chinese no-names, but also some low-end tablets from Samsung or Lenovo) are simply slow to encrypt and decrypt.</p>

<p>We have used Android 23 in our app and we were able to identify some kind of level below which our app will simply not work well for the end user (they would have to wait too long for the content to appear). It was a lot of tablets that we had to rule out for use with our app, but well, we were able to live with that.</p>

<p>Recently some of our dependencies started to require a newer version of Android. For example, we wanted to switch to Facebook Core SDK, instead of the full Facebook SDK to save some space. But it depends on the Android support package v25 and we won't be able to build it because proguard refuses to process the sources.</p>

<p>So a decision was made to move the project to a newer Android. It went quite smooth, apart from the performance impact it had on our encryption/decryption mechanism. Suddenly it was MUCH slower. Tablets we would rate as "working well enough" were extremely slow. </p>

<p><strong>TL;DR</strong></p>

<p>I've started to investigate what happened during our migration from Android 23 to Android 26, which would cause a HUGE performance drop in AES encryption/decryption.</p>

<p>I've created an app, which works as kind of a benchmark. By making a simple change:</p>

<ul>
<li><code>compileSdkVersion 23-&gt;26</code></li>
<li><code>targetSdkVersion 23-&gt;26</code></li>
<li><code>compile 'com.android.support:appcompat-v7:VERSION' 23.4.0 -&gt; 26.+</code></li>
</ul>

<p>the performance drop is huge.</p>

<p>Here's an example result from one of the tablets:</p>

<pre><code>Android 23: 136959 B/s
Android 26: 34419 B/s
</code></pre>

<p>That's almost 4x slower. I can reproduce these results on all of the devices I have to test. Sure, on new, high-performance devices it's barely visible, but on old devices, it's clear.</p>

<p>I've searched the web for any details on this, but I have found nothing. I would really be grateful for someone to shed some light on this issue.</p>

<p>I really hope I have made a mistake somewhere, but I wasn't able to find it.</p>

<p>For encryption/decryption, we use the SpongyCastle library.</p>

<p>The sources of my Crypto Tester app are available on GitHub: <a href="https://github.com/krstns/cryptoTester" rel="noreferrer">https://github.com/krstns/cryptoTester</a></p>

<p>There's the <code>master</code> branch with Android 23 configuration and <code>master_26</code> branch with Android 26 configuration. </p>

<p>For the sake of completeness, I will paste here the method which is used for decryption:</p>

<pre><code>/**
 * 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 &lt; outputSize) {
            processed += cipher.doFinal(outBuf, processed);
        }
        return Arrays.copyOfRange(outBuf, 0, processed);

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

    return null;
}
</code></pre>

<p>Oh and.. yes. I am aware this is CBC, I am aware of why it should not be used etc. Currently, it is done on purpose. This is not the topic of the question, so let's not go there.</p>
