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

Обработка криптовых исключений

Этот, довольно простой, фрагмент кода довольно распространен при обработке шифрования/расшифровки на Java.

final Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
cipher.doFinal(*something*);

Только эти три строки, возможно, исключают шесть исключений, и я не уверен, что самый чистый (с точки зрения удобочитаемости кода) способ обработки. Попробуйте шесть предложений catch, которые действительно выглядят как запах для меня.

Есть ли микропаттерны или лучшие практики, которых я, очевидно, не хватает, работая с такими объектами?

ИЗМЕНИТЬ

Извините, я думаю, что не очень хорошо себя объяснил. Мой вопрос заключается не в том, чтобы избежать предложения try\catch, но если есть общий способ справиться с подобными ситуациями.

Исключения составляют

NoSuchPaddingException, NoSuchAlgorithmException
InvalidAlgorithmParameterException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException
4b9b3361

Ответ 1

Вы указали следующие исключения:

NoSuchPaddingException, NoSuchAlgorithmException
InvalidAlgorithmParameterException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException

Теперь все это GeneralSecurityException, так что было бы легко их поймать. Но, глядя на прецедент, вы, вероятно, не хотите этого делать.

Если вы посмотрите на причины исключений, вы обнаружите, что любое из этих исключений - за исключением последних двух - вызывается только при генерации реализации алгоритма или ключа. Я думаю, что разумно, что после того, как вы протестировали свое приложение, эти значения остаются более или менее статичными. Следовательно, было бы логично бросить - например, IllegalStateException. IllegalStateException - это исключение во время выполнения, которое вам не нужно бросать или ловить. Конечно, вы должны указать исключение безопасности как причину исключения.

Теперь последние два исключения, BadPaddingException и IllegalBlockSizeException. Они зависят от фактического зашифрованного текста, поэтому они зависят от ввода алгоритма. Теперь, как правило, вы всегда должны проверять целостность ввода до того, как будете его подавать в свой Cipher экземпляр, инициированный для дешифрования, например, сначала проверка контрольной суммы HMAC). Таким образом, в этом смысле вы все равно можете избавиться от исключения во время выполнения.

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

Вероятно, лучше всего использовать отдельные блоки try/catch для построения и инициализации Cipher и самого дешифрования. Вы также можете поймать исключения BadPaddingException и IllegalBlockSizeException перед обработкой GeneralSecurityException. Начиная с Java 7, вы также можете использовать инструкции с несколькими catch (например, catch(final BadPaddingException | IllegalBlockSizeException e)).


Наконец, некоторые примечания:

  • Остерегайтесь того, что исключение может быть выбрано для размеров ключей AES 192 бит и 256 бит, если неограниченные криптовальные файлы не установлены (проверьте сайт Oracle JavaSE для получения дополнительной информации); вы должны проверить, разрешен ли размер ключа при запуске приложения;
  • Оба BadPaddingException и IllegalBlockSizeException может быть создано из-за атак или потому, что данные не были полностью представлены;
  • BadPaddingException также может быть сброшен, если ключ неверен.

Ответ 2

Если вы хотите потерять определенную специфику, все исключения Crypto расширяют GeneralSecurityException, вы можете просто поймать это.

Ответ 3

Лучший способ справиться с этим - создать исключение бизнес-класса (исключение MyModuleException или что-то еще), а затем восстановить это исключение, добавляя исключения Crypto, чтобы вызвать часть. Таким образом, ваш метод будет генерировать только одно исключение, а не шесть, что было бы намного проще управлять в других слоях вашего приложения.

public void myMethod(...) throws MyModuleException {
  try {
    final Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, key, iv);
    cipher.doFinal(*something*);
  } catch(Crypto1Ex ex){
    throw new MyModuleException("something is wrong", ex); //ex added, so it is not lost and visible in stacktraceses
  } catch(Crypto1Ex ex){
    throw new MyModuleException("something is wrong", ex);
  } //etc.
}

В Java 7 вы можете справиться с этим еще проще (см. http://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html)