Spec-Zone .ru
спецификации, руководства, описания, API
Содержание документации

Архитектура Криптографии Java™
(JCA) Справочник


Введение

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

JCA является главной частью платформы, и содержит архитектуру "провайдера" и ряд API для цифровых подписей, обзоры сообщения (hashs), сертификаты и проверка допустимости сертификата, шифрование (симметричный/асимметричный блок/поточные шифры), генерация ключей и управление, и безопасная генерация случайных чисел, чтобы назвать некоторых. Эти API позволяют разработчикам легко интегрировать безопасность в свой код программы. Архитектура была разработана вокруг следующих принципов:

  1. Независимость реализации
    Приложения не должны реализовать алгоритмы безопасности. Скорее они могут запросить службы безопасности с платформы Java. Службы безопасности реализуются в провайдерах (см. ниже), которые включаются в платформу Java через стандартный интерфейс. Приложение может положиться на многократных независимых провайдеров для функциональности безопасности.
  2. Функциональная совместимость реализации
    Провайдеры являются взаимодействующими через приложения. Определенно, приложение не связывается с определенным провайдером, и провайдер не связывается с определенным приложением.
  3. Расширяемость алгоритма
    Платформа Java включает много встроенных провайдеров, которые реализуют основной набор служб безопасности, которые широко используются сегодня. Однако, некоторые приложения могут положиться на появляющиеся стандарты, еще реализованные, или на собственных службах. Платформа Java поддерживает установку пользовательских провайдеров, которые реализуют такие службы.

Другие криптографические коммуникационные библиотеки, доступные в JDK, используют архитектуру провайдера JCA, но описываются в другом месте. Расширение Защищенного сокета Java™ (JSSE) обеспечивает доступ к Уровню защищенных сокетов (SSL) и Безопасность Транспортного уровня (TLS) реализации. Java Универсальные Службы безопасности (JGSS) (через Kerberos) API, и Простой Уровень Аутентификации и Безопасности (SASL) может также использоваться для того, чтобы надежно обмениваться сообщениями между связывающимися приложениями.

Примечания по Терминологии


ПРЕДУПРЕЖДЕНИЕ: JCA облегчает включать средства защиты в Ваше приложение. Однако, этот документ не касается теории безопасности/криптографии вне элементарного введения в понятия, необходимые, чтобы обсудить API. Этот документ также не касается сильных мест/слабых мест определенных алгоритмов, не делает он покрывает проект протокола. Криптография является усовершенствованной темой, и нужно консультироваться с телом, предпочтительно недавним, ссылка, чтобы лучше всего использовать эти инструменты.

Следует всегда понимать то, что Вы делаете и почему: DO НЕ просто копирует случайный код и ожидает, что это полностью решит Ваш сценарий использования. Много приложений были развернуты, которые содержат существенную безопасность или проблемы производительности, потому что неправильный инструмент или алгоритм были выбраны.


Принципы разработки

JCA был разработан вокруг этих принципов:

Независимость реализации и независимость алгоритма дополнительны; можно использовать криптографические службы, такие как цифровые подписи и передать обзоры, не волнуясь о деталях реализации или даже алгоритмах, которые формируют основание для этих понятий. В то время как полная независимость алгоритма не возможна, JCA обеспечивает стандартизированные, специфичные для алгоритма API. Когда независимость реализации не является требуемой, JCA позволяет разработчикам указывать на определенную реализацию.

Независимость алгоритма достигается, определяя типы криптографических "механизмов" (службы), и определяя классы, которые обеспечивают функциональность этих криптографических механизмов. Эти классы вызывают классами механизма, и примеры MessageDigest, Signature, KeyFactory, KeyPairGenerator, и Cipher классы.

Независимость реализации достигается, используя "провайдера" на основе архитектура. Провайдер криптографических служб термина (CSP) (используемый взаимозаменяемо с "провайдером" в этом документе) обращается к пакету или набору пакетов, которые реализуют один или более криптографические службы, такие как алгоритмы цифровой подписи, алгоритмы обзора сообщения, и ключевые службы преобразования. Программа может просто запросить определенный тип объекта (такого как a Signature объект), реализация определенной службы (такой как алгоритм подписи DSA) и получают реализацию от одного из установленных провайдеров. При желании программа может вместо этого запросить реализацию от определенного провайдера. Провайдеры могут быть обновлены прозрачно к приложению, например когда более быстрые или более безопасные версии доступны.

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

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

Архитектура

Провайдеры криптографических служб

java.security.Provider основной class для всех поставщиков систем обеспечения безопасности. Каждый CSP содержит экземпляр этого class, который содержит имя провайдера и перечисляет все службы/алгоритмы безопасности, которые это реализует. Когда экземпляр определенного алгоритма необходим, платформа JCA консультируется с базой данных провайдера, и если подходящее соответствие находится, экземпляр создается.

Провайдеры содержат пакет (или ряд пакетов) что реализации бетона предоставления для рекламируемых криптографических алгоритмов. У каждой установки JDK есть один или более провайдеров, установленных и сконфигурированных по умолчанию. Дополнительные провайдеры могут быть добавлены статически или динамически (см. классы Провайдера и Безопасности). Клиенты могут сконфигурировать свою среду выполнения, чтобы определить привилегированный порядок провайдера. Привилегированный порядок является порядком, в котором провайдеры ищутся требуемые службы, когда никакого определенного провайдера не требуют.

Чтобы использовать JCA, приложение просто запрашивает определенный тип объекта (такого как a MessageDigest) и определенный алгоритм или служба (такая как алгоритм "MD5"), и получают реализацию от одного из установленных провайдеров. Альтернативно, программа может запросить объекты от определенного провайдера. Каждому провайдеру использовали имя, чтобы обратиться к этому.

    md = MessageDigest.getInstance("MD5");
    md = MessageDigest.getInstance("MD5", "ProviderC");

Следующее число иллюстрирует запрос реализации обзора сообщения "MD5". Шоу числа три различных провайдера, которые реализуют различные алгоритмы обзора сообщения ("SHA 1", "MD5", "SHA 256", и "SHA 512"). Провайдеры упорядочиваются предпочтением слева направо (1-3). На первой иллюстрации приложение запрашивает реализацию алгоритма MD5, не определяя имя провайдера. Провайдеры ищутся в привилегированном порядке и реализации от первого провайдера, предоставляющего, что определенный алгоритм, ProviderB, возвращается. Во втором числе приложение запрашивает реализацию алгоритма MD5 от определенного провайдера, ProviderC. На сей раз реализация от ProviderC возвращается, даже при том, что провайдер с более высоким привилегированным порядком, ProviderB, также предоставляет реализацию MD5.

Общий Краткий обзор Архитектуры JCA

Криптографические реализации на солнце JDK распределяются через несколько различных провайдеров (Sun, SunJSSE, SunJCE, SunRsaSign) прежде всего по историческим причинам, но до меньшей степени типом функциональности и алгоритмов они обеспечивают. Другие среды выполнения Java, возможно, не обязательно содержат этих провайдеров Sun, таким образом, приложения не должны запросить специфичную для провайдера реализацию, если не известно, что определенный провайдер будет доступен.

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

Эта архитектура также облегчает для конечных пользователей добавлять дополнительных провайдеров. Много сторонних реализаций провайдера уже доступны. См. Provider Класс для получения дополнительной информации о том, как провайдеры пишутся, установил, и зарегистрировался.

Как Провайдеры Фактически Реализуются

Как отмечалось ранее независимость алгоритма достигается, определяя универсальный высокоуровневый Прикладной программный интерфейс (API) что все использование приложений, чтобы получить доступ к типу службы. Независимость реализации достигается при наличии всех реализаций провайдера, соответствуют четко определенным интерфейсам. Экземпляры классов механизма таким образом "поддерживаются" классами реализации, у которых есть те же самые сигнатуры методов. Вызовы приложения направляются через механизм class и поставляются базовой реализации поддержки. Реализация обрабатывает запрос, и возвратите надлежащие результаты.

Методы API приложения в каждом механизме, class направляется к реализациям провайдера через классы, которые реализуют соответствующий Интерфейс Поставщика услуг (SPI). Таким образом, для каждого механизма class есть соответствующий абстрактный SPI class, который определяет методы, которые должен реализовать алгоритм каждого провайдера криптографических служб. Имя каждого SPI class является тем же самым как тем из соответствующего механизма class, сопровождаемый Spi. Например, Signature механизм class обеспечивает доступ к функциональности алгоритма цифровой подписи. Фактическая реализация провайдера предоставляется в подклассе SignatureSpi. Приложения вызывают механизм class' методы API, которые поочередно вызывают методы SPI в фактической реализации.

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

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

Чтобы сделать это более четким, рассмотрите следующий код и иллюстрацию:

    import javax.crypto.*;

    Cipher c = Cipher.getInstance("AES");
    c.init(ENCRYPT_MODE, key);
Краткий обзор Архитектуры провайдера

Здесь приложение хочет "AES" javax.crypto.Cipher экземпляр, и не заботится, какой провайдер используется. Приложение вызывает getInstance() методы фабрики Cipher class механизма, который поочередно просит, чтобы платформа JCA нашла первый экземпляр провайдера, который поддерживает "AES". Платформа консультируется с каждым установленным провайдером, и получает экземпляр провайдера Provider class. (Вспомните что Provider class является базой данных доступных алгоритмов.) Платформа ищет каждого провайдера, наконец находя подходящую запись в CSP3. Эта база данных точки входа к реализации class com.foo.AESCipher который расширяется CipherSpi, и является таким образом подходящим для использования Cipher механизм class. Экземпляр com.foo.AESCipher создается, и инкапсулируется в недавно создаваемом экземпляре javax.crypto.Cipher, который возвращается к приложению. Когда приложение теперь делает init() работа на Cipher экземпляр, Cipher механизм class направляет запрос в соответствие engineInit() поддержка метода в com.foo.AESCipher class.

Приложение списки Стандартные имена определяется для среды Java. Другие сторонние провайдеры могут определить свои собственные реализации этих служб, или даже дополнительных служб.

Управление ключами

База данных, названная "keystore", может использоваться, чтобы управлять репозитарием ключей и сертификатов. Keystores доступны приложениям, которые нуждаются в данных для аутентификации, шифрования, или подписания целей.

Приложения могут получить доступ к keystore через реализацию KeyStore class, который находится в java.security пакет. Значение по умолчанию KeyStore реализация обеспечивается Sun Microsystems. Это реализует keystore как файл, используя собственный тип keystore (формат), названный "jks". Другие форматы keystore доступны, таковы как "jceks", который является альтернативным собственным форматом keystore с намного более сильным шифрованием чем "jks", и "pkcs12", который основан на RSA PKCS12 Стандарт Синтаксиса Exchange Персональных данных.

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

См. раздел управления ключами для получения дополнительной информации.

Понятия JCA

Этот раздел представляет главные API JCA.

Классы механизма и Алгоритмы

Механизм class обеспечивает интерфейс для определенного типа криптографической службы, независимой от определенного криптографического алгоритма или провайдера. Механизмы любой обеспечивает:

Следующие классы механизма доступны:

ОТМЕТЬТЕ: генератор создает объекты с совершенно новым содержанием, тогда как фабрика создает объекты из существующего материала (например, кодирование).

Базовые Классы и Интерфейсы

Этот раздел обсуждает базовые классы и интерфейсы, обеспеченные в JCA:

Руководство покроет самые полезные высокоуровневые классы сначала (Provider, Security, SecureRandom, MessageDigest, Signature, Cipher, и Mac), затем копайтесь в различных классах поддержки. Пока, достаточно просто сказать, что Ключи (общедоступный, частный, и секретный) сгенерированы и представлены различными классами JCA, и используются высокоуровневыми классами в качестве части их работы.

Этот раздел показывает подписи основных методов в каждом class и интерфейсе. Примеры для некоторых из этих классов (MessageDigest, Signature, KeyPairGenerator, SecureRandom, KeyFactory, и ключевые классы спецификации), предоставляются в соответствующих разделах В качестве примера.

Полная справочная документация для соответствующих пакетов API Безопасности может быть найдена в сводках пакета:

Provider Класс

Термин "Провайдер криптографических служб" (используемый взаимозаменяемо с "провайдером" в этом документе) относится к пакету или набору пакетов, которые предоставляют конкретную реализацию подмножества функций криптографии API Безопасности JDK. Provider class является интерфейсом к такому пакету или набору пакетов. У этого есть методы для того, чтобы получить доступ к имени провайдера, номеру версии, и другой информации. Пожалуйста, отметьте это в дополнение к регистрирующимся реализациям криптографических служб, Provider class может также использоваться, чтобы зарегистрировать реализации других служб безопасности, которые могли бы быть определены как часть API Безопасности JDK или одно из его расширений.

Чтобы предоставить реализации криптографических служб, объект (например, группа разработки) пишет, что реализация кодирует, и создает подкласс Provider class. Конструктор Provider разделите на подклассы устанавливает значения различных свойств; API Безопасности JDK использует эти значения, чтобы искать службы, которые реализует провайдер. Другими словами подкласс определяет имена классов, реализовывая службы.

Провайдер class и реализация провайдера

Есть несколько типов служб, которые могут быть реализованы пакетами провайдера; для получения дополнительной информации см. Классы Механизма и Алгоритмы.

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

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

ОТМЕТЬТЕ: Для получения информации о реализации провайдера см. руководство, Как Реализовать Провайдера для Архитектуры Криптографии Java.

Как Реализации Провайдера Требуют и Предоставляются

Для каждого механизма class в API экземпляр реализации требуют и инстанцируется, вызывая один из getInstance методы на механизме class, определяя имя требуемого алгоритма и, дополнительно, имя провайдера (или Provider class), чья реализация требуется.
static EngineClassName getInstance(String algorithm)
    throws NoSuchAlgorithmException

static EngineClassName getInstance(String algorithm, String provider)
    throws NoSuchAlgorithmException, NoSuchProviderException

static EngineClassName getInstance(String algorithm, Provider provider)
    throws NoSuchAlgorithmException
где EngineClassName является требуемым типом механизма (MessageDigest/Cipher/etc). Например:
    MessageDigest md = MessageDigest.getInstance("MD5");
    KeyAgreement ka = KeyAgreement.getInstance("DH", "SunJCE");
возвратите экземпляр MessageDigest "MD5" и "DH" объекты KeyAgreement, соответственно.

Приложение A содержит список имен, которые были стандартизированы для использования со средой Java. Некоторые провайдеры могут хотеть также включать имена псевдонима, которые также обращаются к тому же самому алгоритму. Например, "SHA 1" алгоритм мог бы упоминаться как "SHA1". Приложения должны использовать стандартные имена вместо псевдонима, как не, все провайдеры могут исказить имена алгоритма таким же образом.

ОТМЕТЬТЕ: имя алгоритма не является чувствительным к регистру. Например, все следующие вызовы эквивалентны:
MessageDigest.getInstance("SHA-1")
MessageDigest.getInstance("sha-1")
MessageDigest.getInstance("sHa-1")

Если никакой провайдер не определяется, getInstance ищет зарегистрированных провайдеров реализацию требуемой криптографической службы, связанной с именованным алгоритмом. В любой данной виртуальной машине Java (JVM) провайдеры устанавливаются в данном привилегированном порядке, порядке, в котором ищется список провайдера, если определенного провайдера не требуют. Например, предположите, что есть два провайдера, установленные в JVM, PROVIDER_1 и PROVIDER_2. Предположите что:

Теперь давайте смотреть на три сценария:
  1. Если мы ищем реализацию MD5. Оба провайдера предоставляют такую реализацию. PROVIDER_1 реализация возвращается с тех пор PROVIDER_1 имеет самый высокий приоритет и ищется сначала.
  2. Если мы ищем алгоритм подписи MD5withRSA, PROVIDER_1 сначала ищется это. Никакая реализация не находится, таким образом, PROVIDER_2 ищется. Так как реализация находится, она возвращается.
  3. Предположите, что мы ищем алгоритм подписи SHA1withRSA. Так как никакой установленный провайдер не реализует это, a NoSuchAlgorithmException бросается.

getInstance методы, которые включают параметр провайдера, для разработчиков, которые хотят определить, от какого провайдера они хотят алгоритм. Федеральное агентство, например, будет хотеть использовать реализацию провайдера, которая получила федеральную сертификацию. Давайте предполагать что реализация SHA1withDSA от PROVIDER_1 не получил такую сертификацию, в то время как реализация DSA PROVIDER_2 получил это.

У программы федерального агентства тогда был бы следующий вызов, определяя PROVIDER_2 так как у этого есть сертифицированная реализация:

Signature dsa = Signature.getInstance("SHA1withDSA", "PROVIDER_2");

В этом случае, если PROVIDER_2 не был установлен, a NoSuchProviderException был бы брошен, даже если другой установленный провайдер реализует алгоритм, который требуют.

У программы также есть опция получения списка всех установленных провайдеров (использующий getProviders метод в Security class) и выбор того от списка.

ОТМЕТЬТЕ: приложения Общего назначения не ДОЛЖНЫ запросить криптографические службы от определенных провайдеров. Иначе, приложения связываются к определенным провайдерам, которые, возможно, не доступны на других реализациях Java. Они также не могли бы быть в состоянии использовать в своих интересах доступных оптимизированных провайдеров (например аппаратные акселераторы через PKCS11 или собственные реализации ОС, такие как MSCAPI Microsoft), у которых есть более высокий привилегированный порядок чем определенный требуемый провайдер.

Установка Провайдеров

Чтобы использоваться, криптографический провайдер должен сначала быть установлен, затем зарегистрировался или статически или динамически. Есть множество провайдеров Sun, поставленных с этим выпуском (SUN, SunJCE, SunJSSE, SunRsaSign, и т.д.), которые уже устанавливаются и регистрируются. Следующие разделы описывают, как установить и зарегистрировать дополнительных провайдеров.

Установка Классов Провайдера

Есть два возможных способа установить классы провайдера:

  1. На нормальном пути к классу Java

    Поместите zip или файл JAR, содержащий классы куда угодно в Вашем пути к классу. Некоторые (Шифры) типов алгоритмов требуют, чтобы провайдер был подписанным файлом Фляги.

  2. Как Устанавливал/Связывал Расширение

    Провайдера будут считать установленным расширением, если он будет помещен в стандартный каталог расширения. В JDK Sun, который был бы расположен в:

        <java-home>/lib/ext                   [Unix]
        <java-home>\lib\ext                   [Windows] 
    
    Здесь <java-home> ссылается на каталог, где программное обеспечение времени выполнения устанавливается, который является высокоуровневым каталогом Среды выполнения Java™ (JRE) или каталогом jre в программном обеспечении JDK Java™. Например, если у Вас есть JDK 6 установленный на Солярисе в названном каталоге /home/user1/JDK1.6.0, или на Microsoft Windows в каталоге называется C:\Java\JDK1.6.0, тогда Вы должны установить файл JAR в следующем каталоге:
        /home/user1/JDK1.6.0/jre/lib/ext      [Unix]
        C:\JDK1.6.0\jre\lib\ext               [Windows]
    

    Точно так же, если у Вас есть JRE 6 установленный на Солярисе в названном каталоге /home/user1/jre1.6.0, или на Microsoft Windows в каталоге называется C:\jre1.6.0, Вы должны установить файл JAR в следующем каталоге:

          /home/user1/jre1.6.0/lib/ext          [Unix]
          C:\jre1.6.0\lib\ext                   [Windows]
    
    Для получения дополнительной информации по тому, как развернуть расширение, см., Как расширение развертывается?

Регистрация Провайдера

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

Статическая Регистрация
Конфигурационный файл располагается в следующем расположении:
    <java-home>/lib/security/java.security     [Unix]
    <java-home>\lib\security\java.security     [Windows] 
