Вы можете перейти к TL, DR
У нас есть приложение, которое сильно зависит от шифрования и дешифрования AES. Мы хотим поддерживать как можно больше устройств, но некоторые из них (особенно дерьмовые планшеты, и я имею в виду не только китайские имена, но и некоторые недорогие планшеты от Samsung или Lenovo) просто замедляют шифрование и дешифрование.
Мы использовали Android 23 в нашем приложении, и нам удалось определить какой-то уровень, ниже которого наше приложение будет просто плохо работать для конечного пользователя (им придется слишком долго ждать появления контента). Было много таблеток, которые мы должны были исключить для использования с нашим приложением, но хорошо, мы смогли с этим справиться.
Недавно некоторые из наших зависимостей начали требовать более новую версию Android. Например, мы хотели перейти на Facebook Core SDK, а не на полный SDK Facebook, чтобы сэкономить место. Но это зависит от пакета поддержки 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
Там находится ветвь master
с конфигурацией Android 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;
}
О, и.. да. Я знаю, что это CBC, я знаю, почему его не следует использовать и т.д. В настоящее время это делается специально. Это не тема вопроса, поэтому не ходите туда.