Статьи

Использование криптографии в приложениях Java

Этот пост описывает, как использовать архитектуру криптографии Java (JCA), которая позволяет использовать криптографические сервисы в ваших приложениях.

Услуги криптографической архитектуры Java

JCA предоставляет ряд криптографических сервисов, таких как дайджесты сообщений и подписи .

Эти сервисы доступны через специальные API-интерфейсы, такие как MessageDigest и Signature .

Криптографические сервисы абстрагируют разные алгоритмы. Например, для дайджестов вы можете использовать MD5 или SHA1 . Вы указываете алгоритм в качестве параметра для метода getInstance() криптографического класса обслуживания:

1
MessageDigest digest = MessageDigest.getInstance("MD5");

Вы найдете значение параметра для вашего алгоритма в документации имени стандартного алгоритма JCA.

Некоторые алгоритмы имеют параметры. Например, алгоритм для генерации пары секретный / открытый ключ будет принимать размер ключа в качестве параметра. Вы указываете параметр (ы), используя метод initialize() :

1
2
KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA");
generator.initialize(1024);

Если вы не initialize() метод initialize() , будет использовано какое-то значение по умолчанию, которое может быть, а может и не быть тем, что вы хотите.

К сожалению, API для инициализации не на 100% согласован между сервисами.

Например, класс Cipher использует init() с аргументом, указывающим шифрование или дешифрование, в то время как класс Signature использует initSign() для подписи и initVerify() для проверки.

Поставщики архитектуры криптографии Java

JCA сохраняет ваш код независимым от реализации конкретного криптографического алгоритма через систему провайдера .

Поставщики ранжируются в соответствии с порядком предпочтений, который настраивается (см. Ниже). Наилучшее предпочтение — 1, следующее наилучшее — 2 и т. Д. Порядок предпочтений позволяет JCA выбрать наилучшего доступного поставщика, реализующего данный алгоритм.

В качестве альтернативы вы можете указать конкретного поставщика во втором аргументе getInstance() :

1
Signature signature = Signature.getInstance("SHA1withDSA", "SUN");

JRE поставляется с группой поставщиков из Oracle по умолчанию. Однако из-за исторических ограничений на экспорт это не самые безопасные реализации. Чтобы получить доступ к более совершенным алгоритмам и ключам большего размера, установите файлы политик неограниченной юрисдикции расширения криптографии Java .

Обновление : обратите внимание, что приведенное выше утверждение верно для Oracle JRE. OpenJDK не имеет такого же ограничения .

Сделайте ваше использование криптографии настраиваемым

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

Если вы сделаете это, вы можете изменить криптографический алгоритм и / или реализацию без выпуска патча.

Это особенно ценно, когда становится доступной новая атака на (реализацию) алгоритма.

JCA упрощает настройку использования криптографии.

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

Также убедитесь, что вы храните свой код СУХОЙ и создаете экземпляры криптографических сервисов в одном месте.

Убедитесь, что запрошенный алгоритм и / или поставщик действительно доступны.

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

Обратите внимание, что Oracle рекомендует не указывать провайдера . Причины, которые они приводят, состоят в том, что не все поставщики могут быть доступны на всех платформах, и что указание поставщика может означать, что вы упускаете возможности оптимизации.

Вы должны сопоставить эти недостатки с риском быть уязвимым.

Развертывание конкретных поставщиков с известными характеристиками в вашем приложении может нейтрализовать недостатки, о которых упоминает Oracle.

Добавление поставщиков криптографических услуг

Система провайдеров является расширяемой, поэтому вы можете добавлять провайдеров.

Например, вы можете использовать Bouncy Castle с открытым исходным кодом или коммерческих поставщиков RSA BSAFE .

Чтобы добавить провайдера, вы должны убедиться, что его jar-файл доступен для приложения. Вы можете поместить это в classpath для этой цели.

Кроме того, вы можете сделать его установленным расширением , поместив его в каталог $JAVA_HOME/lib/ext , где $JAVA_HOME — это расположение вашего дистрибутива JDK / JRE.

Основное различие между этими двумя подходами состоит в том, что установленным расширениям по умолчанию предоставляются все разрешения , тогда как код на пути к классам — нет. Это важно, когда (часть) ваш код выполняется в песочнице .

Некоторые сервисы, такие как Cipher , требуют подписи файла провайдера.

Следующим шагом является регистрация провайдера в системе провайдера JCA. Самый простой способ — использовать Security.addProvider() :

1
Security.addProvider(new BouncyCastleProvider());

Вы также можете установить порядок предпочтений поставщика, используя метод Security.insertProviderAt() :

1
Security.insertProviderAt (new JsafeJCE(), 1);

Недостатком этого подхода является то, что он связывает ваш код с провайдером, поскольку вы должны импортировать класс провайдера. Это не может быть важной проблемой в модульной системе, такой как OSGi .

Еще одна вещь, на которую стоит обратить внимание, это то, что для кода требуется, чтобы SecurityPermission добавлял провайдера.

Поставщик также можно настроить как часть вашей среды с помощью статической регистрации, добавив запись в java.security свойств java.security (находится в $JAVA_HOME/jre/lib/security/java.security ):

1
2
security.provider.1=com.rsa.jsafe.provider.JsafeJCE
security.provider.2=sun.security.provider.Sun

Имена свойств в этом файле начинаются с security.provider. и заканчивается предпочтением провайдера. Значение свойства — это полное имя класса, реализующего Provider .

Реализация собственного провайдера криптографических услуг

Не делай этого . Вы ошибетесь и будете уязвимы для атак.

Использование провайдеров криптографических услуг

В документации для провайдера должно быть указано, какое имя провайдера следует использовать в качестве второго аргумента для getInstance() . Например, Bouncy Castle использует BC , а RSA BSAFE использует JsafeJCE .

У большинства провайдеров есть собственные API, а также соответствующие API JCA. Не используйте пользовательские API, так как это сделает невозможным настройку используемых алгоритмов и поставщиков.

Не все алгоритмы и реализации созданы равными

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

Например, некоторые организации разрешают только те алгоритмы и реализации, которые сертифицированы FIPS 140-2 или включены в список криптографических алгоритмов NSA Suite B.

Всегда убедитесь, что вы понимаете криптографические потребности вашего клиента.

Использование JCA в среде OSGi

Метод getInstance() является фабричным методом, который использует интерфейс поставщика услуг (SPI). Это проблематично в мире OSGi, поскольку OSGi нарушает допущение инфраструктуры SPI о наличии единого пути к классам.

Другая потенциальная проблема заключается в том, что JCA требует подписать несколько банок. Если эти jar-файлы не являются действительными OSGi-пакетами, вы не можете запустить их через bnd, чтобы сделать их так, поскольку это сделает подпись недействительной.

К счастью, вы можете убить обеих птиц одним камнем. Поместите jar-файл вашего провайдера в classpath вашей основной программы, то есть программы, которая запускает каркас OSGi.

Затем экспортируйте пакет поставщика из системного пакета OSGi, используя системное свойство org.osgi.framework.system.packages.extra . Это заставит системный пакет экспортировать этот пакет.

Теперь вы можете просто использовать Import-Package в пакете провайдера в ваших пакетах.

Существуют и другие варианты решения этих проблем, если вы не можете использовать вышеуказанное решение.

Ссылка: Использование криптографии в приложениях Java от нашего партнера по JCG Ремона Синнема в блоге по безопасной разработке программного обеспечения .