You can skip to TL;DR
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.
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.
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.
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.
TL;DR
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.
I've created an app, which works as kind of a benchmark. By making a simple change:
compileSdkVersion 23->26
targetSdkVersion 23->26
compile 'com.android.support:appcompat-v7:VERSION' 23.4.0 -> 26.+
the performance drop is huge.
Here's an example result from one of the tablets:
Android 23: 136959 B/s
Android 26: 34419 B/s
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.
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.
I really hope I have made a mistake somewhere, but I wasn't able to find it.
For encryption/decryption, we use the SpongyCastle library.
The sources of my Crypto Tester app are available on GitHub: https://github.com/krstns/cryptoTester
There's the master
branch with Android 23 configuration and master_26
branch with Android 26 configuration.
For the sake of completeness, I will paste here the method which is used for decryption:
/**
* 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;
}
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.
Bookmark this question. Show activity on this post. Fun fact: when using AES-NI for accelerating AES, decryption is actually slower because an additional instruction, AESIMC , must be used every round.
With the right quantum computer, AES-128 would take about 2.61*10^12 years to crack, while AES-256 would take 2.29*10^32 years. For reference, the universe is currently about 1.38×10^10 years old, so cracking AES-128 with a quantum computer would take about 200 times longer than the universe has existed.
yes, it's slower, for sure. How much slower? That depends a lot on how much hardware help the operation is getting, CPUs can accelerate the process if all the ducks are in a row, so results can vary quite a bit. You will need to test in your environment to tell how fast it will be in your environment.
AES is a symmetric encryption, and is the same speed whether encrypting or decrypting.
You seem to be using SpongyCastle directly. SpongyCastle is the Android version of BouncyCastle (BC). BC however is a software only implementation of cryptographic algorithms and surrounding utility API's.
If you really want to speed up AES calculations you should be using the Java Security API instead, e.g. using the javax.crypto.Cipher
class. This will allow hardware acceleration and native code execution on platforms that support it. Generally this will be all platforms as the main crypto functionality is implemented using OpenSSL libraries on the newer platforms.
Generally it is recommended to only use the Bouncy Castle "lightweight" API's (such as the software AES implementations you are using) whenever the required functionality is not available within the provided Cryptography providers. This is definitely not the case for algorithms such as AES/CBC.
Currently your library depends upon the byte code execution of the Bouncy Castle implementation, which is much slower. Note also that Bouncy Castle doesn't like debugging environments much, so make sure it runs without delays when testing the performance - if possible without debugger support.
I have finally found a solution.
When I tried to create an issue on SpongyCastle GitHub I have noticed there are newer releases than 1.54
... Well silly me for not investigating this earlier.
Just a word of caution, it didn't work straight away in my main project. The encryption/decryption mechanism is part of a library project which is then included in my main project. Please remember to also update your main project, or else it will still be very slow.
So it worked for me after:
1.56
compileSdkVersion
to 26
buildToolsVersion
to 26.0.2
targetSdkVersion
to 26
in both, library project and main project.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With