Для каждого зарегистрированного провайдера у этого файла должен быть оператор следующей формы:
    security.provider.n=masterClassName

Это объявляет провайдера, и определяет его привилегированный порядок n. Привилегированный порядок является порядком, в котором провайдеры ищутся требуемые алгоритмы (когда никакого определенного провайдера не требуют). Порядок на основе 1: 1 является самым привилегированным, сопровождается 2, и так далее.

masterClassName должен определить полностью определенное имя основного class провайдера. Документация провайдера определит свой основной class. Этот class всегда является подклассом Provider class. Конструктор подкласса устанавливает значения различных свойств, которые требуются для API Криптографии Java искать алгоритмы или другие средства реализации провайдера.

JDK прибывает стандарт с автоматически установленными и сконфигурированными провайдерами, такими как "SUN" и "SunJCE". Основной class провайдера "SUN" SUN class в sun.security.provider пакет, и соответствующая java.security запись файла следующие:

    security.provider.5=sun.security.provider.Sun

Чтобы использовать другого провайдера JCA, добавьте строку, ссылающуюся на альтернативного провайдера, определите привилегированный порядок (вносящий соответствующие корректировки в заказы других провайдеров, если нужно).

Предположите, что основной class провайдера CompanyX com.companyx.provider.ProviderX, и это требуется сконфигурировать этого провайдера как наиболее предпочтенное восьмое. Чтобы сделать так, Вы добавили бы следующую строку к java.security файл:

    security.provider.8=com.companyx.provider.ProviderX
Динамическая Регистрация
Чтобы зарегистрировать провайдеров динамически, приложения вызывают любого addProvider или insertProviderAt метод в Security class. Этот тип регистрации не является персистентным через экземпляры VM, и может только быть сделан программами, которым "доверяют", с соответствующим полномочием. См. Безопасность.

Установка Полномочий Провайдера

Всякий раз, когда провайдеры шифрования используются (то есть, те, которые предоставляют реализации Шифра, KeyAgreement, KeyGenerator, Mac, или SecretKeyFactory), и провайдер не является установленным расширением, которое Полномочия, возможно, должны быть предоставлены для того, когда апплеты или приложения, используя JCA выполняются, в то время как менеджер безопасности устанавливается. обычно есть менеджер безопасности, установленный всякий раз, когда апплет работает, и менеджер безопасности может быть установлен для приложения или через код в приложении непосредственно или через параметр командной строки. Полномочия не должны предоставить установленным расширениям, так как системный конфигурационный файл политики значения по умолчанию предоставляет все полномочия установленным расширениям (то есть, установленный в каталоге расширений).

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

Например, демонстрационное предоставление оператора полномочия к провайдеру, имя которого является "MyJCE" и чей код находится в myjce_provider.jar появляется ниже. Такой оператор мог появиться в файле политики. В этом примере, myjce_provider.jar файл, как предполагается, находится в /localWork каталог.

    grant codeBase "file:/localWork/myjce_provider.jar" {
        permission java.lang.RuntimePermission "getProtectionDomain";
        permission java.security.SecurityPermission
            "putProviderProperty.MyJCE";
     };

Provider Методы класса

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

public String getName()
public double getVersion()
public String getInfo()

Security Класс

Security class управляет установленными провайдерами и свойствами всей безопасности. Это только содержит статические методы и никогда не инстанцируется. Методы для добавления или удаления провайдеров, и для того, чтобы установить Security свойства, может только быть выполнен доверяемой программой. В настоящий момент "доверяемая программа" также

Определение, что код считают доверяемым, чтобы выполнить предпринятое действие (такое как добавление провайдера) требует, чтобы апплету предоставили надлежащее разрешение (я) для того определенного действия. Конфигурационный файл (ы) политики для установки JDK определяет то, что полномочия (который типы доступов системного ресурса) позволяются кодом из указанных источников кода. (См. ниже и "Синтаксис Файла Реализации и Политики Политики значения по умолчанию" и "файлы" Спецификации Архитектуры безопасности Java для получения дополнительной информации.)

Выполняемый код, как всегда полагают, прибывает из определенного "источника кода". Источник кода включает не только расположение (URL), где код, порожденный из, но также и ссылка на любой открытый ключ (и), соответствующий закрытому ключу (ам), который, возможно, использовался, чтобы подписать код. На открытые ключи в источнике кода ссылаются (символьные) имена псевдонима от keystore пользователя.

В конфигурационном файле политики источник кода представляется двумя компонентами: кодовая база (URL), и имя псевдонима (предшествовавший signedBy), где имя псевдонима идентифицирует keystore запись, содержащую открытый ключ, который должен использоваться, чтобы проверить подпись кода.

Каждый оператор "предоставления" в таком файле предоставляет указанному источнику кода ряд полномочий, определяя, какие действия позволяются.

Вот демонстрационный конфигурационный файл политики:

grant codeBase "file:/home/sysadmin/", signedBy "sysadmin" {
    permission java.security.SecurityPermission "insertProvider.*";
    permission java.security.SecurityPermission "removeProvider.*";
    permission java.security.SecurityPermission "putProviderProperty.*";
};
Этот конфигурационный файл определяет что код, загруженный из подписанного файла JAR из-под /home/sysadmin/ каталог на локальной файловой системе может добавить или удалить провайдеров или установить свойства провайдера. (Отметьте, что подпись файла JAR может быть проверена, используя открытый ключ, на который ссылается имя псевдонима sysadmin в keystore пользователя.)

Или компонент источника кода (или оба) могут отсутствовать. Вот пример конфигурационного файла где codeBase опускается:

grant signedBy "sysadmin" {
    permission java.security.SecurityPermission "insertProvider.*";
    permission java.security.SecurityPermission "removeProvider.*";
};
Если эта политика в действительности, кодируйте, который прибывает в Файл JAR, подписанный sysadmin могут добавить/удалить провайдеры - независимо от где порожденный Файл JAR.

Вот пример без подписывающего лица:

grant codeBase "file:/home/sysadmin/" {
    permission java.security.SecurityPermission "insertProvider.*";
    permission java.security.SecurityPermission "removeProvider.*";
};
В этом случае, код, который прибывает отовсюду в пределах /home/sysadmin/ каталог на локальной файловой системе может добавить/удалить провайдеров. Код не должен быть подписан.

Пример, где ни один codeBase ни signedBy включается:

grant {
    permission java.security.SecurityPermission "insertProvider.*";
    permission java.security.SecurityPermission "removeProvider.*";
};
Здесь, с обоими исходными компонентными без вести пропавшими кода, любой код (независимо от того, где это происходит, или подписывается ли это, или кто подписал это) может добавить/удалить провайдеров. Очевидно, это определенно НЕ рекомендуется, поскольку это предоставление могло открыть дыру в системе безопасности. Недоверяемый код мог установить Провайдера, таким образом влияя позже кодирует, который является в зависимости от должным образом функционирующей реализации. (Например, жулик Cipher объект мог бы получить и сохранить уязвимую информацию, которую он получает.)

Управление Провайдерами

Следующие таблицы суммируют методы в Security class можно использовать, чтобы запросить который Providers устанавливаются, так же как установить или удалить провайдеров во времени выполнения.

Запросы Провайдеров
Метод Описание
static Provider[] getProviders() Возвращает массив, содержащий всех установленных провайдеров (технически, Provider подкласс для каждого провайдера пакета). Порядок Providers в массиве их привилегированный порядок.
static Provider getProvider
(String providerName)
Возвраты Provider именованный providerName. Это возвращается null если Provider не находится.

Добавление Провайдеров
Метод Описание
static int addProvider(Provider provider) Добавляет a Provider до конца списка установленных Providers. Это возвращает привилегированную позицию в который Provider был добавлен, или -1 если Provider не был добавлен, потому что это было уже установлено.
static int insertProviderAt (Provider provider, int position) Добавляет новое Provider в указанной позиции. Если данный провайдер устанавливается в требуемой позиции, провайдер прежде в той позиции и всех провайдерах с позицией, больше чем position смещаются одна позиция (к концу списка). Этот метод возвращает привилегированную позицию в который Provider был добавлен, или -1 если Provider не был добавлен, потому что это было уже установлено.

Удаление Провайдеров
Метод Описание
static void removeProvider(String name) Удаляет Provider с указанным именем. Это возвращается тихо, если провайдер не устанавливается. Когда указанный провайдер удаляется, все провайдеры, расположенные в позиции, больше чем, где указанный провайдер был, смещаются вниз одна позиция (к главе списка установленных провайдеров).

ОТМЕТЬТЕ: Если Вы хотите изменить привилегированную позицию провайдера, следует сначала удалить ее, и затем вставить ее, въезжают задним ходом в новой привилегированной позиции.

Свойства безопасности

Security class поддерживает список свойств безопасности в масштабе всей системы. Эти свойства подобны System свойства, но связаны с безопасностью. Эти свойства могут быть установлены статически или динамически. Мы уже видели пример статических свойств безопасности (то есть, регистрируя провайдера статически через "security.provider.i" свойство безопасности). Если Вы хотите установить свойства динамически, доверяемые программы могут использовать следующие методы:

static String getProperty(String key)
static void setProperty(String key, String datum)
Отметьте: список поставщиков систем обеспечения безопасности составляется во время запуска VM, поэтому методы, описанные выше, должны использоваться, чтобы изменить список провайдера.

Как напоминание, конфигурационный файл располагается в следующем расположении:

<java-home>/lib/security/java.security     [Unix]
<java-home>\lib\security\java.security     [Windows]

SecureRandom Класс

SecureRandom class является механизмом class, который обеспечивает функциональность Генератора случайных чисел (RNG). Это отличается от Random class в этом это производит криптографически случайные числа strong. Если есть недостаточная случайность в генераторе, она делает намного легче поставить под угрозу Ваши механизмы защиты. Случайные числа используются всюду по криптографии, такой как генерирование криптографических ключей или алгоритмических параметров.

Работа SecureRandom

Создание a SecureRandom Объект

Как со всеми классами механизма, способ получить a SecureRandom объект состоит в том, чтобы вызвать один из getInstance() статические методы фабрики в SecureRandom class.

Отбор или Переотбор SecureRandom Объект

SecureRandom реализация пытается полностью рандомизировать внутреннее состояние генератора непосредственно, если вызывающая сторона не следует за звонком a getInstance метод со звонком в один из setSeed методы:

synchronized public void setSeed(byte[] seed)
public void setSeed(long seed)
Однажды SecureRandom объект был отобран, он произведет биты столь же случайные как исходные семена.

В любое время a SecureRandom объект может быть повторно отобран, используя один из setSeed методы. Данные дополнения семени, а не замены, существующее семя; поэтому, повторные вызовы, как гарантируют, никогда не не уменьшат случайность.

Используя a SecureRandom Объект

Чтобы получить случайные байты, вызывающая сторона просто передает массив любой длины, которая тогда заполнена случайными байтами:

synchronized public void nextBytes(byte[] bytes)

Генерирование Байтов Семени

При желании возможно вызвать generateSeed метод, чтобы генерировать данное число байтов семени (чтобы отобрать другие генераторы случайных чисел, например):
byte[] generateSeed(int numBytes)

MessageDigest Класс

MessageDigest class является механизмом class, разработанный, чтобы обеспечить функциональность криптографически безопасных обзоров сообщения, таких как SHA 1 или MD5. Криптографически безопасный обзор сообщения берет ввод произвольного размера (байтовый массив), и генерирует вывод фиксированного размера, названный обзором или хешем.

Работа MessageDigest

Например, алгоритм MD5 производит 16-байтовый обзор, и SHA1's составляет 20 байтов.

У обзора есть два свойства:

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

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

Создание a MessageDigest Объект

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

Обновление Объекта Обзора сообщения

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

void update(byte input)
void update(byte[] input)
void update(byte[] input, int offset, int len)

Вычисления Обзора

После того, как блоки данных были предоставлены звонками update, обзор вычисляется, используя звонок в один из digest методы:

byte[] digest()
byte[] digest(byte[] input)
int digest(byte[] buf, int offset, int len)

Первый метод возвращает вычисленный обзор. Второй метод делает финал update(input) с входным байтовым массивом перед вызовом digest(), который возвращает байтовый массив обзора. Последний метод хранит вычисленный обзор в обеспеченном буфере buf, запуск в offset. len число байтов в buf выделенный для обзора, метод возвращает число байтов, фактически сохраненных в buf. Если будет недостаточно комнаты в буфере, то метод выдаст исключение.

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

Signature Класс

Signature class является механизмом class, разработанный, чтобы обеспечить функциональность криптографического алгоритма цифровой подписи, такого как DSA или RSAwithMD5. Криптографически безопасный алгоритм подписи берет ввод произвольного размера и закрытый ключ и генерирует относительно короткое (часто фиксированный размер) строка байтов, названных подписью, со следующими свойствами: Это может также использоваться, чтобы проверить, является ли предполагаемая подпись фактически подлинной подписью данных, связанных с этим. Работа подписи

A Signature объект инициализируется для того, чтобы подписаться с Закрытым ключом и дается данные, которые будут подписаны. Получающиеся байты подписи обычно сохраняются с подписанными данными. Когда проверка необходима, другой Signature объект создается и инициализируется для проверки и дается соответствующий Открытый ключ. Данные и байты подписи питаются к объекту подписи, и если данные и соответствие подписи, Signature объект сообщает об успехе.

Даже при том, что подпись кажется подобной обзору сообщения, у них есть совсем другие цели в типе защиты, которую они обеспечивают. Фактически, алгоритмы, такие как "SHA1WithRSA" используют обзор сообщения "SHA1", чтобы первоначально "сжать" большие наборы данных в более управляемую форму, затем подписывают получающийся 20-байтовый обзор сообщения с алгоритмом "RSA".

Пожалуйста, см. раздел В качестве примера для примера подписания и проверки данных.

Signature Объектные государства

Signature объекты являются модальными объектами. Это означает это a Signature объект всегда находится в данном состоянии, где он может только сделать один тип работы. Государства представляются как заключительные целочисленные константы, определенные в их соответствующих классах.

Три состояния a Signature объект может иметь:

Когда это сначала создается, a Signature объект находится в UNINITIALIZED состояние. Signature class определяет два метода инициализации, initSign и initVerify, которые изменяют состояние на SIGN и VERIFY, соответственно.

Создание a Signature Объект

Первый шаг для подписания или проверки подписи должен создать a Signature экземпляр. Signature объекты получаются при использовании одного из Signature getInstance() статические методы фабрики.

Инициализация a Signature Объект

A Signature объект должен быть инициализирован прежде, чем он будет использоваться. Метод инициализации зависит от того, собирается ли объект использоваться для того, чтобы подписаться или для проверки.

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

final void initSign(PrivateKey privateKey)
Этот метод помещает Signature объект в SIGN состояние.

Если вместо этого Signature объект собирается использоваться для проверки, он должен сначала быть инициализирован с открытым ключом объекта, подпись которого собирается быть проверенной. Эта инициализация делается, вызывая любой из этих методов:

    final void initVerify(PublicKey publicKey)

    final void initVerify(Certificate certificate)

Этот метод помещает Signature объект в VERIFY состояние.

Подписание

Если Signature объект был инициализирован для того, чтобы подписаться (если это находится в SIGN состояние), данными, которые будут подписаны, можно тогда снабдить к объекту. Это делается, делая один или более звонков в один из update методы:

final void update(byte b)
final void update(byte[] data)
final void update(byte[] data, int off, int len)

Звонки update метод (ы) должен быть сделан, пока всеми данными, которые будут подписаны, не снабдили к Signature объект.

Чтобы генерировать подпись, просто вызовите один из sign методы:

final byte[] sign()
final int sign(byte[] outbuf, int offset, int len)

Первый метод возвращает результат подписи в байтовом массиве. Вторые хранилища результат подписи в обеспеченном буфере outbuf, запускаясь при смещении. len является числом байтов в outbuf, выделенном для подписи. Метод возвращает число байтов, фактически сохраненных.

Кодирование подписи является определенным алгоритмом. См. документ Стандартных имен для получения дополнительной информации об использовании кодирования ASN.1 в Архитектуре Криптографии Java.

Звонок a sign метод сбрасывает объект подписи к состоянию, в котором это было когда ранее инициализировано для того, чтобы подписаться через звонок initSign. Таким образом, объект сбрасывается и доступен, чтобы генерировать другую подпись с тем же самым закрытым ключом, при желании, через новые звонки update и sign.

Альтернативно, новый вызов может быть выполнен к initSign определение различного закрытого ключа, или к initVerify (чтобы инициализировать Signature объект проверить подпись).

Проверка

Если Signature объект был инициализирован для проверки (если это находится в VERIFY состояние), это может тогда проверить, является ли предполагаемая подпись фактически подлинной подписью данных, связанных с этим. Чтобы запустить процесс, данными, которые будут проверены (в противоположность подписи непосредственно), снабжают к объекту. Данные передают к объекту, вызывая один из update методы:

final void update(byte b)
final void update(byte[] data)
final void update(byte[] data, int off, int len)

Звонки update метод (ы) должен быть сделан, пока всеми данными, которые будут проверены, не снабдили к Signature объект. Подпись может теперь быть проверена, вызывая один из verify методы:

final boolean verify(byte[] signature)

final boolean verify(byte[] signature, int offset, int length)

Параметром должен быть байтовый массив, содержащий подпись. Параметром должен быть байтовый массив, содержащий подпись. Этот байтовый массив содержал бы байты подписи, которые были возвращены предыдущим звонком в один из sign методы.

verify метод возвращает a boolean указание, является ли закодированная подпись подлинной подписью данных, снабженных к update метод (ы).

Звонок verify метод сбрасывает объект подписи к своему состоянию, когда это было инициализировано для проверки через звонок initVerify. Таким образом, объект сбрасывается и доступен, чтобы проверить другую подпись от идентификационных данных, открытый ключ которых был определен в звонке initVerify.

Альтернативно, новый вызов может быть выполнен к initVerify определение различного открытого ключа (чтобы инициализировать Signature объект для того, чтобы проверить подпись от различного объекта), или к initSign (чтобы инициализировать Signature объект для того, чтобы генерировать подпись).

Класс Шифра

Cipher class обеспечивает функциональность криптографического шифра, используемого для шифрования и дешифрования. Шифрование является процессом взятия данных (названный открытым текстом) и ключ, и создание данных (шифрованный текст), бессмысленный к стороннему, кто не знает ключ. Дешифрование является обратным процессом: это взятия шифрованного текста и ключа и создания открытого текста.

Работа шифра

Симметричный по сравнению с Криптографией с асимметричными шифрами

Есть два главных типа шифрования: симметричный (также известный как секретный ключ), и асимметричный (или шифрование с открытым ключом). В криптографии с симметричными шифрами, тот же самый секретный ключ, чтобы и зашифровать и дешифровать данные. Хранение частного ключа является критическим по отношению к хранению конфиденциальных данных. С другой стороны криптография с асимметричными шифрами использует пару "открытый/закрытый ключ", чтобы зашифровать данные. Данные, зашифрованные с одним ключом, дешифровываются с другим. Пользователь сначала генерирует пару "открытый/закрытый ключ", и затем публикует открытый ключ в доверяемой базе данных, к которой любой может получить доступ. Пользователь, который хочет связаться надежно с тем пользователем, шифрует данные, используя полученный открытый ключ. Только держатель закрытого ключа будет в состоянии дешифровать. Хранение конфиденциального закрытого ключа является критическим по отношению к этой схеме.

Асимметричные алгоритмы (такие как RSA) обычно намного медленнее чем симметричные. Эти алгоритмы не разрабатываются для того, чтобы эффективно защитить большие объемы данных. Практически, асимметричные алгоритмы используются, чтобы обмениваться меньшими секретными ключами, которые используются, чтобы инициализировать симметричные алгоритмы.

