Подтвердить что ты не робот

Почему шифрование/дешифрование AES более чем на 3 раза медленнее на Android 24+?

Вы можете перейти к 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, я знаю, почему его не следует использовать и т.д. В настоящее время это делается специально. Это не тема вопроса, поэтому не ходите туда.

4b9b3361

Ответ 1

Вы, кажется, используете SpongyCastle напрямую. SpongyCastle - это Android-версия BouncyCastle (BC). BC, однако, представляет собой программную реализацию только криптографических алгоритмов и окружающих API-интерфейсов.

Если вы действительно хотите ускорить вычисления AES, вы должны использовать API безопасности Java, например, используя javax.crypto.Cipher класс. Это позволит ускорить аппаратное ускорение и выполнить собственный код на поддерживающих его платформах. Обычно это будут все платформы, поскольку основные функции криптографии реализованы с использованием библиотек OpenSSL на новых платформах.

Как правило, рекомендуется использовать только "облегченный" API Bouncy Castle (например, используемые вами реализации AES программного обеспечения), когда требуемые функции недоступны в рамках предоставленных поставщиков криптографии. Это определенно не случай для алгоритмов, таких как AES/CBC.

В настоящее время ваша библиотека зависит от выполнения байтового кода реализации Bouncy Castle, которая намного медленнее. Также обратите внимание, что Bouncy Castle не очень любит отладочную среду, поэтому убедитесь, что она работает без задержек при тестировании производительности - если возможно, без поддержки отладчика.

Ответ 2

Наконец-то я нашел решение.

Когда я попытался создать проблему на SpongyCastle GitHub, я заметил, что есть более новые версии, чем 1.54... Ну, глупо мне, чтобы не исследовать это раньше.

Просто осторожное слово, это не сработало сразу в моем основном проекте. Механизм шифрования/дешифрования является частью проекта библиотеки, который затем включен в мой основной проект. Не забудьте также обновить свой основной проект, иначе он все равно будет очень медленным.

Итак, это сработало для меня после:

  • изменение версии шпоночного замка на 1.56
  • изменение compileSdkVersion на 26
  • изменение buildToolsVersion на 26.0.2
  • изменение targetSdkVersion на 26

как в проекте библиотеки, так и в главном проекте.