Java crypto, сбросить IV возможно для повышения производительности?

1

Я создаю шифровальный шифр следующим образом (в Scala, используя bouncy-castle)

  def encryptCipher(secret:SecretKeySpec, iv:IvParameterSpec):Cipher = {
    val e = Cipher.getInstance("AES/GCM/NoPadding")
    e.init(Cipher.ENCRYPT_MODE, secret, iv)
  }

Вы видите, что медленная операция генерации ключевой спецификации уже обрабатывается. Однако вызов init для каждого сообщения слишком медленный.
В настоящее время я обрабатываю 50K сообщений, а вызов метода init добавляет почти 4 секунды.

Есть ли способ повторно инициализировать новый IV, который не так интенсивен?

  • 0
    Что Javadocs говорят об этом? Кажется, они полностью отвечают на ваш вопрос.
  • 0
    Конечно, мне было интересно, есть ли лучший подход. Между прочим, я обнаружил значительную выгоду от перехода с Bouncy Castle AES / GCM на Java AES / CBC
Показать ещё 1 комментарий
Теги:
encryption
performance

1 ответ

1
Лучший ответ

Там нет стандартного способа сделать это в стандартной библиотеке, но есть хороший обходной путь, если вы используете AES:

Цель IV - исключить возможность того, что одни и те же простые тексты шифруются в одни и те же шифрованные тексты.

Вы можете просто "обновить" (как в Cipher.update(byte[])) со случайным блочным байтовым массивом до шифрования (и с тем же блоком при расшифровке). Это почти точно так же, как с использованием того же случайного блока, что и IV.

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

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecureRandom secureRandom = new SecureRandom();

byte[] keyBytes = new byte[16];
secureRandom.nextBytes(keyBytes);
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

byte[] plain = new byte[256];
secureRandom.nextBytes(plain);

// first init using random IV (save it for later)
cipher.init(Cipher.ENCRYPT_MODE, key, secureRandom);
byte[] realIv = cipher.getIV();
byte[] expected = cipher.doFinal(plain);

// now init using dummy IV and encrypt with real IV prefix
IvParameterSpec nullIv = new IvParameterSpec(new byte[16]);
cipher.init(Cipher.ENCRYPT_MODE, key, nullIv);
// calculate equivalent iv
Cipher equivalentIvAsFirstBlock = Cipher.getInstance("AES/CBC/NoPadding");
equivalentIvAsFirstBlock.init(Cipher.DECRYPT_MODE, key, nullIv);
byte[] equivalentIv = equivalentIvAsFirstBlock.doFinal(realIv);

cipher.update(equivalentIv);
byte[] result = cipher.doFinal(plain);
System.out.println(Arrays.equals(expected, result));

Часть расшифровки проще, потому что результат блочного дешифрования XORed с предыдущим зашифрованным текстом (см. Режим работы блочного шифрования), вам просто нужно добавить реальный IV в шифрованный текст и затем его бросить:

// Encrypt as before

IvParameterSpec nullIv = new IvParameterSpec(new byte[16]);
cipher.init(Cipher.DECRYPT_MODE, key, nullIv);

cipher.update(realIv);
byte[] result = cipher.doFinal(encrypted);
// result.length == plain.length + 16
// just throw away the first block

Ещё вопросы

Сообщество Overcoder
Наверх
Меню