Поток по сравнению с Блочными шифрами

Есть два главных типа шифров: блок и поток. Блочные шифры обрабатывают все блоки за один раз, обычно много байтов в длине. Если есть недостаточно многие данные, чтобы сделать полный входной блок, данные должны быть дополнены: то есть, перед шифрованием фиктивные байты должны быть добавлены, чтобы сделать кратное число размера блока шифра. Эти байты являются тогда неизолированными во время фазы дешифрования. Дополнение может или быть сделано приложением, или инициализируя шифр, чтобы использовать дополнительный тип, такой как "PKCS5PADDING". Напротив, поточные шифры обрабатывают входящие данные один маленький модуль (обычно байт или даже немного) за один раз. Это учитывает шифры, чтобы обработать произвольный объем данных без дополнения.

Режимы работы

Шифруя использование простого блочного шифра, два идентичных блока простого текста будут всегда производить идентичный блок шифрованного текста. У криптоаналитиков, пытающихся повредить шифрованный текст, будет более легкое задание, если они отметят блоки повторяющегося текста. Чтобы добавить больше сложности к тексту, режимы обратной связи используют предыдущий блок вывода, чтобы изменить входные блоки прежде, чем применить алгоритм шифрования. Первый блок будет нуждаться в начальном значении, и это значение вызывают вектором инициализации (IV). Так как IV просто изменяет данные прежде, чем любое шифрование, IV должен будет быть случайным, но должен будет не обязательно держаться в секрете. Есть множество режимов, таких как CBC (Сцепление блоков шифра), CFB (Режим Обратной связи Шифра), и OFB (Выходной Режим Обратной связи). ECB (Электронный Режим Поваренной книги) является режимом без обратной связи.

Некоторые алгоритмы, такие как AES и RSA учитывают ключи различных длин, но другие фиксируются, такие как DES и 3DES. Шифрование используя ключ большей длины обычно подразумевает более сильное сопротивление, чтобы передать восстановление. Как обычно есть компромисс между безопасностью и время, так выберите длину ключа соответственно.

Большинство алгоритмов использует двоичные ключи. У большинства людей нет возможности помнить длинные последовательности двоичных чисел, даже когда представлено в шестнадцатеричном. Символьные пароли намного легче напомнить. Поскольку символьные пароли обычно выбираются из небольшого количества символов (например, [a-zA-Z0-9]), протоколы, такие как "Основанное на пароле Шифрование" (PBE) были определены, которые берут символьные пароли и генерируют двоичные ключи strong. Чтобы сделать задачу из получения с пароля на ключ очень отнимающей много времени для атакующего (через так называемые "атаки с подбором по словарю", где общее слово словаря-> отображения значения предварительно вычисляются), большинство реализаций PBE смешается в случайном числе, известном как соль, чтобы увеличить ключевую случайность.

Более новые режимы шифра, такие как Аутентифицируемое Шифрование со Связанными Данными (AEAD) (например, Режим Galois/Counter (GCM)) шифруют данные и аутентифицируют получающееся сообщение одновременно. Дополнительные Связанные Данные (AAD) могут использоваться во время calulation получающегося тега AEAD (Mac), но эти данные AAD не выводятся как шифрованный текст. (Например, некоторые данные, возможно, не должны были бы быть сохранены конфиденциальными, но должны фигурировать в вычисление тега, чтобы обнаружить модификации.) Cipher.updateAAD () методы могут использоваться, чтобы включать AAD в вычисления тега.

Создание Объекта Шифра

Cipher объекты получаются при использовании одного из Cipher getInstance() статические методы фабрики. Здесь, имя алгоритма немного отличается чем с другими классами механизма, в которых оно определяет не только имя алгоритма, но и "преобразование". Преобразование является строкой, которая описывает работу (или набор операций), чтобы быть выполненной на данном вводе, чтобы произвести некоторый вывод. Преобразование всегда включает имя криптографического алгоритма (например, DES), и может сопровождаться дополнительной схемой и режимом.

Преобразование имеет форму:

Например, следующее допустимые преобразования:

    "DES/CBC/PKCS5Padding"

    "DES"

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

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

Если никакой режим или дополнение не определяются, специфичные для провайдера значения по умолчанию для режима и дополнительной схемы используются. Например, SunJCE использование провайдера ECB как режим по умолчанию, и PKCS5Padding как дополнительная схема значения по умолчанию DES, DES-EDE и Blowfish шифры. Это означает это в случае SunJCE провайдер:

    Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding");
и
    Cipher c1 = Cipher.getInstance("DES");
эквивалентные операторы.

Используя режимы, такие как CFB и OFB, блочные шифры могут зашифровать данные в модулях, меньших чем фактический размер блока шифра. Запрашивая такой режим, можно дополнительно определить число битов, которые будут обработаны за один раз, добавляя это число к имени режима как показано в "DES/CFB8/NoPadding" и "DES/OFB32/PKCS5Padding" преобразованиях. Если никакое такое число не определяется, специфичное для провайдера значение по умолчанию используется. (Например, SunJCE провайдер использует значение по умолчанию 64 битов для DES.) Таким образом блочные шифры могут быть превращены в байтовые поточные шифры при использовании режима на 8 битов, такие как CFB8 или OFB8.

Приложение A этого документа содержит список стандартных имен, которые могут использоваться, чтобы определить имя алгоритма, режим, и дополнительные компоненты схемы преобразования.

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

Инициализация Объекта Шифра

Объект Шифра, полученный через getInstance должен быть инициализирован для одного из четырех режимов, которые определяются как заключительные целочисленные константы в Cipher class. На режимы могут сослаться их символьные имена, которые показывают ниже наряду с описанием цели каждого режима:

ENCRYPT_MODE
Шифрование данных.
DECRYPT_MODE
Дешифрование данных.
WRAP_MODE
Обертывание a java.security.Key в байты так, чтобы ключ мог быть надежно транспортирован.
UNWRAP_MODE
Разворачивание ранее обернутого ключа в a java.security.Key объект.

Каждый из методов инициализации Шифра берет операционный параметр режима (opmode), и инициализирует объект Шифра для того режима. Другие параметры включают ключ (key) или сертификат, содержащий ключ (certificate), параметры алгоритма (params), и источник случайности (random).

Чтобы инициализировать объект Шифра, вызовите один из следующих init методы:

    public void init(int opmode, Key key);

    public void init(int opmode, Certificate certificate);

    public void init(int opmode, Key key, SecureRandom random);

    public void init(int opmode, Certificate certificate, 
                     SecureRandom random);

    public void init(int opmode, Key key,
                     AlgorithmParameterSpec params);

    public void init(int opmode, Key key,
                     AlgorithmParameterSpec params, SecureRandom random);

    public void init(int opmode, Key key,
                     AlgorithmParameters params);

    public void init(int opmode, Key key,
                     AlgorithmParameters params, SecureRandom random);

Если объект Шифра, который требует параметров (например, вектор инициализации) инициализируется для шифрования, и никакие параметры не предоставляются init метод, базовая реализация шифра, как предполагается, предоставляет обязательные параметры самостоятельно, или генерируя случайные параметры или при использовании значения по умолчанию, специфичного для провайдера набора параметров.

Однако, если объект Шифра, который требует параметров, инициализируется для дешифрования, и никакие параметры не предоставляются init метод, InvalidKeyException или InvalidAlgorithmParameterException исключение будет повышено, в зависимости от init метод, который использовался.

См. раздел об Управляющих Параметрах Алгоритма для большего количества деталей.

Те же самые параметры, которые использовались для шифрования, должны использоваться для дешифрования.

Отметьте, что, когда объект Шифра инициализируется, он теряет все ранее полученное состояние. Другими словами инициализация Шифра эквивалентна созданию нового экземпляра того Шифра, и инициализации этого. Например, если Шифр будет сначала инициализирован для дешифрования с данным ключом, и затем инициализирован для шифрования, то это потеряет любое состояние, полученное в то время как в режиме дешифрования.

Шифрование и Дешифрование Данных

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

Чтобы зашифровать или дешифровать данные в единственном шаге, вызовите один из doFinal методы:

    public byte[] doFinal(byte[] input);

    public byte[] doFinal(byte[] input, int inputOffset, int inputLen);

    public int doFinal(byte[] input, int inputOffset, 
                       int inputLen, byte[] output);

    public int doFinal(byte[] input, int inputOffset, 
                       int inputLen, byte[] output, int outputOffset)

Чтобы зашифровать или дешифровать данные в многократных шагах, вызовите один из update методы:

    public byte[] update(byte[] input);
    
    public byte[] update(byte[] input, int inputOffset, int inputLen);
    
    public int update(byte[] input, int inputOffset, int inputLen,
                      byte[] output);

    public int update(byte[] input, int inputOffset, int inputLen,
                      byte[] output, int outputOffset)

Работа многократной части должна быть завершена одним из вышеупомянутых doFinal методы (если есть все еще некоторые входные данные, в которые уезжают последний шаг), или одним из следующих doFinal методы (если нет никаких входных данных, в которые уезжают последний шаг):

    public byte[] doFinal();

    public int doFinal(byte[] output, int outputOffset);

Весь doFinal методы заботятся о любом необходимом дополнении (или недополнении), если дополнение (или недополнение) требовали как часть указанного преобразования.

Звонок doFinal сбрасывает объект Шифра к состоянию, в котором это было когда инициализировано через звонок init. Таким образом, объект Шифра сбрасывается и доступен, чтобы зашифровать или дешифровать (в зависимости от режима работы, который был определен в звонке init) больше данных.

Обертывание и Разворачивание Ключей

Обертывание ключа включает безопасной передаче ключа от одного места до другого.

wrap/unwrap API делает более удобным записать код, так как это работает с ключевыми объектами непосредственно. Эти методы также включают возможности безопасной передачи основанных на аппаратных средствах ключей.

Чтобы обернуть Ключ, сначала инициализируйте объект Шифра для WRAP_MODE, и затем вызовите следующее:

    public final byte[] wrap(Key key);

Если Вы предоставляете обернутые ключевые байты (результат вызова wrap) кому-то еще, кто развернет их, убедиться, что также отправил дополнительную информацию, в которой будет нуждаться получатель, чтобы сделать unwrap:

  1. имя ключевого алгоритма, и
  2. тип обернутого ключа (один из Cipher.SECRET_KEY, Cipher.PRIVATE_KEY, или Cipher.PUBLIC_KEY).

Ключевое имя алгоритма может быть определено, вызывая getAlgorithm метод от Ключевого интерфейса:

    public String getAlgorithm();

Разворачивать байты, возвращенные предыдущим звонком wrap, сначала инициализируйте объект Шифра для UNWRAP_MODE, затем вызовите следующее:

    public final Key unwrap(byte[] wrappedKey,
                            String wrappedKeyAlgorithm,
                            int wrappedKeyType));

Здесь, wrappedKey байты, возвращенные из предыдущего вызова, чтобы перенестись, wrappedKeyAlgorithm алгоритм, связанный с обернутым ключом, и wrappedKeyType тип обернутого ключа. Это должно быть одним из Cipher.SECRET_KEY, Cipher.PRIVATE_KEY, или Cipher.PUBLIC_KEY.

Управление Параметрами Алгоритма

Параметры, используемые базовой реализацией Шифра, которые или явно передали к init метод приложением или сгенерированный базовой реализацией непосредственно, может быть получен от объекта Шифра, вызывая getParameters метод, который возвращает параметры как a java.security.AlgorithmParameters объект (или null если никакие параметры не используются). Если параметр является вектором инициализации (IV), он может также быть получен, вызывая getIV метод.

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

    import javax.crypto.*;
    import java.security.AlgorithmParameters;
    
    // get cipher object for password-based encryption
    Cipher c = Cipher.getInstance("PBEWithMD5AndDES");
    
    // initialize cipher for encryption, without supplying
    // any parameters. Here, "myKey" is assumed to refer 
    // to an already-generated key.
    c.init(Cipher.ENCRYPT_MODE, myKey);
    
    // encrypt some data and store away ciphertext
    // for later decryption
    byte[] cipherText = c.doFinal("This is just an example".getBytes());
    
    // retrieve parameters generated by underlying cipher
    // implementation
    AlgorithmParameters algParams = c.getParameters();
    
    // get parameter encoding and store it away
    byte[] encodedAlgParams = algParams.getEncoded();

Те же самые параметры, которые использовались для шифрования, должны использоваться для дешифрования. Они можно инстанцировать от их кодирования и использоваться, чтобы инициализировать соответствующий объект Шифра для дешифрования, следующим образом:

    import javax.crypto.*;
    import java.security.AlgorithmParameters;
    
    // get parameter object for password-based encryption
    AlgorithmParameters algParams;
    algParams = AlgorithmParameters.getInstance("PBEWithMD5AndDES");
    
    // initialize with parameter encoding from above
    algParams.init(encodedAlgParams);
    
    // get cipher object for password-based encryption
    Cipher c = Cipher.getInstance("PBEWithMD5AndDES");
    
    // initialize cipher for decryption, using one of the 
    // init() methods that takes an AlgorithmParameters 
    // object, and pass it the algParams object from above
    c.init(Cipher.DECRYPT_MODE, myKey, algParams);

Если Вы не определяли параметров, когда Вы инициализировали объект Шифра, и Вы не уверены, использует ли базовая реализация какие-либо параметры, можно узнать, просто вызывая getParameters метод Вашего объекта Шифра и проверки значения возвратился. Возвращаемое значение null указывает, что никакие параметры не использовались.

Следующие алгоритмы шифра, реализованные SunJCE параметры использования провайдера:

Отметьте, что Вы не должны волноваться о хранении или передаче никаких параметров алгоритма для использования работой дешифрования, если Вы используете SealedObject class. Этот class присоединяет параметры, используемые для того, чтобы изолировать (шифрование) к зашифрованному объектному содержанию, и использует те же самые параметры для того, чтобы распечатать (дешифрование).

Выходные Соображения шифра

Часть из update и doFinal методы Шифра позволяют вызывающей стороне определять буфер вывода, в который можно зашифровать или дешифровать данные. В этих случаях важно передать буфер, который является достаточно большим, чтобы содержать результат работы дешифрования или шифрования.

Следующий метод шифром может использоваться, чтобы определить, насколько большой буфер вывода должен быть:

    public int getOutputSize(int inputLen)

Другой CipherНа основе Классы

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

Потоковые Классы Шифра

Класс CipherInputStream

Этот class является a FilterInputStream это шифрует или дешифрует данные, проходящие через это. Это составляется из InputStream, или один из его подклассов, и a Cipher. CipherInputStream представляет безопасный входной поток, в который был вставлен объект Шифра. read методы CipherInputStream возвращают данные, которые читаются из базового InputStream, но были дополнительно обработаны встроенным объектом Шифра. Объект Шифра должен быть полностью инициализирован прежде, чем быть используемым CipherInputStream.

Например, если встроенный Шифр был инициализирован для дешифрования, CipherInputStream попытается дешифровать данные, которые это читает из базового InputStream прежде, чем возвратить их приложению.

Этот class придерживается строго семантики, особенно семантика отказа, ее классов предка java.io.FilterInputStream и java.io.InputStream. Этот class имеет точно те методы, определенные в его классах предка, и переопределяет их всех, так, чтобы данные были дополнительно обработаны встроенным шифром. Кроме того этот class ловит все исключения, которые не выдаются его классами предка. В частности skip(long) метод пропускает только данные, которые были обработаны Шифром.

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

Как пример его использования, предположить cipher1 был инициализирован для шифрования. Код ниже демонстрирует, как использовать CipherInputStream, содержащий тот шифр и FileInputStream, чтобы зашифровать входные потоковые данные:

    FileInputStream fis;
    FileOutputStream fos;
    CipherInputStream cis;
    
    fis = new FileInputStream("/tmp/a.txt");
    cis = new CipherInputStream(fis, cipher1);
    fos = new FileOutputStream("/tmp/b.txt");
    byte[] b = new byte[8];
    int i = cis.read(b);
    while (i != -1) {
        fos.write(b, 0, i);
        i = cis.read(b);
    }
    fos.close();

Вышеупомянутая программа читает и шифрует контент от файла /tmp/a.txt и затем хранит результат (зашифрованные байты) в /tmp/b.txt.

Следующий пример демонстрирует, как легко соединить несколько экземпляров CipherInputStream и FileInputStream. В этом примере примите это cipher1 и cipher2 были инициализированы для шифрования и дешифрования (с соответствующими ключами), соответственно.

    FileInputStream fis;
    FileOutputStream fos;
    CipherInputStream cis1, cis2;
    
    fis = new FileInputStream("/tmp/a.txt");
    cis1 = new CipherInputStream(fis, cipher1);
    cis2 = new CipherInputStream(cis1, cipher2);
    fos = new FileOutputStream("/tmp/b.txt");
    byte[] b = new byte[8];
    int i = cis2.read(b);
    while (i != -1) {
        fos.write(b, 0, i);
        i = cis2.read(b);
    }
    fos.close();
    

Вышеупомянутая программа копирует контент с файла /tmp/a.txt к /tmp/b.txt, за исключением того, что контент сначала шифруется и затем дешифровал назад, когда он читается из /tmp/a.txt. Конечно, так как эта программа просто шифрует текст и дешифрует его назад сразу же, это фактически не очень полезно за исключением простого способа иллюстрировать объединение в цепочку CipherInputStreams.

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

Класс CipherOutputStream

Этот class является a FilterOutputStream это шифрует или дешифрует данные, проходящие через это. Это составляется из OutputStream, или один из его подклассов, и a Cipher. CipherOutputStream представляет безопасный поток вывода, в который был вставлен объект Шифра. write методы CipherOutputStream сначала обрабатывают данные со встроенным объектом Шифра перед выписыванием их к базовому OutputStream. Объект Шифра должен быть полностью инициализирован прежде, чем быть используемым CipherOutputStream.

Например, если встроенный Шифр был инициализирован для шифрования, CipherOutputStream зашифрует свои данные перед выписыванием их к базовому потоку вывода.

Этот class придерживается строго семантики, особенно семантика отказа, ее классов предка java.io.OutputStream и java.io.FilterOutputStream. Этот class имеет точно те методы, определенные в его классах предка, и переопределяет их всех, так, чтобы все данные были дополнительно обработаны встроенным шифром. Кроме того этот class ловит все исключения, которые не выдаются его классами предка.

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

Как пример его использования, предположить cipher1 был инициализирован для шифрования. Код ниже демонстрирует, как использовать CipherOutputStream, содержащий тот шифр и FileOutputStream, чтобы зашифровать данные, которые будут записаны потоку вывода:

    FileInputStream fis;
    FileOutputStream fos;
    CipherOutputStream cos;
    
    fis = new FileInputStream("/tmp/a.txt");
    fos = new FileOutputStream("/tmp/b.txt");
    cos = new CipherOutputStream(fos, cipher1);
    byte[] b = new byte[8];
    int i = fis.read(b);
    while (i != -1) {
        cos.write(b, 0, i);
        i = fis.read(b);
    }
    cos.flush();

Вышеупомянутая программа читает контент из файла /tmp/a.txt, тогда шифрует и хранит результат (зашифрованные байты) в /tmp/b.txt.

Следующий пример демонстрирует, как легко соединить несколько экземпляров CipherOutputStream и FileOutputStream. В этом примере примите это cipher1 и cipher2 были инициализированы для дешифрования и шифрования (с соответствующими ключами), соответственно:

    FileInputStream fis;
    FileOutputStream fos;
    CipherOutputStream cos1, cos2;
    
    fis = new FileInputStream("/tmp/a.txt");
    fos = new FileOutputStream("/tmp/b.txt");
    cos1 = new CipherOutputStream(fos, cipher1);
    cos2 = new CipherOutputStream(cos1, cipher2);
    byte[] b = new byte[8];
    int i = fis.read(b);
    while (i != -1) {
        cos2.write(b, 0, i);
        i = fis.read(b);
    }
    cos2.flush();

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

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

