AES ускорение для Java

Я хочу зашифровать / расшифровать множество небольших (2-10 КБ) фрагментов данных. На данный момент производительность нормальная: на Core2Duo я получаю около 90 МБ / с AES256 (при использовании 2 потоков). Но мне может понадобиться улучшить это в будущем - или хотя бы уменьшить влияние на процессор.

  • Можно ли использовать выделенное аппаратное шифрование AES с Java (с использованием JCE или, возможно, другого API)?
  • Пользуется ли Java преимуществами специальных функций процессора (SSE5?!), если я получу лучший процессор?
  • Или есть более быстрые провайдеры JCE? (Я пробовал SunJCE и BouncyCastle - без большой разницы.)
  • Другие возможности?

5 ответов

Решение

JVM сама по себе не будет использовать специальные возможности ЦП при выполнении кода, который является шифрованием AES: распознавание некоторого кода как реализации AES выходит за рамки возможностей JIT-компилятора. Чтобы использовать специальное оборудование (например, "Padlock" на процессорах VIA или инструкции AES-NI на более новых процессорах Intel), в какой-то момент вы должны пройти через "собственный код".

Возможно, провайдер JCE мог бы сделать это для вас. Я не знаю ни одного легкодоступного JCE-провайдера, который включает в себя оптимизированный нативный код для AES (был проект под названием Apache JuiCE, но он, похоже, остановился, и я не знаю его состояния). Тем не менее, вполне возможно, что SunJCE сделает это в будущей версии (но с учетом того, что Oracle покупает Sun и из-за избыточного количества OpenJDK 7, неясно, когда будет выпущена следующая версия Java). Кроме того, укусите пулю и используйте собственный код самостоятельно. Нативный код вызывается через JNI, а для нативного кода AES популярной является реализация Брайана Гладмана. Когда вы получите более крупный и новый процессор с инструкцией AES-NI, замените этот собственный код на некоторый код, который знает об этих инструкциях, как описывает Intel.

Используя AES-128 вместо AES-256, вы получите повышение скорости на +40%. Взлом AES-128 в настоящее время находится за пределами технологической досягаемости человечества, и должен оставаться таковым в течение следующих нескольких десятилетий. Вам действительно нужен 256-битный ключ для AES?

На случай, если люди столкнутся с этим. JAVA 8 теперь использует AES-NI. Смотрите это: встроенные функции AES-NI включены по умолчанию?

Вы можете воспользоваться улучшенными скоростями AES, используя провайдера безопасности SunPKCS11 вместе с библиотекой mozilla-nss.

Настройка описана в

Простой поиск в Google позволит определить некоторых поставщиков JCE, которые заявляют об аппаратном ускорении Solaris Crypto Framework. Я слышал, что точка безубыточности составляет 4K (где при 4k его быстрее выполнять с помощью JVM-провайдеров Java).

Я мог бы взглянуть на использование реализации NSS, в нем могут быть некоторые оптимизации компилятора для вашей платформы (и вы, безусловно, можете собрать из исходного кода с их включенными); хотя я сам этим не пользовался. Большим преимуществом поставщика оборудования, вероятно, является тот факт, что ключи могут храниться на оборудовании таким образом, чтобы их можно было использовать, не подвергая их воздействию операционной системы.

Обновление: я, вероятно, должен упомянуть, что источник Keyczar имел некоторую полезную информацию (где-то в источнике или в окружающих документах) о сокращении накладных расходов при инициализации Шифра. Он также делает именно то, что вы хотите (см. Encrypter), и, кажется, реализует асинхронное шифрование (с использованием пула потоков).

Я бы также предложил использовать AES-128 вместо 256. Если код слабо связан и все еще существует в течение многих лет, которые требуются для того, чтобы AES-128 стал архаичным, я предполагаю, что будет гораздо проще обновить шифрование в тот момент (когда аппаратное обеспечение будет более мощным), чем пытаться оптимизировать производительность с помощью аппаратного обеспечения сейчас.

Конечно, это предполагает, что это слабо связано:D

Обычно этап, на который уходит больше времени, - это запуск KeyGenerator.

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // This step takes more time
KeyGenerator aesKey = keyGen.generateKey();

Я решил это путем создания пула KeyGenerator экземпляры до состояния сервера и повторное их использование только для генерации ключей

Другие вопросы по тегам