Есть одно другое важное различие между flush и close методы этого class, который становится еще более релевантным, если инкапсулировавший объект Шифра реализует алгоритм блочного шифра с дополнением включенного:

Класс SealedObject

Этот class позволяет программисту создать объект и защитить его конфиденциальность с криптографическим алгоритмом.

Учитывая любой объект, который реализует java.io.Serializable интерфейс, можно создать a SealedObject это инкапсулирует исходный объект, в сериализированном формате (то есть, "глубокая копия"), и изоляции (шифруют) ее сериализированное содержание, используя криптографический алгоритм, такое как DES, чтобы защитить ее конфиденциальность. Зашифрованный контент может позже быть дешифрован (с соответствующим алгоритмом, используя корректный ключ расшифровки) и десериализован, приводя к исходному объекту.

Типичное использование иллюстрируется в следующем сегменте кода: Чтобы изолировать объект, Вы создаете a SealedObject от объекта, который будет изолирован и полностью инициализированный Cipher объект, который зашифрует сериализированное объектное содержание. В этом примере Строка "Это - секрет", изолируется, используя алгоритм DES. Отметьте, что любые параметры алгоритма, которые могут использоваться в работе изоляции, сохранены в SealedObject:

    // create Cipher object
    // NOTE: sKey is assumed to refer to an already-generated
    // secret DES key.
    Cipher c = Cipher.getInstance("DES");
    c.init(Cipher.ENCRYPT_MODE, sKey);
    
    // do the sealing
    SealedObject so = new SealedObject("This is a secret", c);

Исходный объект, который был изолирован, может быть восстановлен двумя различными способами:

Мак Класс

Подобный a MessageDigest, Код аутентификации сообщений (MAC) обеспечивает способ проверить целостность информации, переданной или сохраненный в ненадежном носителе, но включает секретный ключ в вычисление. Только кто-то с надлежащим ключом будет в состоянии проверить полученное сообщение. Как правило, коды аутентификации сообщений используются между двумя сторонами, которые совместно используют секретный ключ, чтобы проверить информации, переданной между этими сторонами.

Работа Mac

Механизм MAC, который основан на криптографических хеш-функциях, упоминается как HMAC. HMAC может использоваться с любой криптографической хеш-функцией, например, MD5 или SHA 1, в комбинации с секретом совместно использованный ключ.

Mac class обеспечивает функциональность Кода аутентификации сообщений (MAC). Пожалуйста, обратитесь к примеру кода.

Создание a Mac Объект

Mac объекты получаются при использовании одного из Mac getInstance() статические методы фабрики.

Инициализация Мак Обджекта

Объект Mac всегда инициализируется с (секретным) ключом и может дополнительно быть инициализирован с рядом параметров, в зависимости от базового алгоритма MAC.

Чтобы инициализировать объект Mac, вызовите один из init методы:

    public void init(Key key);
    
    public void init(Key key, AlgorithmParameterSpec params);

Можно инициализировать свой объект Mac с любым (секрет-) ключевой объект, который реализует javax.crypto.SecretKey интерфейс. Это могло быть объектом, возвращенным javax.crypto.KeyGenerator.generateKey(), или тот, который является результатом протокола согласования ключей, как возвращено javax.crypto.KeyAgreement.generateSecret(), или экземпляр javax.crypto.spec.SecretKeySpec.

С некоторыми алгоритмами MAC (секрет-) ключевой алгоритм, связанный с (секрет-) не имеет значения ключевой объект, используемый, чтобы инициализировать объект Mac (дело обстоит так с HMAC-MD5 и реализациями HMAC-SHA1 SunJCE провайдер). С другими, однако, (секрет-) ключевой алгоритм действительно имеет значение, и InvalidKeyException бросается, если (секрет-) ключевой объект с несоответствующим (секрет-) ключевой алгоритм используется.

Вычисления MAC

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

Чтобы вычислить MAC некоторых данных в единственном шаге, вызовите следующий doFinal метод:

    public byte[] doFinal(byte[] input);

Чтобы вычислить MAC некоторых данных в многократных шагах, вызовите один из update методы:

    public void update(byte input);
    
    public void update(byte[] input);
    
    public void update(byte[] input, int inputOffset, int inputLen);

Работа многократной части должна быть завершена вышеупомянутым doFinal метод (если есть все еще некоторые входные данные, в которые уезжают последний шаг), или одним из следующих doFinal методы (если нет никаких входных данных, в которые уезжают последний шаг):

    public byte[] doFinal();
    
    public void doFinal(byte[] output, int outOffset);

Key Интерфейсы

К этой точке мы фокусировали высокоуровневое использование JCA, не заблудившись в деталях того, что ключи и как они генерируются/представляются. Теперь пора обратить наше внимание к ключам.

java.security.Key интерфейс является высокоуровневым интерфейсом для всех непрозрачных ключей. Это определяет функциональность, совместно использованную всеми непрозрачными ключевыми объектами.

Непрозрачное ключевое представление - тот, в котором у Вас нет никакого прямого доступа к ключевому материалу, который составляет ключ. Другими словами: "непрозрачный" дает Вам ограниченный доступ к ключу - только эти три метода, определенные Key интерфейс (см. ниже): getAlgorithm, getFormat, и getEncoded.

Это в отличие от прозрачного представления, в котором можно получить доступ к каждой ключевой материальной ценности индивидуально, через один из get методы, определенные в соответствующей спецификации class.

У всех непрозрачных ключей есть три характеристики:

Алгоритм
Ключевой алгоритм для того ключа. Ключевой алгоритм обычно является шифрованием или асимметричным алгоритмом работы (такой как AES, DSA или RSA), который будет работать с теми алгоритмами и со связанными алгоритмами (такой как MD5withRSA, SHA1withRSA, и т.д.), имя алгоритма ключа получается, используя этот метод:
String getAlgorithm()
Закодированная Форма
Внешняя закодированная форма для ключа, используемого, когда стандартное представление ключа необходимо вне виртуальной машины Java, передавая ключ к некоторой другой стороне. Ключ кодируется согласно стандартному формату (такому как X.509 или PKCS8), и возвращается, используя метод:
byte[] getEncoded()
Формат
Имя формата закодированного ключа. Это возвращается методом:
String getFormat()
Ключи обычно получаются через ключевые генераторы такой как KeyGenerator и KeyPairGenerator, сертификаты, ключевые спецификации (использующий a KeyFactory), или a KeyStore реализация, получающая доступ к keystore базе данных, используемой, чтобы управлять ключами. Возможно проанализировать закодированные ключи, зависимым от алгоритма способом, используя a KeyFactory.

Также возможно проанализировать сертификаты, используя a CertificateFactory.

Вот список интерфейсов, которые расширяются Key интерфейс в java.security.interfaces и javax.crypto.interfaces пакеты:

PublicKey и PrivateKey Интерфейсы

PublicKey и PrivateKey интерфейсы (который оба расширяют Key интерфейс), бессистемные интерфейсы, используемые для безопасности типов и идентификации типа.

KeyPair Класс

KeyPair class является простым держателем для пары ключей (открытый ключ и закрытый ключ). У этого есть два открытых метода, один для того, чтобы возвратить закрытый ключ, и другой для того, чтобы возвратить открытый ключ:

PrivateKey getPrivate()
PublicKey getPublic()

Ключевые Интерфейсы Спецификации и Классы

Key объекты и ключевые спецификации (KeySpecs) два различных представления ключевых данных. Ciphers использование Key объекты инициализировать их алгоритмы шифрования, но ключи, возможно, должны быть преобразованы в более переносимый формат для передачи или хранения.

Прозрачное представление ключей означает, что можно получить доступ к каждой ключевой материальной ценности индивидуально, через один из get методы, определенные в соответствующей спецификации class. Например, DSAPrivateKeySpec определяет getX, getP, getQ, и getG методы, чтобы получить доступ к закрытому ключу x, и параметры алгоритма DSA, используемые, чтобы вычислить ключ: начало p, субстандартное q, и основа g. Если ключ сохранен на устройстве, его спецификация может содержать информацию, которая помогает идентифицировать ключ на устройстве.

Это представление противопоставляется с непрозрачным представлением, как определено Key интерфейс, в котором у Вас нет никакого прямого доступа к ключевым материальным полям. Другими словами "непрозрачное" представление дает Вам ограниченный доступ к ключу - только эти три метода, определенные Key интерфейс: getAlgorithm, getFormat, и getEncoded.

Ключ может быть определен специфичным для алгоритма способом, или независимым от алгоритма форматом кодирования (таким как ASN.1). Например, закрытый ключ DSA может быть определен его компонентами x, p, q, и g (см. DSAPrivateKeySpec), или это может быть определено, используя его DER, кодирующий (см. PKCS8EncodedKeySpec).

KeyFactory и SecretKeyFactory классы могут использоваться, чтобы преобразовать между непрозрачными и прозрачными ключевыми представлениями (то есть, между Keys и KeySpecs, предполагая, что работа возможна. (Например, закрытые ключи на смарт-картах не могли бы быть в состоянии, оставляют карту. Такой Keys не конвертируемы.)

В следующих разделах мы обсуждаем ключевые интерфейсы спецификации и классы в java.security.spec пакет.

KeySpec Интерфейс

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

KeySpec Подынтерфейсы

Как Key интерфейс, есть подобный набор KeySpec интерфейсы.

EncodedKeySpec Класс

Этот абстрактный class (который реализует KeySpec интерфейс), представляет или закрытый ключ с открытым ключом в закодированном формате. getEncoded метод возвращает закодированный ключ:
abstract byte[] getEncoded();
и getFormat метод возвращает имя формата кодирования:
abstract String getFormat();

См. следующие разделы для конкретных реализаций PKCS8EncodedKeySpec и X509EncodedKeySpec.

PKCS8EncodedKeySpec Класс

Этот class, который является подклассом EncodedKeySpec, представляет кодирование DER закрытого ключа, согласно формату, определенному в стандарте PKCS8. getEncoded метод возвращает ключевые байты, закодированные согласно стандарту PKCS8. getFormat метод возвращает строку "PKCS#8".

X509EncodedKeySpec Класс

Этот class, который является подклассом EncodedKeySpec, представляет кодирование DER открытого ключа, согласно формату, определенному в стандарте X.509. getEncoded метод возвращает ключевые байты, закодированные согласно стандарту X.509. getFormat метод возвращает строку "X.509".

Из Генераторов и Фабрик

Вновь прибывшие к Java и API JCA в особенности иногда не схватывают различие между генераторами и фабриками. Сравнение Между Генераторами и Фабриками

Генераторы используются, чтобы генерировать совершенно новые объекты. Генераторы могут быть инициализированы или зависимым от алгоритма или независимым от алгоритма способом. Например, чтобы создать Diffie-Hellman (DH) пара ключей, приложение могло определить необходимые значения P и Г, или генератор мог просто быть инициализирован с соответствующей длиной ключа, и генератор выберет соответствующие значения P и Г. В обоих случаях генератор произведет совершенно новые ключи, основанные на параметрах.

С другой стороны фабрики используются, чтобы преобразовать данные от одного существующего объектного типа до другого. Например, приложение могло бы иметь доступный компоненты закрытого ключа DH и может упаковать их как a KeySpec, но потребности преобразовать их в a PrivateKey объект, который может использоваться a KeyAgreement объект, или наоборот. Или они могли бы иметь байтовый массив сертификата, но должны использовать a CertificateFactory преобразовать это в a X509Certificate объект. Приложения используют объекты фабрики сделать преобразование.

KeyFactory Класс

KeyFactory class является механизмом class, разработанный, чтобы выполнить преобразования между криптографическим непрозрачным Keys и ключевые спецификации (прозрачные представления базового ключевого материала). Работа KeyFactory

Ключевые фабрики двунаправлены. Они позволяют Вам создавать непрозрачный ключевой объект из данной ключевой спецификации (ключевой материал), или получать базовый ключевой материал ключевого объекта в подходящем формате.

Многократные совместимые ключевые спецификации могут существовать для того же самого ключа. Например, открытый ключ DSA может быть определен его компонентами y, p, q, и g (см. java.security.spec.DSAPublicKeySpec), или это может быть определено, используя его DER, кодирующий согласно стандарту X.509 (см. X509EncodedKeySpec).

Ключевая фабрика может использоваться, чтобы преобразовать между совместимыми ключевыми спецификациями. Ключевой парсинг может быть достигнут через преобразование между совместимыми ключевыми спецификациями, например, когда Вы преобразовываете из X509EncodedKeySpec к DSAPublicKeySpec, Вы в основном анализируете закодированный ключ в его компоненты. Для примера см. конец Подписей Генерирования/Проверки Используя Ключевые Спецификации и KeyFactory раздел.

Создание a KeyFactory Объект

KeyFactory объекты получаются при использовании одного из KeyFactory getInstance() статические методы фабрики.

Преобразование Между Ключевой Спецификацией и Ключевым объектом

Если у Вас есть ключевая спецификация для открытого ключа, можно получить непрозрачное PublicKey объект от спецификации при использовании generatePublic метод:

PublicKey generatePublic(KeySpec keySpec)

Точно так же, если у Вас есть ключевая спецификация для закрытого ключа, можно получить непрозрачное PrivateKey объект от спецификации при использовании generatePrivate метод:

PrivateKey generatePrivate(KeySpec keySpec)

Преобразование Между Ключевым объектом и Ключевой Спецификацией

Если у Вас есть a Key объект, можно получить соответствующий ключевой объект спецификации, вызывая getKeySpec метод:

KeySpec getKeySpec(Key key, Class keySpec)
keySpec идентифицирует спецификацию class, в котором должен быть возвращен ключевой материал. Это могло, например, быть DSAPublicKeySpec.class, указать, что ключевой материал должен быть возвращен в экземпляре DSAPublicKeySpec class.

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

Класс SecretKeyFactory

Этот class представляет фабрику для секретных ключей. В отличие от этого KeyFactory, a javax.crypto.SecretKeyFactory объект работает только на секретных (симметричных) ключах, тогда как a java.security.KeyFactory возразите обрабатывает компоненты с закрытым ключом и с открытым ключом пары ключей.

Работа SecretKeyFactory

Ключевые фабрики используются, чтобы преобразовать Keys (непрозрачные криптографические ключи типа java.security.Key) в ключевые спецификации (прозрачные представления базового ключевого материала в подходящем формате), и наоборот.

Объекты типа java.security.Key, из которых java.security.PublicKey, java.security.PrivateKey, и javax.crypto.SecretKey подклассы, непрозрачные ключевые объекты, потому что невозможно сказать, как они реализуются. Базовая реализация зависима от провайдера, и может быть программным обеспечением или базируемыми аппаратными средствами. Ключевые фабрики позволяют провайдерам предоставлять свои собственные реализации криптографических ключей.

Например, если у Вас есть ключевая спецификация для Diffie Hellman открытый ключ, состоя из общедоступного значения y, главный модуль p, и основа g, и Вы подаете ту же самую спецификацию к фабрикам ключа Diffie-Hellman от различных провайдеров, получающегося PublicKey у объектов наиболее вероятно будут различные базовые реализации.

Провайдер должен задокументировать ключевые спецификации, поддерживаемые его фабрикой секретного ключа. Например, SecretKeyFactory для ключей DES, предоставленных SunJCE провайдер поддерживает DESKeySpec как прозрачное представление ключей DES, SecretKeyFactory для ЭДЕ DES ключи поддерживает DESedeKeySpec как прозрачное представление ключей ЭДЕ DES, и SecretKeyFactory поскольку PBE поддерживает PBEKeySpec как прозрачное представление базового пароля.

Следующее является примером того, как использовать a SecretKeyFactory преобразовать данные секретного ключа в a SecretKey объект, который может использоваться для последующего Cipher работа:

    // Note the following bytes are not realistic secret key data
    // bytes but are simply supplied as an illustration of using data
    // bytes (key material) you already have to build a DESKeySpec.
    byte[] desKeyData = { (byte)0x01, (byte)0x02, (byte)0x03, 
    (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08 };
    DESKeySpec desKeySpec = new DESKeySpec(desKeyData);
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
    SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

В этом случае, базовая реализация SecretKey основано на провайдере KeyFactory.

Альтернативный, независимый от провайдера способ создать функционально эквивалентный SecretKey объект от того же самого ключевого материала состоит в том, чтобы использовать javax.crypto.spec.SecretKeySpec class, который реализует javax.crypto.SecretKey интерфейс:

    byte[] desKeyData = { (byte)0x01, (byte)0x02, ...};
    SecretKeySpec secretKey = new SecretKeySpec(desKeyData, "DES");

Создание a SecretKeyFactory Объект

SecretKeyFactory объекты получаются при использовании одного из SecretKeyFactory getInstance() статические методы фабрики.

Преобразование Между Ключевой Спецификацией и Объектом Секретного ключа

Если у Вас есть ключевая спецификация для секретного ключа, можно получить непрозрачное SecretKey объект от спецификации при использовании generateSecret метод:

SecretKey generateSecret(KeySpec keySpec)

Преобразование Между Объектом Секретного ключа и Ключевой Спецификацией

Если у Вас есть a Secret Key объект, можно получить соответствующий ключевой объект спецификации, вызывая getKeySpec метод:

KeySpec getKeySpec(Key key, Class keySpec)
keySpec идентифицирует спецификацию class, в котором должен быть возвращен ключевой материал. Это могло, например, быть DESKeySpec.class, указать, что ключевой материал должен быть возвращен в экземпляре DESKeySpec class.

KeyPairGenerator Класс

KeyPairGenerator class является механизмом class, используемый, чтобы генерировать пар открытых и закрытых ключей.

Работа KeyPairGenerator

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

Пожалуйста, см. раздел В качестве примера для примеров звонков в методы, задокументированные ниже.

Создание a KeyPairGenerator

Вся генерация пары ключей запускается с a KeyPairGenerator. KeyPairGenerator объекты получаются при использовании одного из KeyPairGenerator getInstance() статические методы фабрики.

Инициализация a KeyPairGenerator

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

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

Независимая от алгоритма Инициализация

Все генераторы пары ключей совместно используют понятие размера ключа и источник случайности. Размер ключа интерпретируется по-другому для различных алгоритмов. Например, в случае алгоритма DSA, размер ключа соответствует длине модуля. (См. документ Стандартных имен для информации о размерах ключа для определенных алгоритмов.)

initialize метод берет два универсально совместно используемых типа параметров:

void initialize(int keysize, SecureRandom random)
Другой initialize метод берет только a keysize параметр; это использует обеспеченный системой источник случайности:
void initialize(int keysize)

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

Если алгоритм является алгоритмом "DSA", и размер модуля (размер ключа) 512, 768, или 1024, то SUN провайдер использует ряд предварительно вычисленных значений для p, q, и g параметры. Если размер модуля не является одним из вышеупомянутых значений, SUN провайдер создает новый набор параметров. Другие провайдеры, возможно, предварительно вычислили наборы параметра для больше чем только три упомянутые выше размера модуля. Все еще другие не могли бы иметь списка предварительно вычисленных параметров вообще и вместо этого всегда создавать новые наборы параметра.

Специфичная для алгоритма Инициализация

Для ситуаций, где ряд специфичных для алгоритма параметров уже существует (такие как "параметры сообщества" в DSA), есть два initialize методы, которые имеют AlgorithmParameterSpec параметр. У каждого также есть a SecureRandom параметр, в то время как источник случайности предусматривается на систему другой:

void initialize(AlgorithmParameterSpec params,
                SecureRandom random)

void initialize(AlgorithmParameterSpec params)
См. раздел В качестве примера для большего количества деталей.

Генерирование Пары ключей

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

KeyPair generateKeyPair()
Множественные вызовы generateKeyPair приведет к различным парам ключей.

Класс KeyGenerator

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

Работа KeyGenerator

Создание a KeyGenerator

KeyGenerator объекты получаются при использовании одного из KeyGenerator getInstance() статические методы фабрики.

Инициализация Объекта KeyGenerator

Ключевой генератор для определенного алгоритма с симметричным ключом создает симметричный ключ, который может использоваться с тем алгоритмом. Это также связывает специфичные для алгоритма параметры (если любой) со сгенерированным ключом.

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

В случае, если клиент явно не инициализирует KeyGenerator (через звонок init метод), каждый провайдер должен предоставить (и документ) инициализацию значения по умолчанию.

Создание Ключа

Следующий метод генерирует секретный ключ:
    public SecretKey generateKey();

Класс KeyAgreement

Согласование ключей является протоколом, которым 2 или больше стороны могут установить те же самые криптографические ключи, не имея необходимость обмениваться любой секретной информацией. Работа KeyAgreement

Каждая сторона инициализирует их объект согласования ключей с их закрытым ключом, и затем вводит открытые ключи для каждой стороны, которая будет участвовать в передаче. В большинстве случаев есть только две стороны, но алгоритмы, такие как Diffie-Hellman учитывают многократные стороны (3 или больше), чтобы участвовать. Когда все открытые ключи были введены, каждый KeyAgreement объект генерирует (согласуют) тот же самый ключ.

KeyAgreement class обеспечивает функциональность протокола согласования ключей. Ключи, включенные в установление совместно используемого секрета, создаются одним из ключевых генераторов (KeyPairGenerator или KeyGenerator), a KeyFactory, или в результате от промежуточной фазы протокола согласования ключей.

Создание Объекта KeyAgreement

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

Инициализация Объекта KeyAgreement

Вы инициализируете объект KeyAgreement со своей частной информацией. В случае Diffie-Hellman Вы инициализируете это со своим закрытым ключом Diffie-Hellman. Дополнительная информация об инициализации может содержать источник случайности и/или ряда параметров алгоритма. Отметьте, что, если требуемый алгоритм согласования ключей требует, спецификация параметров алгоритма, и только ключ, но никакие параметры обеспечиваются, чтобы инициализировать объект KeyAgreement, ключ должен содержать необходимые параметры алгоритма. (Например, алгоритм Diffie-Hellman использует главный модуль p и основной генератор g как его параметры.)

Чтобы инициализировать объект KeyAgreement, вызовите один из init методы:

    public void init(Key key);
    
    public void init(Key key, SecureRandom random);
    
    public void init(Key key, AlgorithmParameterSpec params);
    
    public void init(Key key, AlgorithmParameterSpec params,
                     SecureRandom random);

Выполнение Фазы KeyAgreement

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

Чтобы выполнить следующую фазу в согласовании ключей, вызовите doPhase метод:

    public Key doPhase(Key key, boolean lastPhase);

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

lastPhase параметр определяет, является ли фаза, которая будет выполнена, последним в согласовании ключей: значение FALSE указывает, что это не последняя фаза согласования ключей (есть больше фаз, чтобы следовать), и значение TRUE указывает, что это - последняя фаза согласования ключей, и согласование ключей завершается, то есть, generateSecret может быть вызван затем.

В примере Diffie-Hellman между двумя сторонами Вы вызываете doPhase однажды, с lastPhase набор к TRUE. В примере Diffie-Hellman между тремя сторонами Вы вызываете doPhase дважды: в первый раз с lastPhase набор к FALSE, в 2-ой раз с lastPhase набор к TRUE.

Генерирование Совместно используемого Секрета

После того, как каждая сторона выполнила все необходимые фазы согласования ключей, она может вычислить совместно используемый секрет, вызывая один из generateSecret методы:

    public byte[] generateSecret();
    
    public int generateSecret(byte[] sharedSecret, int offset);
    
    public SecretKey generateSecret(String algorithm);

Управление ключами

База данных, названная "keystore", может использоваться, чтобы управлять репозитарием ключей и сертификатов. (Сертификат является в цифровой форме подписанным заявлением от одного объекта, говоря, что у открытого ключа некоторого другого объекта есть определенное значение.)

Расположение Keystore

Пользователь keystore по умолчанию сохранен в названном файле .keystore в корневом каталоге пользователя, как определено "user.home" системным свойством. На системах Соляриса "user.home" значения по умолчанию к корневому каталогу пользователя. На системах Win32, учитывая имя пользователя uName, "user.home" значения по умолчанию к:

Конечно, keystore файлы может быть расположен как требующийся. В некоторых средах может иметь смысл для многократного keystores существовать. Например, в JSSE (SSL/TLS), один keystore мог бы содержать закрытые ключи пользователя, и другой мог бы содержать сертификаты, используемые, чтобы установить доверительные отношения.

В дополнение к keystore пользователя Sun JDK также поддерживает keystore в масштабе всей системы, который используется, чтобы сохранить сертификаты, которым доверяют, от множества Центров сертификации (CA). Эти сертификаты CA могут использоваться, чтобы помочь принять доверительные решения. Например, на SSL/TLS, когда SunJSSE провайдеру дарят сертификаты от удаленной коллеги, значение по умолчанию trustmanager будет консультироваться:

    <java-home>/lib/ext/cacerts           [Unix], or
    <java-home>\lib\ext\cacerts           [Windows]
    
файл, чтобы определить, нужно ли соединению доверять. Вместо того, чтобы использовать в масштабе всей системы cacerts keystore, приложения могут установить и использовать свой собственный keystores, или даже использовать пользователя keystore описанный выше.

Реализация Keystore

KeyStore class предоставляет четко определенные интерфейсы, чтобы получить доступ и изменить информацию в keystore. Для там возможно быть многократными различными конкретными реализациями, где каждая реализация состоит в том что для определенного типа keystore.

В настоящий момент есть два инструмента командной строки, которые используют KeyStore: keytool и jarsigner, и также основанный на GUI инструмент называют policytool. Это также используется Policy ссылочная реализация, когда это обрабатывает файлы политики, определяющие полномочия (предоставленные доступы к системным ресурсам), чтобы быть предоставленным кодировать из различных источников. С тех пор KeyStore публично доступно, пользователи JDK могут записать дополнительные приложения безопасности, которые используют это.

Приложения могут выбрать различные типы keystore реализаций от различных провайдеров, используя getInstance метод фабрики в KeyStore class. Тип keystore определяет хранение и формат данных keystore информации, и алгоритмы, используемые, чтобы защитить закрытые ключи в keystore и целостности keystore непосредственно. Реализации Keystore различных типов не являются совместимыми.

Есть встроенное значение по умолчанию keystore тип реализации, известный как"jks"это обеспечивается Sun Microsystems. Это реализует keystore как файл, используя собственный тип keystore (формат). Это защищает каждый закрытый ключ со своим собственным отдельным паролем, и также защищает целостность всего keystore с (возможно отличающийся) пароль. Значение по умолчанию определяется следующей строкой в файле свойств безопасности:

    keystore.type=jks

Чтобы иметь инструменты и другие приложения используют различное значение по умолчанию keystore реализация, можно изменить ту строку, чтобы определить тип значения по умолчанию. Если у Вас есть пакет провайдера, который предоставляет keystore реализацию для типа keystore, названного "jceks", измените строку на:

    keystore.type=jceks
Некоторые приложения, такой как keytool, также позвольте Вам переопределять значение по умолчанию keystore тип (через -storetype параметр командной строки).
ОТМЕТЬТЕ: обозначения типа Keystore не являются чувствительными к регистру. Например, "jks" считали бы тем же самым как "jks".
Есть два других типа keystores, которые идут с Sun реализация JDK.
  1. "jceks" является альтернативным собственным форматом keystore к "jks", который использует намного более сильное шифрование в форме Основанного на пароле Шифрования с Тройным DES.

    Sun "jceks" реализация может проанализировать и преобразовать "jks" keystore файл к формату "jceks". Можно обновить свой keystore типа "jks" к keystore типа "jceks", изменяя пароль записи с закрытым ключом в Вашем keystore и определения "-storetype jceks" как тип keystore. Чтобы применяться криптографически strong (er) ключевая защита, предоставленная закрытому ключу, названному "signkey" в Вашем значении по умолчанию keystore, используйте следующую команду, которая запросит Вас старые и новые ключевые пароли:

        keytool -keypasswd -alias signkey -storetype jceks
    
    См. Средства обеспечения безопасности для получения дополнительной информации о keytool и о keystores и как ими управляют.
  2. "pkcs12" является другой опцией. Это - перекрестная платформа keystore основанный на RSA PKCS12 Стандарт Синтаксиса Exchange Персональных данных. Этот стандарт прежде всего предназначается для хранения или переноса закрытых ключей пользователя, сертификатов, и разных секретов. С JDK 6, стандарты для того, чтобы сохранить Сертификаты, Которым доверяют, в "pkcs12" еще не были установлены, и таким образом "jks", или "jceks" должен использоваться для доверяемых сертификатов.

Реализации Keystore основаны на провайдере. Разработчики, заинтересованные в письменной форме, их собственные реализации KeyStore должны консультироваться, Как Реализовать Провайдера для Архитектуры Криптографии Java для получения дополнительной информации об этой теме.

KeyStore Класс

KeyStore class является механизмом class, который предоставляет четко определенные интерфейсы, чтобы получить доступ и изменить информацию в keystore. Работа KeyStore

Этот class представляет набор в памяти ключей и сертификатов. KeyStore управляет двумя типами записей:

Ключевая Запись

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

Закрытые ключи и цепочки сертификата используются данным объектом для самоаутентификации, используя цифровые подписи. Например, организации распределения программного обеспечения в цифровой форме подписывают файлы JAR как часть выпуска и/или лицензирования программного обеспечения.

Доверяемая Запись Сертификата

Этот тип записи содержит единственный сертификат с открытым ключом, принадлежащий другой стороне. Это вызывают доверяемым сертификатом, потому что keystore владелец полагает, что открытый ключ в сертификате действительно принадлежит идентификационным данным, идентифицированным предметом (владелец) сертификата.

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

Каждая запись в keystore идентифицируется строкой "псевдонима". В случае закрытых ключей и их связанных цепочек сертификата, эти строки различают среди различных путей, которыми объект может аутентифицировать себя. Например, объект может аутентифицировать себя, используя различные центры сертификации, или используя различные алгоритмы с открытым ключом.

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

Основное KeyStore методы описываются ниже.

Создание a KeyStore Объект

KeyStore объекты получаются при использовании одного из KeyStore getInstance() статические методы фабрики.

Загрузка Определенного Keystore в Память

Прежде a KeyStore объект может использоваться, фактические keystore данные должны быть загружены в память через load метод:
final void load(InputStream stream, char[] password)
Дополнительный пароль используется, чтобы проверить целостность keystore данных. Если никакой пароль не предоставляется, никакая проверка целостности не выполняется.

Чтобы создать пустой keystore, Вы передаете null как InputStream параметр load метод.

Получение Списка Псевдонимов Keystore

Ко всем keystore записям получают доступ через уникальные псевдонимы. aliases метод возвращает перечисление имен псевдонима в keystore:

final Enumeration aliases()

Определение Типы Записи Keystore

Как утверждено в KeyStore Класс, есть два различных типов записей в keystore.

Следующие методы определяют, является ли запись, определенная данным псевдонимом, ключом/сертификатом или доверяемой записью сертификата, соответственно:

final boolean isKeyEntry(String alias)
final boolean isCertificateEntry(String alias)

Добавление/Установка/Удаление Кеистор Энтрис

setCertificateEntry метод присваивает сертификат указанному псевдониму:
final void setCertificateEntry(String alias, Certificate cert)
Если alias не существует, запись сертификата, которой доверяют, с тем псевдонимом создается. Если alias существует и идентифицирует доверяемую запись сертификата, сертификат, связанный с нею, заменяется cert.

setKeyEntry методы добавляют (если alias еще не существует), или установите ключевые записи:

final void setKeyEntry(String alias,
                       Key key,
                       char[] password,
                       Certificate[] chain)

final void setKeyEntry(String alias,
                       byte[] key,
                       Certificate[] chain)
В методе с key как байтовый массив, это - байты для ключа в защищенном формате. Например, в keystore реализации, предоставленной SUN провайдер, key байтовый массив, как ожидают, будет содержать защищенный закрытый ключ, закодированный как EncryptedPrivateKeyInfo как определено в стандарте PKCS8. В другом методе, password пароль, используемый, чтобы защитить ключ.

deleteEntry метод удаляет запись:

final void deleteEntry(String alias)

Получение информации от Keystore

getKey метод возвращает ключ, связанный с данным псевдонимом. Ключ восстанавливается, используя данный пароль:
final Key getKey(String alias, char[] password)
Следующие методы возвращают сертификат, или цепочку сертификата, соответственно, связанный с данным псевдонимом:
final Certificate getCertificate(String alias)
final Certificate[] getCertificateChain(String alias)
Можно определить имя (alias) из первой записи, сертификат которой соответствует данный сертификат через следующее:
final String getCertificateAlias(Certificate cert)

Сохранение KeyStore

keystore в памяти может быть сохранен через store метод:
final void store(OutputStream stream, char[] password)
Пароль используется, чтобы вычислить контрольную сумму целостности keystore данных, которые добавляются к keystore данным.

Классы Параметров алгоритма

Как Keys и Keyspecs, параметры инициализации алгоритма представляются также AlgorithmParameters или AlgorithmParameterSpecs. В зависимости от ситуации с использованием алгоритмы могут использовать параметры непосредственно, или параметры, возможно, должны были бы быть преобразованы в более переносимый формат для передачи или хранения.

Прозрачное представление ряда параметров (через AlgorithmParameterSpec) средства, что можно получить доступ к каждому значению параметра в наборе индивидуально. Можно получить доступ к этим значениям через один из get методы, определенные в соответствующей спецификации class (например, DSAParameterSpec определяет getP, getQ, и getG методы, к доступу p, q, и g, соответственно).

Напротив, AlgorithmParameters class предоставляет непрозрачное представление, в котором у Вас нет никакого прямого доступа к полям параметра. Можно только получить имя алгоритма, связанного с набором параметра (через getAlgorithm) и некоторое кодирование для набора параметра (через getEncoded).

AlgorithmParameterSpec Интерфейс

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

Интерфейсы спецификации параметра алгоритма и классы в java.security.spec и javax.crypto.spec пакеты описываются в JDK javadocs:

Следующие спецификации параметра алгоритма используются определенно для цифровых подписей как часть JSR 105.

AlgorithmParameters Класс

AlgorithmParameters class является механизмом class, который обеспечивает непрозрачное представление криптографических параметров. Можно инициализировать AlgorithmParameters class используя определенное AlgorithmParameterSpec объект, или кодируя параметры в распознанном формате. Можно получить получающуюся спецификацию с getParameterSpec метод (см. следующий раздел).

Создание AlgorithmParameters Объект

AlgorithmParameters объекты получаются при использовании одного из AlgorithmParameters getInstance() статические методы фабрики.

Инициализация AlgorithmParameters Объект

Однажды AlgorithmParameters объект инстанцируют, он должен быть инициализирован через звонок init, использование соответствующей спецификации параметра или кодирование параметра:

void init(AlgorithmParameterSpec paramSpec)
void init(byte[] params)
void init(byte[] params, String format)
В них init методы, params массив, содержащий закодированные параметры, и format имя формата декодирования. В init метод с a params параметр, но нет format параметр, основной формат декодирования для параметров используется. Основной формат декодирования является ASN.1, если спецификация ASN.1 для параметров существует.
ОТМЕТЬТЕ: AlgorithmParameters объекты могут быть инициализированы только однажды. Они не являются допускающими повторное использование.

Получение Закодированных Параметров

Кодирование байта параметров, представленных в AlgorithmParameters объект может быть получен через звонок getEncoded:

byte[] getEncoded()
Этот метод возвращает параметры в их основном формате кодирования. Основной формат кодирования для параметров является ASN.1, если спецификация ASN.1 для этого типа параметров существует.

Если Вы хотите параметры, возвращенные в указанном формате кодирования, использовать

byte[] getEncoded(String format)
Если format нуль, основной формат кодирования для параметров используется, как в другом getEncoded метод.
ОТМЕТЬТЕ: В значении по умолчанию AlgorithmParameters реализация, предоставленная SUN провайдер, format параметр в настоящий момент игнорируется.

Преобразование AlgorithmParameters Объект к Прозрачной Спецификации

Прозрачная спецификация параметра для параметров алгоритма может быть получена из AlgorithmParameters объект через звонок getParameterSpec:

AlgorithmParameterSpec getParameterSpec(Class paramSpec)
paramSpec идентифицирует спецификацию class, в котором должны быть возвращены параметры. Спецификация class могла быть, например, DSAParameterSpec.class указать, что параметры должны быть возвращены в экземпляре DSAParameterSpec class. (Этот class находится в java.security.spec пакет.)

AlgorithmParameterGenerator Класс

AlgorithmParameterGenerator class является механизмом class, используемый, чтобы генерировать ряд совершенно новых параметров, подходящих для определенного алгоритма (алгоритм определяется когда AlgorithmParameterGenerator экземпляр создается). Этот объект используется, когда Вы не имеете существующего набора параметров алгоритма, и хотите генерировать тот с нуля.

Создание AlgorithmParameterGenerator Объект

AlgorithmParameterGenerator объекты получаются при использовании одного из AlgorithmParameterGenerator getInstance() статические методы фабрики.

Инициализация AlgorithmParameterGenerator Объект

AlgorithmParameterGenerator объект может быть инициализирован двумя различными способами: независимый от алгоритма способ или специфичный для алгоритма способ.

Независимый от алгоритма подход использует факт, что все генераторы параметра совместно используют понятие "размера" и источник случайности. Мера размера универсально совместно используется всеми параметрами алгоритма, хотя это интерпретируется по-другому для различных алгоритмов. Например, в случае параметров для алгоритма DSA, "размер" соответствует размеру главного модуля в битах. (См. документ Стандартных имен для информации о размерах для определенных алгоритмов.) При использовании этого подхода, специфичных для алгоритма значений генерации параметра - если любой - значение по умолчанию к некоторым стандартным значениям. Один init метод, который берет эти два универсально совместно используемых типа параметров:

void init(int size, SecureRandom random);
Другой init метод берет только a size параметр и использование обеспеченный системой источник случайности:
void init(int size)

Третий подход инициализирует объект генератора параметра использование специфичной для алгоритма семантики, которые представляются рядом специфичных для алгоритма значений генерации параметра, предоставленных в AlgorithmParameterSpec объект:

void init(AlgorithmParameterSpec genParamSpec,
                          SecureRandom random)

void init(AlgorithmParameterSpec genParamSpec)
Чтобы генерировать системные параметры Diffie-Hellman, например, значения генерации параметра обычно состоят из размера главного модуля и размера случайной экспоненты, оба определенные в числе битов.

Генерирование Параметров Алгоритма

Как только Вы создали и инициализировали AlgorithmParameterGenerator объект, можно использовать generateParameters метод, чтобы генерировать параметры алгоритма:
AlgorithmParameters generateParameters()

CertificateFactory Класс

CertificateFactory class является механизмом class, который определяет функциональность фабрики сертификата, которая используется, чтобы генерировать список аннулированных сертификатов и список аннулированных сертификатов (CRL) объекты от их кодировок.

Фабрика сертификата для X.509 должна возвратить сертификаты, которые являются экземпляром java.security.cert.X509Certificate, и CRL, которые являются экземпляром java.security.cert.X509CRL.

Создание a CertificateFactory Объект

CertificateFactory объекты получаются при использовании одного из getInstance() статические методы фабрики.

Генерирование Объектов Сертификата

Чтобы генерировать сертификат возражают и инициализируют это с данными, считанными из входного потока, используют generateCertificate метод:
final Certificate generateCertificate(InputStream inStream)
Чтобы возвратиться (возможно пустой) представление набора сертификатов, считанных из данного входного потока, используйте generateCertificates метод:
final Collection generateCertificates(InputStream inStream)

Генерирование Объектов CRL

Чтобы генерировать список аннулированных сертификатов (CRL) возражают и инициализируют это с данными, считанными из входного потока, используют generateCRL метод:
final CRL generateCRL(InputStream inStream)
Чтобы возвратиться (возможно пустой) представление набора CRL, считанных из данного входного потока, используйте generateCRLs метод:
final Collection generateCRLs(InputStream inStream)

Генерирование CertPath Объекты

Разработчик пути сертификата и блок проверки допустимости для PKIX определяются Интернетом Сертификат Инфраструктуры управления открытыми ключами X.509 и Профиль CRL, RFC 3280.

Реализация хранилища сертификата для того, чтобы получить сертификаты и CRL из каталогов Collection и LDAP, используя PKIX LDAP V2 Схема также доступна от IETF как RFC 2587.

Генерировать a CertPath возразите и инициализируйте это с данными, считанными из входного потока, используйте один из следующих generateCertPath методы (с или не определяя кодирование, которое будет использоваться для данных):

final CertPath generateCertPath(InputStream inStream)

final CertPath generateCertPath(InputStream inStream,
                                String encoding)
Генерировать a CertPath возразите и инициализируйте это со списком сертификатов, используйте следующий метод:
final CertPath generateCertPath(List certificates)
Получать список CertPath кодировки, поддерживаемые этой фабрикой сертификата, можно вызвать getCertPathEncodings метод:
final Iterator getCertPathEncodings()
Кодировка по умолчанию будет перечислена сначала.

Как JCA Мог бы Использоваться в Реализации SSL/TLS

С пониманием классов JCA рассмотрите, как эти классы могли бы быть объединены, чтобы реализовать усовершенствованный сетевой протокол как SSL/TLS. Раздел Краткого обзора SSL/TLS в Справочнике JSSE описывает на высоком уровне, как протоколы работают. Поскольку асимметричные операции шифра (с открытым ключом) намного медленнее чем симметричные операции (секретный ключ), шифрование с открытым ключом используется, чтобы установить секретные ключи, которые тогда используются, чтобы защитить фактические данные приложения. Значительно упрощенный, квитирование SSL/TLS включает данные инициализации обмена, выполнение некоторых операций с открытым ключом, чтобы достигнуть секретного ключа, и затем использования того ключа, чтобы зашифровать дальнейший трафик.
ОТМЕТЬТЕ: детали, представленные здесь просто, показывают, как могли бы использоваться некоторые из вышеупомянутых классов. Этот раздел не будет представлять достаточную информацию для создания реализации SSL/TLS. Для получения дополнительной информации, пожалуйста, см. Справочник JSSE и RFC 2246: Протокол TLS.

Предположите, что эта реализация SSL/TLS будет сделана доступной как провайдер JSSE. Конкретная реализация Provider class сначала пишется, который будет в конечном счете зарегистрирован в Security class' список провайдеров. Этот провайдер, главным образом, обеспечивает отображение от имен алгоритма до фактических классов реализации. (который является: "SSLContext. TLS"-> "com.foo. TLSImpl"), Когда приложение запрашивает экземпляр "TLS" (через SSLContext.getInstance("TLS"), со списком провайдера консультируются для требуемого алгоритма, и соответствующий экземпляр создается.

Прежде, чем обсудить детали фактического квитирования, быстрый анализ части архитектуры JSSE необходим. Основа архитектуры JSSE SSLContext. Контекст в конечном счете создает объекты конца (SSLSocket и SSLEngine) которые фактически реализуют протокол SSL/TLS. SSLContexts инициализируются с двумя классами обратного вызова, KeyManager и TrustManager, которые позволяют приложениям сначала выбирать материал аутентификации, чтобы передаться и второй, чтобы проверить учетные данные, отправленные коллегой.

JSSE KeyManager ответственно за выбор который учетные данные представить коллеге. Много алгоритмов возможны, но общая стратегия состоит в том, чтобы поддержать RSA или пару "открытый/закрытый ключ" DSA наряду с a X509Certificate в a KeyStore поддержанный дисковым файлом. Когда a KeyStore объект инициализируется и загружается из файла, необработанные байты файла преобразовываются в PublicKey и PrivateKey объекты используя a KeyFactory, и сертификат байты цепочки преобразовывается, используя a CertificateFactory. Когда учетные данные необходимы, KeyManager просто консультируется с этим KeyStore возразите и определяет который учетные данные представить.

A KeyStore's содержание, возможно, был первоначально создан, используя утилиту такой как keytool. keytool создает RSA или DSA KeyPairGenerator и инициализирует это с соответствующим размером ключа. Этот генератор тогда используется, чтобы создать a KeyPair который keytool сохранил бы наряду с недавно создаваемым сертификатом в KeyStore, который в конечном счете пишется диску.

JSSE TrustManager ответственно за проверку учетных данных, полученных от коллеги. Есть много способов проверить учетные данные: один из них должен создать a CertPath объект, и позволял встроенной Инфраструктуре управления открытыми ключами JDK (PKI) дескриптор платформы проверка допустимости. Внутренне, реализация CertPath могла бы создать a Signature объект, и использование, что, чтобы проверить, что каждую из подписей в цепочке сертификата.

С этим основным пониманием архитектуры мы можем смотреть на некоторые из шагов в квитировании SSL/TLS. Клиент начинает, отправляя сообщение ClientHello серверу. Сервер выбирает ciphersuite, чтобы использовать, и отсылает это назад в сообщении ServerHello, и начинает создавать объекты JCA, основанные на выборе комплекта. Мы будем использовать аутентификацию только для сервера в следующих примерах.

Сообщения SSL/TSL

В первом примере сервер пытается использовать RSA-на-основе ciphersuite, такой как TLS_RSA_WITH_AES_128_CBC_SHA. Сервер KeyManager запрашивается, и возвращает соответствующую запись RSA. Учетные данные сервера (который является: сертификат/открытый ключ), отправляются в сообщении Сертификата сервера. Клиент TrustManager проверяет сертификат сервера, и если принято, клиент генерирует некоторые случайные байты, используя a SecureRandom объект. Это тогда шифруется, используя шифрующий асимметричный RSA Cipher объект, который был инициализирован с PublicKey найденный в сертификате сервера. Эти зашифрованные данные отправляются в Клиентском Ключевом сообщении Exchange. Сервер использовал бы свое соответствие PrivateKey восстановить байты, используя подобное Cipher в дешифруют режим. Эти байты тогда используются, чтобы установить фактические ключи шифрования.

В различном примере эфемерный алгоритм согласования ключей Diffie-Hellman наряду с алгоритмом подписи DSA выбирается, такие как TLS_DHE_DSS_WITH_AES_128_CBC_SHA. Эти две стороны должны каждый установить новый временный DH общедоступная/частная пара ключей, используя a KeyPairGenerator. Каждый генератор создает ключи DH, которые могут тогда быть далее преобразованы в части, используя KeyFactory и DHPublicKeySpec классы. Каждая сторона тогда создает a KeyAgreement возразите и инициализирует это с их соответствующим DH PrivateKeys. Сервер отправляет свои части с открытым ключом в сообщении ServerKeyExchange (защищенный алгоритмом подписи DSA, и клиент отправляет его открытый ключ в сообщении ClientKeyExchange. Когда открытые ключи повторно собираются, используя другого KeyFactory, они питаются в объекты соглашения. KeyAgreement объекты тогда генерируют согласованный байты, которые тогда используются, чтобы установить фактические ключи шифрования.

Как только фактические ключи шифрования были установлены, секретный ключ используется, чтобы инициализировать симметричное Cipher объект, и этот шифр используются, чтобы защитить все данные в пути. Помочь определить, были ли данные изменены, a MessageDigest создается и получает копию данных, предназначенных для сети. Когда пакет полон, обзор (хеш) добавляется к данным, и весь пакет шифруется Cipher. Если блочный шифр, такой как AES используется, данные должны быть дополнены, чтобы сделать полный блок. На удаленной стороне просто инвертируются шаги.

Снова, это значительно simplied, но дает общее представление, один из как эти классы могли бы быть объединены, чтобы создать высокоуровневый протокол.

Как Подать Заявки, "Освобожденные" от Криптографических Ограничений

Отметьте 1: Этот раздел должен быть проигнорирован большинством разработчиков приложений. Это только для людей, приложения которых могут быть экспортированы в те немного стран, правительства которых передают под мандат криптографические ограничения, если это требуется, чтобы у таких приложений было меньше криптографических ограничений чем переданные под мандат. Отметьте 2: Всюду по этому разделу термин "приложение" предназначается, чтобы охватить и приложения и апплеты.]

Платформа JCA включает возможность осуществить ограничения относительно криптографических алгоритмов и максимальных криптографических сильных мест, доступных апплетам/приложениям в различных контекстах юрисдикции (расположения). Любые такие ограничения определяются в "файлах политики юрисдикции".

Должный импортировать ограничения управления правительствами нескольких стран, файлы политики юрисдикции, поставленные с Java, Комплект разработчика 6 SE из Sun Microsystems определяет, что "strong", но ограниченная криптография может использоваться. "Неограниченная сила" версия этих файлов, не указывающих ни на какие ограничения на криптографические сильные места, доступна для тех, которые живут в имеющих право странах (который является большинством стран). Но только версия "strong" может быть импортирована в те страны, правительства которых передают под мандат ограничения. Платформа JCA осуществит ограничения, определенные в установленных файлах политики юрисдикции.

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

Для приложения, которое будет распознано как "освобожденный" во времени выполнения, это должно встретить следующие условия:

Ниже демонстрационные шаги, требуемые, чтобы подать заявку, освобожденную от некоторых или всех криптографических ограничений. Это - основная схема, которая включает информацию о том, что требуется JCA, чтобы распознать и обработать приложения, как являющиеся освобожденным. Вы должны будете знать требования освобождения определенной страны или стран, в которых требуется, чтобы Ваше приложение было в состоянии быть выполненными, но чьи правительства требуют криптографических ограничений. Вы должны будете также знать требования поставщика платформы JCA, у которого есть процесс на месте для того, чтобы обработать освобожденные приложения. Консультируйтесь с таким поставщиком для дополнительной информации. (ОТМЕТЬТЕ: SunJCE провайдер не предоставляет реализацию ExemptionMechanismSpi class.)


Специальные Требования Кода для Приложений то Освобождение Использования Механизмы

Когда у приложения есть файл политики разрешения, связанный с этим (в том же самом файле JAR), и тот файл политики разрешения определяет механизм освобождения, затем когда Шифр getInstance метод вызывают, чтобы инстанцировать Шифра, код JCA ищет установленных провайдеров тот, который реализует указанный механизм освобождения. Если это находит такого провайдера, JCA инстанцирует объекта API ExemptionMechanism, связанного с реализацией провайдера, и затем связывает объект ExemptionMechanism с Шифром, возвращенным getInstance.

После инстанцирования Шифра, и до инициализации этого (через звонок в Шифр init метод), Ваш код должен вызвать следующий метод Cipher:

    public ExemptionMechanism getExemptionMechanism()

Этот вызов возвращает объект ExemptionMechanism, связанный с Шифром. Следует тогда инициализировать реализацию механизма освобождения, вызывая следующий метод на возвращенном ExemptionMechanism:

    public final void init(Key key)

Параметром, который Вы предоставляете, должно быть то же самое как параметр тех же самых типов, что Вы впоследствии предоставите к Шифру init метод.

Как только Вы инициализировали ExemptionMechanism, можно продолжить как обычно, чтобы инициализировать и использовать Шифр.

Файлы Политики разрешения

Для приложения, которое будет распознано во времени выполнения, как являющемся "освобожденным" от некоторых или всех криптографических ограничений, у этого должен быть файл политики разрешения, связанный этим в файле JAR. Файл политики разрешения определяет, какие связанные с криптографией полномочия приложение имеет, и при каких условиях (если любой).

ОТМЕТЬТЕ: файл политики разрешения, связанный приложением, нужно назвать cryptoPerms.

Формат записи разрешения в файле политики разрешения, который сопровождает освобожденное приложение, является тем же самым как форматом для файла политики юрисдикции, загруженного JDK, который является:

    permission <crypto permission class name>[ <alg_name>
        [[, <exemption mechanism name>][, <maxKeySize>
        [, <AlgorithmParameterSpec class name>,
        <parameters for constructing an AlgorithmParameterSpec object>
        ]]]];

См. Приложение B для получения дополнительной информации о формате файла политики юрисдикции.

Файлы Политики разрешения для Освобожденных Приложений

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

    grant {
        // There are no restrictions to any algorithms.
        permission javax.crypto.CryptoAllPermission;
    };

Если приложение только использует единственный алгоритм (или несколько определенных алгоритмов), то файл политики разрешения мог просто упомянуть что алгоритм (или алгоритмы) явно, вместо того, чтобы предоставить CryptoAllPermission. Например, если приложение только использует алгоритм Шифра, файл политики разрешения не должен предоставить CryptoAllPermission всем алгоритмам. Это могло только определить, что нет никакого криптографического ограничения, если алгоритм Шифра используется. Чтобы сделать это, файл политики разрешения был бы похож на следующее:

    grant {
        permission javax.crypto.CryptoPermission "Blowfish";
    };

Файлы Политики разрешения для Приложений, Освобожденных из-за Механизмов Освобождения

Если заявление рассматривается "освобожденное", если механизм освобождения осуществляется, то файл политики разрешения, который сопровождает приложение, должен определить один или более механизмов освобождения. Во времени выполнения заявление будет рассмотрено освобожденное, если какой-либо из тех механизмов освобождения будет осуществлен. Каждый механизм освобождения должен быть определен в записи разрешения, которая похожа на следующее:

    // No algorithm restrictions if specified
    // exemption mechanism is enforced.
    permission javax.crypto.CryptoPermission *, 
        "<ExemptionMechanismName>";

где <ExemptionMechanismName> определяет имя механизма освобождения. Список возможных имен механизма освобождения включает:

Как пример, предположите, что Ваше приложение освобождено, если или ключевое восстановление или ключевое условное депонирование осуществляются. Затем Ваш файл политики разрешения должен содержать следующее:
    grant {
        // No algorithm restrictions if KeyRecovery is enforced.
        permission javax.crypto.CryptoPermission *, 
            "KeyRecovery";
        // No algorithm restrictions if KeyEscrow is enforced.
        permission javax.crypto.CryptoPermission *, 
            "KeyEscrow";
    };

ОТМЕТЬТЕ: записи Разрешения, которые определяют механизмы освобождения, не должны также определить максимальные размеры ключа. Позволенные размеры ключа фактически определяются от установленных освобожденных файлов политики юрисдикции, как описано в следующем разделе.

Как Связанные Файлы Политики Разрешения Влияют на Криптографические Полномочия

Во времени выполнения, когда приложение инстанцирует Шифра (через звонок в getInstance метод), и у того приложения есть связанный файл политики разрешения, проверки JCA, чтобы видеть, есть ли у файла политики разрешения запись, которая применяется к алгоритму, определенному в getInstance вызвать. Если это делает, и запись предоставляет CryptoAllPermission или не определяет, что механизм освобождения должен быть осуществлен, это означает, что нет никакого криптографического ограничения для этого определенного алгоритма.

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

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

Примеры кода

Вот некоторые короткие примеры, которые иллюстрируют использование нескольких из механизмов JCA. Кроме того, полные рабочие примеры могут быть найдены в Приложении D.

Вычисления a MessageDigest Объект

Сначала создайте объект обзора сообщения, как в следующем примере:

MessageDigest sha = MessageDigest.getInstance("SHA-1");
Этот вызов присваивает должным образом инициализированный объект обзора сообщения sha переменная. Реализация реализует Безопасный Хеш-алгоритм (SHA 1), как определено в Национальном Институте Стандартов и Технология (NIST) FIPS 180-2 документа. См. Приложение A для полного обсуждения стандартных имен и алгоритмов.

Затем, предположите, что у нас есть три байтовых массива, i1, i2 и i3, которые формируют общие затраты, обзор сообщения которых мы хотим вычислить. Этот обзор (или "хеш") мог быть вычислен через следующие вызовы:

sha.update(i1);
sha.update(i2);
sha.update(i3);
byte[] hash = sha.digest();

Эквивалентная альтернативная серия вызовов была бы:

sha.update(i1);
sha.update(i2);
byte[] hash = sha.digest(i3);
После того, как обзор сообщения был вычислен, объект обзора сообщения автоматически сбрасывается и готов получить новые данные и вычислить его обзор. Все прежнее состояние (то есть, данные, снабженные к update вызовы), теряется.

Некоторые реализации хеша могут поддерживать промежуточные хеши посредством клонирования. Предположите, что мы хотим вычислить отдельные хеши для:

Способ сделать это:

/* compute the hash for i1 */
sha.update(i1);
byte[] i1Hash = sha.clone().digest();

/* compute the hash for i1 and i2 */
sha.update(i2);
byte[] i12Hash = sha.clone().digest();

/* compute the hash for i1, i2 and i3 */
sha.update(i3);
byte[] i123hash = sha.digest();
Этот код работает, только если SHA 1 реализация является cloneable. В то время как некоторые реализации обзоров сообщения являются cloneable, другие не. Определить, возможно ли клонирование, попытка клонироваться MessageDigest возразите и поймайте потенциальное исключение следующим образом:
try {
    // try and clone it
    /* compute the hash for i1 */
    sha.update(i1);
    byte[] i1Hash = sha.clone().digest();
    . . .
    byte[] i123hash = sha.digest();
} catch (CloneNotSupportedException cnse) {
    // do something else, such as the code shown below
}
Если обзор сообщения не является cloneable, другим, менее изящный способ вычислить промежуточные обзоры состоит в том, чтобы создать несколько обзоров. В этом случае число промежуточных обзоров, которые будут вычислены, должно быть известно заранее:
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
MessageDigest sha12 = MessageDigest.getInstance("SHA-1");
MessageDigest sha123 = MessageDigest.getInstance("SHA-1");

byte[] i1Hash = sha1.digest(i1);

sha12.update(i1);
byte[] i12Hash = sha12.digest(i2);

sha123.update(i1);
sha123.update(i2);
byte[] i123Hash = sha123.digest(i3);

Генерирование Пары Ключей

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

Создание Генератора Пары ключей

Первый шаг должен получить объект генератора пары ключей для того, чтобы он генерировал ключи для алгоритма DSA:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");

Инициализация Генератора Пары ключей

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

Независимая от алгоритма Инициализация

Все генераторы пары ключей совместно используют понятие размера ключа и источник случайности. KeyPairGenerator Методы инициализации class в минимуме нуждаются в размере ключа. Если источник случайности явно не обеспечивается, a SecureRandom реализация самого высокого приоритета установленный провайдер будет использоваться. Таким образом, чтобы генерировать ключи с размером ключа 1024, просто вызовите:

SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyGen.initialize(1024, random);
Следующий код иллюстрирует, как использовать определенное, дополнительно отобранное SecureRandom объект:
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
random.setSeed(userSeed);
keyGen.initialize(1024, random);
Так как никакие другие параметры не определяются, когда Вы вызываете вышеупомянутое независимое от алгоритма initialize метод, это до провайдера, что сделать о специфичных для алгоритма параметрах (если любой), чтобы быть связанным с каждым из ключей. Провайдер может использовать предварительно вычисленные значения параметра или может генерировать новые значения.

Специфичная для алгоритма Инициализация

Для ситуаций, где ряд специфичных для алгоритма параметров уже существует (такие как "параметры сообщества" в DSA), есть два initialize методы, которые имеют AlgorithmParameterSpec параметр. Предположите, что Ваш генератор пары ключей для алгоритма "DSA", и у Вас есть ряд специфичных для DSA параметров, p, q, и g, то, что требуется использовать, чтобы генерировать Вашу пару ключей. Вы могли выполниться, следующий код, чтобы инициализировать Ваш генератор пары ключей (вспомните это DSAParameterSpec AlgorithmParameterSpec):

DSAParameterSpec dsaSpec = new DSAParameterSpec(p, q, g);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
random.setSeed(userSeed);
keyGen.initialize(dsaSpec, random);
ОТМЕТЬТЕ: параметр называют p простое число, длина которого является длиной модуля ("размер"). Поэтому, Вы не должны вызвать никакой другой метод, чтобы определить длину модуля.

Генерирование Пары Ключей

Заключительный шаг фактически генерирует пару ключей. Независимо от того, какой тип инициализации использовался (независимый от алгоритма или специфичный для алгоритма), тот же самый код используется, чтобы генерировать пару ключей:
KeyPair pair = keyGen.generateKeyPair();

Генерирование и Проверка Подписи Используя Сгенерированные Ключи

Следующая генерация подписи и примеры проверки используют KeyPair сгенерированный в примере пары ключей выше.

Генерирование Подписи

Мы сначала создаем объект подписи:

Signature dsa = Signature.getInstance("SHA1withDSA");
Затем используя пару ключей, сгенерированную в примере пары ключей, мы инициализируем объект с закрытым ключом, затем подписываем вызванный байтовый массив data.
/* Initializing the object with a private key */
PrivateKey priv = pair.getPrivate();
dsa.initSign(priv);

/* Update and sign the data */
dsa.update(data);
byte[] sig = dsa.sign();

Проверка Подписи

Проверка подписи является прямой. (Отметьте, что здесь мы также используем пару ключей, сгенерированную в примере пары ключей.)
/* Initializing the object with the public key */
PublicKey pub = pair.getPublic();
dsa.initVerify(pub);

/* Update and verify the data */
dsa.update(data);
boolean verifies = dsa.verify(sig);
System.out.println("signature verifies: " + verifies);

Генерирование/Проверка Подписей Используя Ключевые Спецификации и KeyFactory

Предположите, что, вместо того, чтобы иметь пару "открытый/закрытый ключ" (как, например, был сгенерирован в примере пары ключей выше), у Вас просто есть компоненты Вашего закрытого ключа DSA: x (закрытый ключ), p (начало), q (субстандартное), и g (основа).

Далее предположите, что Вы хотите использовать свой закрытый ключ, чтобы в цифровой форме подписать некоторые данные, которые находятся в названном байтовом массиве someData. Вы сделали бы следующие шаги, которые также иллюстрируют создание ключевой спецификации и использование ключевой фабрики, чтобы получить a PrivateKey от ключевой спецификации (initSign требует a PrivateKey):

DSAPrivateKeySpec dsaPrivKeySpec = new DSAPrivateKeySpec(x, p, q, g);

KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PrivateKey privKey = keyFactory.generatePrivate(dsaPrivKeySpec);

Signature sig = Signature.getInstance("SHA1withDSA");
sig.initSign(privKey);
sig.update(someData);
byte[] signature = sig.sign();
Предположите, что Элис хочет использовать данные, которые Вы подписали. Для нее, чтобы сделать так, и проверить Вашу подпись, Вы должны отправить ей три вещи:
  1. данные,
  2. подпись, и
  3. открытый ключ, соответствующий закрытому ключу, Вы имели обыкновение подписывать данные.
Можно сохранить someData байты в одном файле, и signature байты в другом, и отправляют тех Элис.

Для открытого ключа примите, как в примере подписания выше, у Вас есть компоненты соответствия открытого ключа DSA закрытому ключу DSA, используемому, чтобы подписать данные. Затем можно создать a DSAPublicKeySpec от тех компонентов:

DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(y, p, q, g);
Вы все еще должны извлечь ключевые байты так, чтобы можно было поместить их в файл. Чтобы сделать так, можно сначала вызвать generatePublic метод на ключевой фабрике DSA, уже создаваемой в примере выше:
PublicKey pubKey = keyFactory.generatePublic(dsaPubKeySpec);
Затем можно извлечь (закодированные) ключевые байты через следующее:
byte[] encKey = pubKey.getEncoded();
Можно теперь сохранить эти байты в файле, и отправить его Элис наряду с файлами, содержащими данные и подпись.

Теперь, предположите, что Элис получила эти файлы, и она скопировала байты данных от файла данных до названного байтового массива data, байты подписи от файла подписи до байтового массива называют signature, и закодированные байты с открытым ключом от файла с открытым ключом до байтового массива называют encodedPubKey.

Элис может теперь выполнить следующий код, чтобы проверить подпись. Код также иллюстрирует, как использовать ключевую фабрику, чтобы инстанцировать открытого ключа DSA от его кодирования (initVerify требует a PublicKey).

    X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encodedPubKey);

    KeyFactory keyFactory = KeyFactory.getInstance("DSA");
    PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);

    Signature sig = Signature.getInstance("SHA1withDSA");
    sig.initVerify(pubKey);
    sig.update(data);
    sig.verify(signature);
ОТМЕТЬТЕ: В вышеупомянутом Элис должна была генерировать a PublicKey от закодированных ключевых битов, с тех пор initVerify требует a PublicKey. Как только у нее есть a PublicKey, она могла также использовать KeyFactory getKeySpec метод, чтобы преобразовать это в a DSAPublicKeySpec так, чтобы она могла получить доступ к компонентам, при желании, как в:
    DSAPublicKeySpec dsaPubKeySpec =
        (DSAPublicKeySpec)keyFactory.getKeySpec(pubKey,
            DSAPublicKeySpec.class)
Теперь она может получить доступ к компонентам открытого ключа DSA y, p, q, и g посредством соответствия "надевают" методы DSAPublicKeySpec class (getY, getP, getQ, и getG).

Определение, равны Ли Два Ключа

Во многих случаях требуется знать, равны ли два ключа; однако, метод значения по умолчанию java.lang.Object.equals возможно, не дает требуемый результат. Самый независимый от провайдера подход должен сравнить закодированные ключи. Если это сравнение не является соответствующим (например, сравниваясь RSAPrivateKey и RSAPrivateCrtKey), следует сравнить каждый компонент. Следующий код демонстрирует эту идею:

static boolean keysEqual(Key key1, Key key2) {
    if (key1.equals(key2)) {
        return true;
    }

    if (Arrays.equals(key1.getEncoded(), key2.getEncoded())) {
        return true;
    }

    // More code for different types of keys here.
    // For example, the following code can check if
    // an RSAPrivateKey and an RSAPrivateCrtKey are equal:
    // if ((key1 instanceof RSAPrivateKey) &&
    //     (key2 instanceof RSAPrivateKey)) {
    //     if ((key1.getModulus().equals(key2.getModulus())) &&
    //         (key1.getPrivateExponent().equals(
    //                                      key2.getPrivateExponent()))) {
    //         return true;
    //     }
    // }

    return false;
}

Чтение Base64-закодированных Сертификатов

Следующий пример читает файл с Base64-закодированными сертификатами, которые каждый ограничиваются вначале

-----BEGIN CERTIFICATE-----
и в конце
-----END CERTIFICATE-----
Мы преобразовываем FileInputStream (который не поддерживает mark и reset) к a ByteArrayInputStream (который поддерживает те методы), так, чтобы каждый звонок generateCertificate использует только один сертификат, и позиция чтения входного потока располагается в следующий сертификат в файле:
FileInputStream fis = new FileInputStream(filename);
BufferedInputStream bis = new BufferedInputStream(fis);

CertificateFactory cf = CertificateFactory.getInstance("X.509");

while (bis.available() > 0) {
    Certificate cert = cf.generateCertificate(bis);
    System.out.println(cert.toString());
}

Парсинг Ответа Сертификата

Следующий пример анализирует PKCS7-отформатированный ответ сертификата, сохраненный в файле, и извлекает все сертификаты из этого:

FileInputStream fis = new FileInputStream(filename);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Collection c = cf.generateCertificates(fis);
Iterator i = c.iterator();
while (i.hasNext()) {
   Certificate cert = (Certificate)i.next();
   System.out.println(cert);
}

Используя Шифрование

Этот раздел берет пользователя посредством процесса генерирования ключа, создания и инициализации объекта шифра, шифрования файла, и затем дешифрования этого. Всюду по этому примеру мы используем Усовершенствованный стандарт шифрования (AES).

Генерирование Ключа

Чтобы создать ключ AES, мы должны инстанцировать KeyGenerator для AES. Мы не определяем провайдера, потому что мы не заботимся об определенной реализации генерации ключей AES. Так как мы не инициализируем KeyGenerator, обеспеченный системой источник случайности и размера ключа значения по умолчанию будет использоваться, чтобы создать ключ AES:

    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    SecretKey aesKey = keygen.generateKey();

После того, как ключ был сгенерирован, тот же самый объект KeyGenerator может быть снова использован, чтобы создать дальнейшие ключи.

Создание Шифра

Следующий шаг должен создать экземпляр Шифра. Чтобы сделать это, мы используем один из getInstance методы фабрики Шифра class. Мы должны определить имя требуемого преобразования, которое включает следующие компоненты, разделенные наклонными чертами (/):

В этом примере мы создаем шифр AES в Электронном режиме Книги шифров с дополнением PKCS5-стиля. Мы не определяем провайдера, потому что мы не заботимся об определенной реализации требуемого преобразования.

Стандартное имя алгоритма для AES является "AES", стандартное имя для Электронного режима Книги шифров является "ECB", и стандартное имя для дополнения PKCS5-стиля является "PKCS5Padding":

    Cipher aesCipher;
    
    // Create the cipher
    aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

Мы используем сгенерированный aesKey сверху, чтобы инициализировать Шифр возражают для шифрования:

    // Initialize the cipher for encryption
    aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
          
    // Our cleartext
    byte[] cleartext = "This is just an example".getBytes();
          
    // Encrypt the cleartext
    byte[] ciphertext = aesCipher.doFinal(cleartext);

    // Initialize the same cipher for decryption
    aesCipher.init(Cipher.DECRYPT_MODE, aesKey);
      
    // Decrypt the ciphertext
    byte[] cleartext1 = aesCipher.doFinal(ciphertext);

cleartext и cleartext1 идентичны.

Используя Основанное на пароле Шифрование

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

Казалось бы логичным собрать и сохранить пароль в объекте типа java.lang.String. Однако, вот протест: Объекты типа String являются неизменными, то есть, нет никаких методов, определенных, которые позволяют, Вы, чтобы измениться (перезаписываете) или обнуляете содержание a String после использования. Эта функция делает String объекты, неподходящие для того, чтобы сохранить уязвимую информацию безопасности, такую как пользовательские пароли. Следует всегда собирать и хранить уязвимую информацию безопасности в массиве случайной работы вместо этого.

По этой причине, javax.crypto.spec.PBEKeySpec class берет (и возвраты) пароль как массив случайной работы. См. ReadPassword class в примере кода в Приложении D для одного возможного способа считать символьные пароли массива из входного потока.

Чтобы использовать Основанное на пароле Шифрование (PBE) как определено в PKCS5, мы должны определить соль и итеративное количество. Та же самая соль и итеративное количество, которые используются для шифрования, должны использоваться для дешифрования:

            PBEKeySpec pbeKeySpec;
            PBEParameterSpec pbeParamSpec;
            SecretKeyFactory keyFac;

            // Salt
            byte[] salt = {
                (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
                (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
            };

            // Iteration count
            int count = 20;

            // Create PBE parameter set
            pbeParamSpec = new PBEParameterSpec(salt, count);

            // Prompt user for encryption password.
            // Collect user password as char array (using the
            // "readPassword" method from above), and convert
            // it into a SecretKey object, using a PBE key
            // factory.
            System.out.print("Enter encryption password:  ");
            System.out.flush();
            pbeKeySpec = new PBEKeySpec(readPassword(System.in));
            keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);

            // Create PBE Cipher
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");

            // Initialize PBE Cipher with key and parameters
            pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

            // Our cleartext
            byte[] cleartext = "This is another example".getBytes();

            // Encrypt the cleartext
            byte[] ciphertext = pbeCipher.doFinal(cleartext);
            

Используя Согласование ключей

Пожалуйста, сошлитесь на Приложение D для примеров программ, осуществляющих Обмен ключами Диффи-Хеллмана между 2 и 3 сторонами.


Приложение A: Стандартные имена

API Безопасности JDK требует и использует ряд стандартных имен для алгоритмов, сертификата и типов keystore. Спецификация называет ранее найденным здесь в Приложении A и в других спецификациях безопасности (JSSE/CertPath/etc). были объединены в документе Стандартных имен. Этот документ также содержит больше информации о спецификациях алгоритма. Определенная информация о провайдере может быть найдена в Документации Провайдера солнца.

Криптографические реализации на солнце JDK распределяются через несколько различных провайдеров прежде всего по историческим причинам (Sun, SunJSSE, SunJCE, SunRsaSign). Отметьте, что эти провайдеры, возможно, не доступны на всех реализациях JDK, и поэтому, действительно переносимые приложения должны вызвать getInstance() не определяя определенных провайдеров. Приложения, определяющие определенного провайдера, возможно, не в состоянии использовать в своих интересах собственных провайдеров, настроенных для базовой операционной среды (таких как PKCS или CAPI Microsoft).

SunPKCS11 сам провайдер не содержит криптографических алгоритмов, но вместо этого, направляет запросы в базовую реализацию PKCS11. Со Справочником PKCS11 и базовой реализацией PKCS11 нужно консультироваться, чтобы определить, будет ли требуемый алгоритм доступен через провайдера PKCS11. Аналогично, на системах Windows, SunMSCAPI провайдер не обеспечивает криптографической функциональности, но вместо этого направляет запросы к базовой Операционной системе для того, чтобы обработать.


Приложение B: Формат файла Политики Юрисдикции

JCA представляет свои файлы политики юрисдикции как файлы политики стиля Java с соответствующими операторами разрешения. Как описано в Синтаксисе Файла Реализации и Политики Политики Значения по умолчанию, файл политики Java определяет то, что полномочия позволяются для кода из указанных источников кода. Разрешение представляет доступ к системному ресурсу. В случае JCA "ресурсы" являются алгоритмами криптографии, и кодируют источники, не должны быть определены, потому что криптографические ограничения применяются ко всему коду.

Файл политики юрисдикции состоит из очень основной "записи предоставления", содержащей одну или более "записей разрешения."

grant {
<permission entries>;
};

Формат записи разрешения в файле политики юрисдикции:

permission <crypto permission class name>[ <alg_name>
    [[, <exemption mechanism name>][, <maxKeySize>
    [, <AlgorithmParameterSpec class name>,
    <parameters for constructing an 
        AlgorithmParameterSpec object>]]]];

Демонстрационный файл политики юрисдикции, который включает ограничение алгоритма "Шифра" в максимальные размеры ключа 64 битов:

    grant {
        permission javax.crypto.CryptoPermission "Blowfish", 64;
        . . .;
    };
    

Запись разрешения должна начаться со слова permission. <crypto permission class name> в шаблоне выше фактически было бы определенное разрешение имя class, такой как javax.crypto.CryptoPermission. crypto разрешение class отражает возможность приложения/апплета использовать определенные алгоритмы с определенными размерами ключа в определенных средах. Есть два crypto класса полномочий: CryptoPermission и CryptoAllPermission. Специальное предложение CryptoAllPermission class подразумевает все связанные с криптографией полномочия, то есть, он определяет, что нет никаких связанных с криптографией ограничений.

<alg_name>, когда использующийся, заключенная в кавычки строка, определяющая стандартное имя (см. Приложение A) алгоритма криптографии, такого как "DES" или "RSA".

<Имя механизма освобождения>, когда определено, является заключенной в кавычки строкой, указывающей на механизм освобождения, который, если осуществлено, включает сокращению криптографических ограничений. Имена механизма освобождения, которые могут использоваться, включают "KeyRecovery" "KeyEscrow", и "KeyWeakening".

<maxKeySize> является целым числом, определяющим, что максимальный размер ключа (в битах) учитывал указанный алгоритм.

Для некоторых алгоритмов, возможно, не достаточно определить стойкость алгоритма с точки зрения только размера ключа. Например, в случае алгоритма "RC5", число раундов нужно также рассмотреть. Для алгоритмов, сила которых должна быть выражена как больше чем размер ключа, запись разрешения должна также определить AlgorithmParameterSpec имя class (такой как javax.crypto.spec.RC5ParameterSpec) и список параметров для того, чтобы создать указанный объект AlgorithmParameterSpec.

Элементы, которые появляются в записи разрешения, должны появиться в указанном порядке. Запись завершается с точкой с запятой.

Случай незначителен для идентификаторов (grant, permission) но является существенным для <crypto permission class name> или для любой строки, в которой передают как значение.

ОТМЕТЬТЕ: "*" может использоваться в качестве подстановочного знака для любой опции записи разрешения. Например, "*" (без кавычек) для <alg_name> опции означает "все алгоритмы."


Приложение C: Максимальные Размеры ключа, Позволенные "Сильными" Файлами Политики Юрисдикции

Должный импортировать ограничения управления, файлы политики юрисдикции, поставленные с Java Комплект разработчика SE, позволяют "strong", но ограниченной криптографии, которая будет использоваться. Для большего количества информации, пожалуйста, см. Пределы Импорта на Криптографических алгоритмах.


Приложение D: Примеры программ

Обмен ключами Диффи-Хеллмана между 2 Сторонами

/*
 * Copyright (c) 1997, 2001, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import java.security.interfaces.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
import com.sun.crypto.provider.SunJCE;

/**
 * This program executes the Diffie-Hellman key agreement protocol
 * between 2 parties: Alice and Bob.
 *
 * By default, preconfigured parameters (1024-bit prime modulus and base
 * generator used by SKIP) are used.
 * If this program is called with the "-gen" option, a new set of
 * parameters is created.
 */

public class DHKeyAgreement2 {

    private DHKeyAgreement2() {}

    public static void main(String argv[]) {
        try {
            String mode = "USE_SKIP_DH_PARAMS";

            DHKeyAgreement2 keyAgree = new DHKeyAgreement2();

            if (argv.length > 1) {
                keyAgree.usage();
                throw new Exception("Wrong number of command options");
            } else if (argv.length == 1) {
                if (!(argv[0].equals("-gen"))) {
                    keyAgree.usage();
                    throw new Exception("Unrecognized flag: " + argv[0]);
                }
                mode = "GENERATE_DH_PARAMS";
            }

            keyAgree.run(mode);
        } catch (Exception e) {
            System.err.println("Error: " + e);
            System.exit(1);
        }
    }

    private void run(String mode) throws Exception {

        DHParameterSpec dhSkipParamSpec;

        if (mode.equals("GENERATE_DH_PARAMS")) {
            // Some central authority creates new DH parameters
            System.out.println
                ("Creating Diffie-Hellman parameters (takes VERY long) ...");
            AlgorithmParameterGenerator paramGen
                = AlgorithmParameterGenerator.getInstance("DH");
            paramGen.init(512);
            AlgorithmParameters params = paramGen.generateParameters();
            dhSkipParamSpec = (DHParameterSpec)params.getParameterSpec
                (DHParameterSpec.class);
        } else {
            // use some pre-generated, default DH parameters
            System.out.println("Using SKIP Diffie-Hellman parameters");
            dhSkipParamSpec = new DHParameterSpec(skip1024Modulus,
                                                  skip1024Base);
        }

        /*
         * Alice creates her own DH key pair, using the DH parameters from
         * above
         */
        System.out.println("ALICE: Generate DH keypair ...");
        KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
        aliceKpairGen.initialize(dhSkipParamSpec);
        KeyPair aliceKpair = aliceKpairGen.generateKeyPair();

        // Alice creates and initializes her DH KeyAgreement object
        System.out.println("ALICE: Initialization ...");
        KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
        aliceKeyAgree.init(aliceKpair.getPrivate());

        // Alice encodes her public key, and sends it over to Bob.
        byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();

        /*
         * Let's turn over to Bob. Bob has received Alice's public key
         * in encoded format.
         * He instantiates a DH public key from the encoded key material.
         */
        KeyFactory bobKeyFac = KeyFactory.getInstance("DH");
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec
            (alicePubKeyEnc);
        PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec);

        /*
         * Bob gets the DH parameters associated with Alice's public key.
         * He must use the same parameters when he generates his own key
         * pair.
         */
        DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams();

        // Bob creates his own DH key pair
        System.out.println("BOB: Generate DH keypair ...");
        KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
        bobKpairGen.initialize(dhParamSpec);
        KeyPair bobKpair = bobKpairGen.generateKeyPair();

        // Bob creates and initializes his DH KeyAgreement object
        System.out.println("BOB: Initialization ...");
        KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
        bobKeyAgree.init(bobKpair.getPrivate());

        // Bob encodes his public key, and sends it over to Alice.
        byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();

        /*
         * Alice uses Bob's public key for the first (and only) phase
         * of her version of the DH
         * protocol.
         * Before she can do so, she has to instantiate a DH public key
         * from Bob's encoded key material.
         */
        KeyFactory aliceKeyFac = KeyFactory.getInstance("DH");
        x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc);
        PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec);
        System.out.println("ALICE: Execute PHASE1 ...");
        aliceKeyAgree.doPhase(bobPubKey, true);

        /*
         * Bob uses Alice's public key for the first (and only) phase
         * of his version of the DH
         * protocol.
         */
        System.out.println("BOB: Execute PHASE1 ...");
        bobKeyAgree.doPhase(alicePubKey, true);

        /*
         * At this stage, both Alice and Bob have completed the DH key
         * agreement protocol.
         * Both generate the (same) shared secret.
         */
        byte[] aliceSharedSecret = aliceKeyAgree.generateSecret();
        int aliceLen = aliceSharedSecret.length;

        byte[] bobSharedSecret = new byte[aliceLen];
        int bobLen;
        try {
            // show example of what happens if you
            // provide an output buffer that is too short
            bobLen = bobKeyAgree.generateSecret(bobSharedSecret, 1);
        } catch (ShortBufferException e) {
            System.out.println(e.getMessage());
        }
        // provide output buffer of required size
        bobLen = bobKeyAgree.generateSecret(bobSharedSecret, 0);

        System.out.println("Alice secret: " +
          toHexString(aliceSharedSecret));
        System.out.println("Bob secret: " +
          toHexString(bobSharedSecret));

        if (!java.util.Arrays.equals(aliceSharedSecret, bobSharedSecret))
            throw new Exception("Shared secrets differ");
        System.out.println("Shared secrets are the same");

        /*
         * Now let's return the shared secret as a SecretKey object
         * and use it for encryption. First, we generate SecretKeys for the
         * "DES" algorithm (based on the raw shared secret data) and
         * then we use DES in ECB mode
         * as the encryption algorithm. DES in ECB mode does not require any
         * parameters.
         *
         * Then we use DES in CBC mode, which requires an initialization
         * vector (IV) parameter. In CBC mode, you need to initialize the
         * Cipher object with an IV, which can be supplied using the
         * javax.crypto.spec.IvParameterSpec class. Note that you have to use
         * the same IV for encryption and decryption: If you use a different
         * IV for decryption than you used for encryption, decryption will
         * fail.
         *
         * NOTE: If you do not specify an IV when you initialize the
         * Cipher object for encryption, the underlying implementation
         * will generate a random one, which you have to retrieve using the
         * javax.crypto.Cipher.getParameters() method, which returns an
         * instance of java.security.AlgorithmParameters. You need to transfer
         * the contents of that object (e.g., in encoded format, obtained via
         * the AlgorithmParameters.getEncoded() method) to the party who will
         * do the decryption. When initializing the Cipher for decryption,
         * the (reinstantiated) AlgorithmParameters object must be passed to
         * the Cipher.init() method.
         */
        System.out.println("Return shared secret as SecretKey object ...");
        // Bob
        // NOTE: The call to bobKeyAgree.generateSecret above reset the key
        // agreement object, so we call doPhase again prior to another
        // generateSecret call
        bobKeyAgree.doPhase(alicePubKey, true);
        SecretKey bobDesKey = bobKeyAgree.generateSecret("DES");

        // Alice
        // NOTE: The call to aliceKeyAgree.generateSecret above reset the key
        // agreement object, so we call doPhase again prior to another
        // generateSecret call
        aliceKeyAgree.doPhase(bobPubKey, true);
        SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES");

        /*
         * Bob encrypts, using DES in ECB mode
         */
        Cipher bobCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
        bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey);

        byte[] cleartext = "This is just an example".getBytes();
        byte[] ciphertext = bobCipher.doFinal(cleartext);

        /*
         * Alice decrypts, using DES in ECB mode
         */
        Cipher aliceCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
        aliceCipher.init(Cipher.DECRYPT_MODE, aliceDesKey);
        byte[] recovered = aliceCipher.doFinal(ciphertext);

        if (!java.util.Arrays.equals(cleartext, recovered))
            throw new Exception("DES in CBC mode recovered text is " +
              "different from cleartext");
        System.out.println("DES in ECB mode recovered text is " +
            "same as cleartext");

        /*
         * Bob encrypts, using DES in CBC mode
         */
        bobCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey);

        cleartext = "This is just an example".getBytes();
        ciphertext = bobCipher.doFinal(cleartext);
        // Retrieve the parameter that was used, and transfer it to Alice in
        // encoded format
        byte[] encodedParams = bobCipher.getParameters().getEncoded();

        /*
         * Alice decrypts, using DES in CBC mode
         */
        // Instantiate AlgorithmParameters object from parameter encoding
        // obtained from Bob
        AlgorithmParameters params = AlgorithmParameters.getInstance("DES");
        params.init(encodedParams);
        aliceCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        aliceCipher.init(Cipher.DECRYPT_MODE, aliceDesKey, params);
        recovered = aliceCipher.doFinal(ciphertext);

        if (!java.util.Arrays.equals(cleartext, recovered))
            throw new Exception("DES in CBC mode recovered text is " +
              "different from cleartext");
        System.out.println("DES in CBC mode recovered text is " +
            "same as cleartext");
    }

    /*
     * Converts a byte to hex digit and writes to the supplied buffer
     */
    private void byte2hex(byte b, StringBuffer buf) {
        char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
                            '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        int high = ((b & 0xf0) >> 4);
        int low = (b & 0x0f);
        buf.append(hexChars[high]);
        buf.append(hexChars[low]);
    }

    /*
     * Converts a byte array to hex string
     */
    private String toHexString(byte[] block) {
        StringBuffer buf = new StringBuffer();

        int len = block.length;

        for (int i = 0; i < len; i++) {
             byte2hex(block[i], buf);
             if (i < len-1) {
                 buf.append(":");
             }
        }
        return buf.toString();
    }

    /*
     * Prints the usage of this test.
     */
    private void usage() {
        System.err.print("DHKeyAgreement usage: ");
        System.err.println("[-gen]");
    }

    // The 1024 bit Diffie-Hellman modulus values used by SKIP
    private static final byte skip1024ModulusBytes[] = {
        (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58,
        (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD,
        (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4,
        (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B,
        (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D,
        (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C,
        (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C,
        (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6,
        (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0,
        (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B,
        (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB,
        (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D,
        (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD,
        (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43,
        (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C,
        (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C,
        (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C,
        (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40,
        (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C,
        (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72,
        (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03,
        (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29,
        (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C,
        (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB,
        (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B,
        (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08,
        (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D,
        (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C,
        (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22,
        (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB,
        (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55,
        (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7
    };

    // The SKIP 1024 bit modulus
    private static final BigInteger skip1024Modulus
    = new BigInteger(1, skip1024ModulusBytes);

    // The base used with the SKIP 1024 bit modulus
    private static final BigInteger skip1024Base = BigInteger.valueOf(2);
}

Обмен ключами Диффи-Хеллмана между 3 Сторонами

/*
 * Copyright (c) 1997, 2001, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import java.security.interfaces.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
import com.sun.crypto.provider.SunJCE;

/**
 * This program executes the Diffie-Hellman key agreement protocol
 * between 3 parties: Alice, Bob, and Carol.
 *
 * We use the same 1024-bit prime modulus and base generator that are
 * used by SKIP.
 */

public class DHKeyAgreement3 {

    private DHKeyAgreement3() {}

    public static void main(String argv[]) {
        try {
            DHKeyAgreement3 keyAgree = new DHKeyAgreement3();
            keyAgree.run();
        } catch (Exception e) {
            System.err.println("Error: " + e);
            System.exit(1);
        }
    }

    private void run() throws Exception {

        DHParameterSpec dhSkipParamSpec;

        System.out.println("Using SKIP Diffie-Hellman parameters");
        dhSkipParamSpec = new DHParameterSpec(skip1024Modulus, skip1024Base);

        // Alice creates her own DH key pair
        System.out.println("ALICE: Generate DH keypair ...");
        KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
        aliceKpairGen.initialize(dhSkipParamSpec);
        KeyPair aliceKpair = aliceKpairGen.generateKeyPair();

        // Bob creates his own DH key pair
        System.out.println("BOB: Generate DH keypair ...");
        KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
        bobKpairGen.initialize(dhSkipParamSpec);
        KeyPair bobKpair = bobKpairGen.generateKeyPair();

        // Carol creates her own DH key pair
        System.out.println("CAROL: Generate DH keypair ...");
        KeyPairGenerator carolKpairGen = KeyPairGenerator.getInstance("DH");
        carolKpairGen.initialize(dhSkipParamSpec);
        KeyPair carolKpair = carolKpairGen.generateKeyPair();


        // Alice initialize
        System.out.println("ALICE: Initialize ...");
        KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
        aliceKeyAgree.init(aliceKpair.getPrivate());

        // Bob initialize
        System.out.println("BOB: Initialize ...");
        KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
        bobKeyAgree.init(bobKpair.getPrivate());

        // Carol initialize
        System.out.println("CAROL: Initialize ...");
        KeyAgreement carolKeyAgree = KeyAgreement.getInstance("DH");
        carolKeyAgree.init(carolKpair.getPrivate());


        // Alice uses Carol's public key
        Key ac = aliceKeyAgree.doPhase(carolKpair.getPublic(), false);

        // Bob uses Alice's public key
        Key ba = bobKeyAgree.doPhase(aliceKpair.getPublic(), false);

        // Carol uses Bob's public key
        Key cb = carolKeyAgree.doPhase(bobKpair.getPublic(), false);


        // Alice uses Carol's result from above
        aliceKeyAgree.doPhase(cb, true);

        // Bob uses Alice's result from above
        bobKeyAgree.doPhase(ac, true);

        // Carol uses Bob's result from above
        carolKeyAgree.doPhase(ba, true);


        // Alice, Bob and Carol compute their secrets
        byte[] aliceSharedSecret = aliceKeyAgree.generateSecret();
        System.out.println("Alice secret: " + toHexString(aliceSharedSecret));

        byte[] bobSharedSecret = bobKeyAgree.generateSecret();
        System.out.println("Bob secret: " + toHexString(bobSharedSecret));

        byte[] carolSharedSecret = carolKeyAgree.generateSecret();
        System.out.println("Carol secret: " + toHexString(carolSharedSecret));


        // Compare Alice and Bob
        if (!java.util.Arrays.equals(aliceSharedSecret, bobSharedSecret))
            throw new Exception("Alice and Bob differ");
        System.out.println("Alice and Bob are the same");

        // Compare Bob and Carol
        if (!java.util.Arrays.equals(bobSharedSecret, carolSharedSecret))
            throw new Exception("Bob and Carol differ");
        System.out.println("Bob and Carol are the same");
    }


    /*
     * Converts a byte to hex digit and writes to the supplied buffer
     */
    private void byte2hex(byte b, StringBuffer buf) {
        char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
                            '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        int high = ((b & 0xf0) >> 4);
        int low = (b & 0x0f);
        buf.append(hexChars[high]);
        buf.append(hexChars[low]);
    }

    /*
     * Converts a byte array to hex string
     */
    private String toHexString(byte[] block) {
        StringBuffer buf = new StringBuffer();

        int len = block.length;

        for (int i = 0; i < len; i++) {
             byte2hex(block[i], buf);
             if (i < len-1) {
                 buf.append(":");
             }
        }
        return buf.toString();
    }

    /*
     * Prints the usage of this test.
     */
    private void usage() {
        System.err.print("DHKeyAgreement usage: ");
        System.err.println("[-gen]");
    }

    // The 1024 bit Diffie-Hellman modulus values used by SKIP
    private static final byte skip1024ModulusBytes[] = {
        (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58,
        (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD,
        (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4,
        (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B,
        (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D,
        (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C,
        (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C,
        (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6,
        (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0,
        (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B,
        (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB,
        (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D,
        (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD,
        (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43,
        (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C,
        (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C,
        (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C,
        (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40,
        (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C,
        (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72,
        (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03,
        (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29,
        (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C,
        (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB,
        (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B,
        (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08,
        (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D,
        (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C,
        (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22,
        (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB,
        (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55,
        (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7
    };

    // The SKIP 1024 bit modulus
    private static final BigInteger skip1024Modulus
    = new BigInteger(1, skip1024ModulusBytes);

    // The base used with the SKIP 1024 bit modulus
    private static final BigInteger skip1024Base = BigInteger.valueOf(2);
}

Пример Шифра шифра

/*
 * Copyright (c) 1997, 2001, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;

/**
 * This program generates a Blowfish key, retrieves its raw bytes, and
 * then reinstantiates a Blowfish key from the key bytes.
 * The reinstantiated key is used to initialize a Blowfish cipher for
 * encryption.
 */

public class BlowfishKey {

    public static void main(String[] args) throws Exception {

        KeyGenerator kgen = KeyGenerator.getInstance("Blowfish");
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "Blowfish");

        Cipher cipher = Cipher.getInstance("Blowfish");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted =
            cipher.doFinal("This is just an example".getBytes());
    }
}

Пример HMAC-MD5

/*
 * Copyright (c) 1997, 2001, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.security.*;
import javax.crypto.*;

/**
 * This program demonstrates how to generate a secret-key object for
 * HMAC-MD5, and initialize an HMAC-MD5 object with it.
 */

public class initMac {

    public static void main(String[] args) throws Exception {

        // Generate secret key for HMAC-MD5
        KeyGenerator kg = KeyGenerator.getInstance("HmacMD5");
        SecretKey sk = kg.generateKey();

        // Get instance of Mac object implementing HMAC-MD5, and
        // initialize it with the above secret key
        Mac mac = Mac.getInstance("HmacMD5");
        mac.init(sk);
        byte[] result = mac.doFinal("Hi There".getBytes());
    }
}

Чтение Паролей ASCII От Примера InputStream

/*
 * @(#)ReadPassword.java  1.1 06/06/07
 *
 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

import java.util.*;
import java.io.*;
import java.security.*;

public class ReadPassword {
    /**
     * Read a password from the InputStream "in".
     * <p>
     * As Strings are immutable, passwords should be stored as an array
     * of characters, which can be blanked out when no longer needed.
     * <p>
     * If the provided InputStream is the System's Console, this method
     * uses the non-echoing readPassword() method of java.io.Console
     * (new to JDK 6).  If not, a fallback implementation is used.
     * <p>
     * NOTE:  For expository purposes, and because some applications do
     * not understand multi-byte characters, only 8-bit ASCII passwords
     * are handled here.
     * <p>
     * NOTE:  If a SecurityManager is used, the default standard
     * java.policy file found in Sun's JDK (i.e.
     * <java-home>/lib/security/java.policy) allows reading the
     * line.separator property.  If your environment is different, this
     * code will need to be granted the appropriate privilege.
     *
     * @param   in
     *          the InputStream used to obtain the password.
     *
     * @return  A character array containing the password or passphrase,
     *          not including the line-termination characters,
     *          or null if an end of stream has been reached.
     *
     * @throws  IOException
     *          if an I/O problem occurs
     */
    public static final char[] readPassword(InputStream in)
            throws IOException {

        /*
         * If available, directly use the java.io.Console class to
         * avoid character echoing.
         */
        if (in == System.in && System.console() != null) {
            // readPassword returns "" if you just print ENTER,
            return System.console().readPassword();
        }

        /*
         * If a console is not available, read the InputStream
         * directly.  This approach may cause password echoing.
         *
         * Since different operating systems have different End-Of-Line
         * (EOL) sequences, this algorithm should allow for
         * platform-independent implementations.  Typical EOL sequences
         * are a single line feed ('\n'), or a carriage return/linefeed
         * combination ('\r\n').  However, some OS's use a single
         * a carriage return ('\r'), which complicates portability.
         *
         * Since we may not have the ability to push bytes back into the
         * InputStream, another approach is used here.  The javadoc for
         * <code>java.lang.System.getProperties()</code> specifies that
         * the set of system properties will contain a system-specific
         * value for the "line.separator".  Scan for this character
         * sequence instead of hard-coding a particular sequence.
         */
         
        /*
         * Enclose the getProperty in a doPrivileged block to minimize
         * the call stack permission required.
         */
        char [] EOL = AccessController.doPrivileged(
            new PrivilegedAction<char[]>() {
                public char[] run() {
                    String s = System.getProperty("line.separator");
                    // Shouldn't happen.
                    if (s == null) {
                        throw new RuntimeException(
                            "line.separator not defined");
                    }
                    return s.toCharArray();
                }
            });

        char [] buffer = new char[128];
        try {
            int len = 0;                // len of data in buffer.
            boolean done = false;       // found the EOL sequence
            int b;                      // byte read

            while (!done) {
                /*
                 * realloc if necessary
                 */
                if (len >= buffer.length) {
                    char [] newbuffer = new char[len + 128];
                    System.arraycopy(buffer, 0, newbuffer, 0, len);
                    Arrays.fill(buffer, ' ');
                    buffer = newbuffer;
                }

                /*
                 * End-of-Stream?
                 */
                if ((b = in.read()) == -1) {
                    // Return as much as we have, null otherwise.
                    if (len == 0) {
                        return null;
                    }
                    break;
                } else {
                    /*
                     * NOTE:  In the simple PBE example here,
                     * only 8 bit ASCII characters are handled.
                     */
                    buffer[len++] = (char) b;
                }

                /*
                 * check for the EOL sequence.  Do we have enough bytes?
                 */
                if (len >= EOL.length) {
                    int i = 0;
                    for (i = 0; i < EOL.length; i++) {
                        if (buffer[len - EOL.length + i] != EOL[i]) {
                            break;
                        }
                    }
                    done = (i == EOL.length);
                }
            }

            /*
             * If we found the EOL, strip the EOL chars.
             */
            char [] result = new char[done ? len - EOL.length : len];
            System.arraycopy(buffer, 0, result, 0, result.length);

            return result;
        } finally {
            /*
             * Zero out the buffer.
             */
            if (buffer != null) {
                Arrays.fill(buffer, ' ');
            }
        }
    }
}
  

Oracle и/или его филиалы Авторское право © 1993, 2012, Oracle и/или его филиалы. Все права защищены.
Свяжитесь с Нами