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

Java PKCS#11 Справочник


1.0 Введение

2.0 Sun PKCS#11 Провайдер

2.1 Требования
2.2 Конфигурация
2.3 Доступ к Службам сетевой безопасности (NSS)

3.0 Разработчики приложений

3.1 Маркерный Вход в систему
3.2 Маркерные Ключи
3.3 Задержанный Выбор Провайдера
3.4 JAAS KeyStoreLoginModule
3.5 Маркеры как JSSE Keystores и Базы доверенных сертификатов

4.0 Инструменты

4.1 KeyTool и JarSigner
4.2 PolicyTool

5.0 Разработчики провайдера

5.1 Службы провайдера
5.1.1 Инстанцирование Классов Механизма
5.1.2 Поддержка параметра

Приложение Sun PKCS#11 Поддерживаемые Алгоритмы Провайдера

Приложение B Sun PKCS#11 Ограничения KeyStore Провайдера

Провайдер приложения C В качестве примера


1.0 Введение

Платформа Java определяет ряд интерфейсов программирования для того, чтобы выполнить криптографические операции. Эти интерфейсы все вместе известны как Архитектура Криптографии Java (JCA) и Расширение Криптографии Java (JCE). Спецификации доступны в Java страница Документации Безопасности SE.

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

Криптографический Маркерный Стандарт Интерфейса, PKCS#11, производится Безопасностью RSA и определяет собственные интерфейсы программирования к криптографическим маркерам, таким как аппаратные средства криптографические акселераторы и Смарт-карты. Чтобы облегчить интеграцию собственных PKCS#11 маркеры в платформу Java, новый криптографический провайдер, Sun PKCS#11 провайдер, был введен в J2SE 5.0 выпусков. Этот новый провайдер позволяет существующим приложениям, записанным JCA и API JCE получить доступ собственный PKCS#11 маркеры. Никакие модификации к приложению не требуются. Единственное требование является надлежащей конфигурацией провайдера в Среду выполнения Java.

Хотя приложение может использовать большинство PKCS#11 функции, используя существующие API, некоторым приложениям, возможно, понадобились бы больше гибкости и возможностей. Например, приложение могло бы хотеть иметь дело со Смарт-картами, удаляемыми и вставленными динамически более легко. Или, PKCS#11 маркер мог бы потребовать аутентификации для некоторых не ключ связанные операции и поэтому, приложение должно быть в состоянии зарегистрировать в маркер, не используя keystore. В J2SE 5.0, JCA был улучшен, чтобы позволить приложениям большую гибкость имея дело с различными провайдерами.

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

2.0 Sun PKCS#11 Провайдер

Sun PKCS#11 провайдер, в отличие от большинства других провайдеров, не реализует криптографические алгоритмы самостоятельно. Вместо этого это действует как мост между Java JCA и API JCE и собственным PKCS#11 криптографический API, преобразовывая вызовы и соглашения между двумя. Это означает, что приложения Java, вызывая стандартный JCA и API JCE, без модификации, могут использовать в своих интересах алгоритмы, предлагаемые базовым PKCS#11 реализации, такой как, например,

Отметьте, что Java, SE только облегчает доступ, собственный PKCS#11 реализации, это самостоятельно не включает собственное PKCS#11 реализация. Однако, криптографические устройства, такие как Смарт-карты и аппаратные акселераторы, с которыми часто идут программное обеспечение, которое включает PKCS#11 реализация, которую Вы должны установить и сконфигурировать согласно инструкциям производителя.

2.1 Требования

Sun PKCS#11 провайдер поддерживается на Солярисе (SPARC и x86), Linux (x86), и платформы Windows и в 32-разрядных и в 64-разрядных процессах Java.

Sun PKCS#11 провайдер требует реализации PKCS#11 v2.0 или позже быть установленным на системе. Эта реализация должна принять форму совместно используемой библиотеки объектов (.so на Солярисе и Linux) или динамически подключаемая библиотека (.dll на Windows). Пожалуйста, консультируйтесь со своей документацией поставщика, чтобы узнать, включает ли Ваше криптографическое устройство такой PKCS#11 реализация, как сконфигурировать это, и каково имя файла библиотеки.

Sun PKCS#11 провайдер поддерживает много алгоритмов, при условии, что базовое PKCS#11 реализация предлагает им. Алгоритмы и их соответствие PKCS#11 механизмы перечисляются в таблице в Приложении A.

2.2 Конфигурация

Sun PKCS#11 провайдер реализуется основным class sun.security.pkcs11.SunPKCS11 и принимает полный путь конфигурационного файла как параметр. Чтобы использовать провайдера, следует сначала установить это при использовании Архитектуры Криптографии Java (JCA). Как со всеми провайдерами JCA, установка провайдера может быть сделана или статически или программно. Чтобы установить провайдера статически, добавьте провайдера к файлу свойств Security Java ($JAVA_HOME/lib/security/java.security). Например, вот фрагмент файла java.security, который устанавливает Sun PKCS#11 провайдер с конфигурационным файлом /opt/bar/cfg/pkcs11.cfg.
# configuration for security providers 1-6 ommitted
security.provider.7=sun.security.pkcs11.SunPKCS11 /opt/bar/cfg/pkcs11.cfg
Чтобы установить провайдера динамически, создайте экземпляр провайдера с соответствующим именем файла конфигурации и затем установите это. Вот пример.
String configName = "/opt/bar/cfg/pkcs11.cfg";
Provider p = new sun.security.pkcs11.SunPKCS11(configName);
Security.addProvider(p);

Чтобы использовать больше чем один слот на PKCS#11 реализация, или использовать больше чем один PKCS#11 реализация, просто повторяют установку для каждого с соответствующим конфигурационным файлом. Это приведет к Sun PKCS#11 экземпляр провайдера для каждого слота каждого PKCS#11 реализация.

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

припишите =, оценивают допустимые значения за атрибут, и значение описываются в таблице в этом разделе. Двумя обязательными атрибутами является name и library. Вот демонстрационный конфигурационный файл.
name = FooAccelerator
library = /opt/foo/lib/libpkcs11.so
Комментарии обозначаются строками, запускающимися с # (число) символ.

Атрибут Значение Описание
библиотека путь PKCS#11 реализация Это - полный путь (включая расширение) PKCS#11 реализация; формат пути является зависимой платформой. Например, /opt/foo/lib/libpkcs11.so мог бы быть путь PKCS#11 реализация на Солярисе и Linux в то время как C:\foo\mypkcs11.dll мог бы быть путь на Windows.
имя суффикс имени этого экземпляра провайдера Эта строка связывается с префиксным SunPKCS11-, чтобы произвести это имя экземпляра провайдера (то есть, строка, возвращенная Provider.getName() метод). Например, если атрибутом name будет "FooAccelerator", то имя экземпляра провайдера будет "SunPKCS11-FooAccelerator".
описание описание этого экземпляра провайдера Эта строка будет возвращена экземпляром провайдера Provider.getInfo() метод. Если ни один не будет определен, то описание значения по умолчанию будет возвращено.
слот идентификатор слота Это - идентификатор слота, с которым должен быть связан этот экземпляр провайдера. Например, Вы использовали бы 1 для слота с идентификатором 1 под PKCS#11. Самое большее один из slot или slotListIndex может быть определен. Если ни один не определяется, значением по умолчанию является slotListIndex 0.
slotListIndex слот индексирует Это - слот, индексируют тот этот экземпляр провайдера, должен быть связан с. Это - индексирование в список всех слотов, возвращенных PKCS#11 функция C_GetSlotList. Например, 0 указывает на первый слот в списке. Самое большее один из slot или slotListIndex может быть определен. Если ни один не определяется, значением по умолчанию является slotListIndex 0.
enabledMechanisms заключите в фигурные скобки включенный, разделенный от пробела список PKCS#11 механизмы, чтобы включить Это - список PKCS#11 механизмы, которые должен использовать этот экземпляр провайдера, при условии, что они поддерживаются и Sun PKCS#11 провайдер и PKCS#11 маркер. Все другие механизмы будут проигнорированы. Каждая запись в списке является именем PKCS#11 механизм. Вот пример, который перечисляет два PKCS#11 механизмы.
enabledMechanisms = {
  CKM_RSA_PKCS
  CKM_RSA_PKCS_KEY_PAIR_GEN
}
Самое большее один из enabledMechanisms или disabledMechanisms может быть определен. Если ни один не определяется, включенные механизмы являются теми, которые поддерживаются и Sun PKCS#11 провайдер и PKCS#11 маркер.
disabledMechanisms заключите в фигурные скобки включенный, разделенный от пробела список PKCS#11 механизмы, чтобы отключить Это - список PKCS#11 механизм, который должен проигнорировать этот экземпляр провайдера. Любой перечисленный механизм будет проигнорирован провайдером, даже если они будут поддерживаться маркером и Sun PKCS#11 провайдер. Строки SecureRandom и KeyStore может быть определен, чтобы отключить те службы.

Самое большее один из enabledMechanisms или disabledMechanisms может быть определен. Если ни один не определяется, включенные механизмы являются теми, которые поддерживаются и Sun PKCS#11 провайдер и PKCS#11 маркер.

атрибуты см. ниже Опция attributes может использоваться, чтобы определить дополнительный PKCS#11, который должен быть установлен, создавая PKCS#11 ключевые объекты. Это позволяет разместить маркеры, которые требуют определенных атрибутов. Для получения дополнительной информации см. раздел ниже.

Конфигурация атрибутов

Опция атрибутов позволяет Вам определять дополнительный PKCS#11 атрибуты, которые должны быть установлены, создавая PKCS#11 ключевые объекты. По умолчанию провайдер SunPKCS11 только определяет обязательный PKCS#11 атрибуты, создавая объекты. Например, для открытых ключей RSA это определяет ключевой тип и алгоритм (CKA_CLASS и CKA_KEY_TYPE) и значения ключа для открытых ключей RSA (CKA_MODULUS и CKA_PUBLIC_EXPONENT). PKCS#11 библиотека, которой Вы пользуетесь, присвоит реализацию определенные значения по умолчанию другим атрибутам открытого ключа RSA, например что ключ может использоваться, чтобы зашифровать и проверить сообщения (CKA_ENCRYPT и CKA_VERIFY = истина).

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

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

attributes(operation, keytype, keyalgorithm) = {
  name1 = value1
  [...]
}
Допустимые значения для operation: Допустимыми значениями для keytype является CKO_PUBLIC_KEY, CKO_PRIVATE_KEY, и CKO_SECRET_KEY, для общедоступных, частных, и секретных ключей, соответственно, и *, чтобы соответствовать любой тип ключа.

Допустимые значения для keyalgorithm являются одной из констант CKK_xxx от PKCS#11 спецификация, или *, чтобы соответствовать ключи любого алгоритма. Алгоритмы, в настоящий момент поддерживаемые провайдером SunPKCS11, являются CKK_RSA, CKK_DSA, CKK_DH, CKK_AES, CKK_DES, CKK_DES3, CKK_RC4, CKK_BLOWFISH, и CKK_GENERIC.

Названия атрибута и значения определяются как список одной или более пар значение-имя. name должен быть CKA_xxx, постоянный от PKCS#11 спецификация, например CKA_SENSITIVE. value может быть одним из следующего:

Если опция attributes определяется многократно, записи обрабатываются в порядке, определенном с атрибутами агрегированные и более поздние атрибуты, переопределяющие более ранние. Например, рассмотрите следующую выборку конфигурационного файла:
attributes(*,CKO_PRIVATE_KEY,*) = {
  CKA_SIGN = true
}

attributes(*,CKO_PRIVATE_KEY,CKK_DH) = {
  CKA_SIGN = null
}

attributes(*,CKO_PRIVATE_KEY,CKK_RSA) = {
  CKA_DECRYPT = true
}
Первая запись говорит, чтобы определить CKA_SIGN = true для всех закрытых ключей. Вторые переопределения опции, что с null для закрытых ключей Diffie-Hellman, таким образом, атрибут CKA_SIGN не будет определенный для них вообще. Наконец, третья опция говорит, чтобы также определить CKA_DECRYPT = true для закрытых ключей RSA. Это означает, что у закрытых ключей RSA будут и CKA_SIGN = true и набор CKA_DECRYPT = true.

Есть также специальная форма опции attributes. Можно записать attributes = compatibility в конфигурационном файле. Это - ярлык для целого набора операторов атрибута. Они разрабатываются к совместимости максимума провайдера с существующими приложениями Java, которые могут ожидать, например, что все ключевые компоненты будут доступными и секретными ключами, чтобы быть применимыми и для шифрования и для дешифрования. Строка атрибутов compatibility может использоваться вместе с другими строками attributes, когда та же самая агрегация и переопределяющие правила применяются как описано ранее.

2.3 Доступ к Службам сетевой безопасности (NSS)

Службы сетевой безопасности (NSS) являются рядом библиотек безопасности с открытым исходным кодом, пользовавшихся браузерами Mozilla/Firefox, программным обеспечением сервера Корпоративной системы Java Sun, и многими другими продуктами. Его crypto API основаны на PKCS#11, но это включает специальные функции, которые являются за пределами PKCS#11 стандарт. Sun PKCS#11 провайдер включает код, чтобы взаимодействовать с этими определенными функциями NSS, включая несколько определенных конфигурационных директив NSS, которые описываются ниже.

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

Sun PKCS#11 провайдер использует определенный код NSS когда любой из nss конфигурационные директивы, описанные ниже, используются. В этом случае, регулярные команды конфигурации library, slot, и slotListIndex не может использоваться.

Атрибут Значение Описание
nssLibraryDirectory каталог, содержащий NSS и библиотеки NSPR Это - полный путь каталога, содержащего NSS и библиотеки NSPR. Это должно быть определено, если NSS не был уже загружен и инициализирован другим компонентом, работающим в том же самом процессе как Java VM.

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

nssSecmodDirectory каталог, содержащий файлы DB NSS Полный путь каталога, содержащего конфигурацию NSS и ключевую информацию (secmod.db, key3.db, и cert8.db). Это направляющее должно быть определено, если NSS не был уже инициализирован другим компонентом (см. выше), или NSS используется без файлов базы данных как описано ниже.
nssDbMode один из readWrite, readOnly, и noDb Это, которое определяют директивы, как к базе данных NSS получают доступ. В режиме чтения-записи полный доступ возможен, но только один процесс за один раз должен получать доступ к базам данных. Режим только для чтения отвергает модификации к файлам.

noDb режим позволяет NSS использоваться без файлов базы данных просто как криптографический провайдер. Не возможно создать персистентные ключи, используя KeyStore PKCS11. Этот режим полезен, потому что NSS включает чрезвычайно оптимизированные реализации и алгоритмы, не в настоящий момент доступные в связанном Java Sun базируемые crypto провайдеры, например Шифрование в эллиптических кривых (ECC).

nssModule один из keystore, crypto, fips, и trustanchors NSS делает свою функциональность доступным использованием нескольких различных библиотек и слотов. Это направляющее определяет, к какому из этих модулей получает доступ этот экземпляр SunPKCS11.

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

fips модуль является значением по умолчанию если NSS secmod.db был установлен в FIPS 140 совместимых режимов. В этом режиме NSS ограничивает доступные алгоритмы и PKCS#11 атрибуты, с которыми могут быть созданы ключи.

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

trustanchors модуль включает доступу к сертификатам привязки доверия NSS через KeyStore PKCS11, если secmod.db был сконфигурирован, чтобы включать доверительную библиотеку привязки.

Пример конфигурационные файлы SunPKCS11 для NSS

NSS как чистый провайдер криптографии
name = NSScrypto
nssLibraryDirectory = /opt/tests/nss/lib
nssDbMode = noDb
attributes = compatibility
NSS как FIPS 140 совместимых crypto маркеров:
name = NSSfips
nssLibraryDirectory = /opt/tests/nss/lib
nssSecmodDirectory = /opt/tests/nss/fipsdb
nssModule = fips

3.0 Разработчики приложений

Приложения Java могут использовать существующий JCA и API JCE к доступу PKCS#11 маркеры через Sun PKCS#11 провайдер. Это достаточно для многих приложений, но для приложения могло бы быть трудно иметь дело с определенным PKCS#11 функции, такие как неизвлекаемые ключи и динамически изменяющий Смарт-карты. Следовательно, много улучшений были сделаны к API лучше поддерживать приложения, использующие бесспорный PKCS#11 функции. Эти enhancments обсуждаются в этом разделе.

3.1 Маркерный Вход в систему

Бесспорный PKCS#11 операции, такие как доступ к закрытым ключам, требуют входа в систему, используя Персональный идентификационный номер, или ПИН, прежде, чем операции смогут продолжиться. Наиболее распространенный тип операций, которые требуют входа в систему, является теми, которые имеют дело с, включает маркер. В приложении Java такие операции часто включают сначала загрузку keystore. Получая доступ PKCS#11 маркер как keystore через java.security.KeyStore class, можно предоставить ПИН во входном параметре пароля к методу загрузки, подобному тому, как приложения инициализируют keystore до J2SE 5.0. ПИН будет тогда использоваться Sun PKCS#11 провайдер для того, чтобы зарегистрировать в маркер. Вот пример.

char[] pin = ...; 
KeyStore ks = KeyStore.getInstance("PKCS11");
ks.load(null, pin); 

Это прекрасно для приложения, которое обрабатывает PKCS#11 маркеры как статический keystores. Для приложения, которое хочет разместить PKCS#11 маркеры более динамически, такие как Смарт-карты, вставляемые и удаленные, можно использовать новый KeyStore.Builder class. Вот пример того, как инициализировать разработчика для PKCS#11 keystore с обработчиком обратного вызова.

KeyStore.CallbackHandlerProtection chp =
    new KeyStore.CallbackHandlerProtection(new MyGuiCallbackHandler());
KeyStore.Builder builder =
    KeyStore.Builder.newInstance("PKCS11", null, chp);

Для Sun PKCS#11 провайдер, обработчик обратного вызова должен быть в состоянии удовлетворить PasswordCallback, который используется, чтобы запросить пользователя ПИН. Всякий раз, когда приложение нуждается в доступе к keystore, это использует разработчика следующим образом.

KeyStore ks = builder.getKeyStore();
Key key = ks.getKey(alias, null);

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

В зависимости от PKCS#11 маркер, могут быть не ключевые связанные операции, которые также требуют маркерного входа в систему. Приложения, которые используют такие операции, могут использовать недавно представленный java.security.AuthProvider class. AuthProvider class расширяется от java.security.Provider и определяет методы, чтобы выполнить операции входа в систему и выхода из системы на провайдере, так же как установить обработчик обратного вызова для провайдера, чтобы использовать.

Для Sun PKCS#11 провайдер, обработчик обратного вызова должен быть в состоянии удовлетворить PasswordCallback, который используется, чтобы запросить пользователя ПИН.

Вот пример того, как приложение могло бы использовать AuthProvider, чтобы зарегистрировать в маркер.

AuthProvider aprov = (AuthProvider)Security.getProvider("SunPKCS11");
aprov.login(subject, new MyGuiCallbackHandler());

3.2 Маркерные Ключи

Java Key объекты могут или, возможно, не содержат фактический ключевой материал.

Приложения и провайдеры должны использовать корректные интерфейсы, чтобы представить эти различные типы Ключевых объектов. Ключевые объекты программного обеспечения (или любой Ключевой объект, у которого есть доступ к фактическому ключевому материалу) должны реализовать интерфейсы в java.security.interfaces и javax.crypto.interfaces пакетах (таких как DSAPrivateKey). Ключевые объекты, представляющие неизвлекаемые маркерные ключи, должны только реализовать соответствующие универсальные интерфейсы в java.security и javax.crypto пакетах (PrivateKey, PublicKey, или SecretKey). Идентификация алгоритма ключа должна быть выполнена, используя метод Key.getAlgorithm().

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

3.3 Задержанный Выбор Провайдера

До J2SE 5.0, методы getInstance() криптографии Java, такие как Cipher.getInstance("DES"), возвратили реализацию из первого провайдера, который реализовывал требуемый алгоритм. Это проблематично, если приложение пытается использовать объект Key для неизвлекаемого маркерного ключа с провайдером, который только принимает ключевые объекты программного обеспечения. В таком случае провайдер бросил бы InvalidKeyException. Это - проблема для Cipher, KeyAgreement, Mac, и классов Signature.

J2SE 5.0, решает эту проблему, задерживая выбор провайдера, пока соответствующий метод инициализации не вызывают. Метод инициализации принимает объект Key и может определить в той точке, какой провайдер может принять указанный объект Key. Это гарантирует, что выбранный провайдер может использовать указанный объект Key. Следующее представляет методы инициализации, на которые влияют.

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

Хотя этот задержанный выбор провайдера скрывается от приложения, он действительно влияет на поведение getProvider() метод для Cipher, KeyAgreement, Mac, и Signature. Если getProvider() вызывается прежде, чем работа инициализации произошла (и поэтому прежде, чем выбор провайдера произошел), тогда первый провайдер, который поддерживает требуемый алгоритм, возвращается. Это, возможно, не тот же самый провайдер как то, выбранное после того, как метод инициализации вызывают. Если getProvider() вызывается после того, как работа инициализации произошла, тогда фактический выбранный провайдер возвращается. Этому рекомендуют это, приложения только вызывают getProvider() после того, как они вызвали соответствующий метод инициализации.

В дополнение к getProvider(), на следующие дополнительные методы так же влияют.

3.4 JAAS KeyStoreLoginModule

SE Java идет с JAAS keystore модуль входа в систему, KeyStoreLoginModule, который позволяет приложению аутентифицировать использование его идентификационных данных в указанном keystore. После аутентификации приложение имело бы, получают его принципал и информацию об учетных данных (сертификат и закрытый ключ) от keystore. При использовании этого модуля входа в систему и конфигурирования этого, чтобы использовать PKCS#11 маркер как keystore, приложение может получить эту информацию от PKCS#11 маркер.

Используйте следующие опции, чтобы сконфигурировать KeyStoreLoginModule, чтобы использовать PKCS#11 маркер как keystore.

где some_pin_url является расположением ПИН. Если опция keyStorePasswordURL будет опущена, то модуль входа в систему получит ПИН через обработчик обратного вызова приложения, предоставляя ее PasswordCallback. Вот пример конфигурационного файла, который использует PKCS#11 маркер как keystore.
other {
    com.sun.security.auth.module.KeyStoreLoginModule required
        keyStoreURL="NONE"
  keyStoreType="PKCS11"
  keyStorePasswordURL="file:/home/joe/scpin";
};

Если больше чем один Sun PKCS#11 провайдер был сконфигурирован динамически или в файле свойств безопасности java.security, можно использовать опцию keyStoreProvider, чтобы предназначаться для определенного экземпляра провайдера. Параметром этой опции является имя провайдера. Для Sun PKCS#11 провайдер, имя провайдера имеет форму SunPKCS11-TokenName, где TokenName является суффиксом имени, что экземпляр провайдера был сконфигурирован с, как детализировано в таблице атрибутов конфигурации. Например, следующий конфигурационный файл называет PKCS#11, экземпляр провайдера с именем снабжает суффиксом SmartCard.

other {
    com.sun.security.auth.module.KeyStoreLoginModule required
        keyStoreURL="NONE"
  keyStoreType="PKCS11"
  keyStorePasswordURL="file:/home/joe/scpin"
  keyStoreProvider="SunPKCS11-SmartCard";
};

Некоторые PKCS#11 маркеры поддерживают вход в систему через защищенный путь аутентификации. Например, у Смарт-карты может быть выделенная клавиатура ПИН, чтобы ввести контакт. У биометрических устройств также будут свои средства собственного получить информацию об аутентификации. Если PKCS#11 у маркера есть защищенный путь аутентификации, то используйте опцию protected=true и опустите опцию keyStorePasswordURL. Вот пример конфигурационного файла для такого маркера.

other {
    com.sun.security.auth.module.KeyStoreLoginModule required
        keyStoreURL="NONE"
  keyStoreType="PKCS11"
  protected=true;
};

3.5 Маркеры как JSSE Keystore и Базы доверенных сертификатов

Чтобы использовать PKCS#11 маркеры в качестве JSSE keystores или базы доверенных сертификатов, приложение JSSE может использовать API, описанные ранее, чтобы инстанцировать KeyStore, который поддерживается PKCS#11 маркер, и передайте это его ключевому менеджеру и доверяйте менеджеру. У приложения JSSE тогда будет доступ к ключам на маркере.

JSSE также поддерживает конфигурирование использования keystores и баз доверенных сертификатов через системные свойства, как описано в Справочнике JSSE. Чтобы использовать PKCS#11 маркер как keystore или база доверенных сертификатов, установите javax.net.ssl.keyStoreType и системные свойства javax.net.ssl.trustStoreType, соответственно, к "PKCS11", и установите javax.net.ssl.keyStore и системные свойства javax.net.ssl.trustStore, соответственно, к NONE. Чтобы определить использование определенного экземпляра провайдера, используйте javax.net.ssl.keyStoreProvider и системные свойства javax.net.ssl.trustStoreProvider (например, "SunPKCS11-смарт-карта").

4.0 Инструменты

В J2SE 5.0, средства обеспечения безопасности были обновлены, чтобы поддерживать операции, используя новый Sun PKCS#11 провайдер. Изменения обсуждаются ниже.

4.1 KeyTool и JarSigner

Если Sun PKCS#11 провайдер был сконфигурирован в файле свойств безопасности java.security (расположенный в каталоге $JAVA_HOME/lib/security Среды выполнения Java), то keytool и jarsigner могут использоваться, чтобы работать на PKCS#11 маркер, определяя следующие опции.

Здесь пример команды, чтобы перечислить содержание сконфигурированного PKCS#11 маркер.
keytool -keystore NONE -storetype PKCS11 -list
ПИН может быть определен, используя-storepass опцию. Если ни один не был определен, то keytool и jarsigner запросят маркерный ПИН. Если у маркера есть защищенный путь аутентификации (такой как выделенная клавиатура ПИН или биометрический читатель), то опция -protected должна быть определена, и никакие опции пароля не могут быть определены.

Если больше чем один Sun PKCS#11 провайдер был сконфигурирован в файле свойств безопасности java.security, можно использовать опцию -providerName, чтобы предназначаться для определенного экземпляра провайдера. Параметром этой опции является имя провайдера.

Для Sun PKCS#11 провайдер, providerName имеет форму SunPKCS11-TokenName, где TokenName является суффиксом имени, что экземпляр провайдера был сконфигурирован с, как детализировано в таблице атрибутов конфигурации. Например, следующие списки команд содержание PKCS#11 keystore экземпляр провайдера с именем снабжают суффиксом SmartCard.
keytool -keystore NONE -storetype PKCS11 \
        -providerName SunPKCS11-SmartCard \
        -list

Если Sun PKCS#11 провайдер не был сконфигурирован в файле свойств безопасности java.security, можно использовать следующие опции, чтобы дать команду keytool и jarsigner устанавливать провайдера динамически.

ConfigFilePath является путем к маркерному конфигурационному файлу. Вот пример команды, чтобы перечислить PKCS#11 keystore, когда Sun PKCS#11 провайдер не был сконфигурирован в файле java.security.
keytool -keystore NONE -storetype PKCS11 \
        -providerClass sun.security.pkcs11.SunPKCS11 \
        -providerArg /foo/bar/token.config \
        -list

4.2 PolicyTool

До J2SE 5.0, у keystore записи в реализации политики значения по умолчанию был следующий синтаксис.

keystore "some_keystore_url", "keystore_type";
Этот синтаксис был несоответствующим для того, чтобы получить доступ PKCS#11 keystore потому что такой доступ, обычно требуемый ПИН, и могло бы быть многократно PKCS#11 экземпляры провайдера. Чтобы разместить эти требования, keystore синтаксис записи был обновлен в J2SE 5.0 к следующему.
keystore "some_keystore_url", "keystore_type", "keystore_provider";
keystorePasswordURL "some_password_url";
Где keystore_provider является keystore именем провайдера (например, "SunPKCS11-SmartCard"), и some_password_url является URL, указывающий на расположение маркерного ПИН. И keystore_provider и keystorePasswordURL строка являются дополнительными. Если keystore_provider не был определен, то первый сконфигурированный провайдер, который поддерживает указанный тип keystore, используется. Если строка keystorePasswordURL не была определена, то никакой пароль не используется.

Следующее является примером keystore запись политики для PKCS#11 маркер.

keystore "NONE", "PKCS11", "SunPKCS11-SmartCard";
keystorePasswordURL "file:/foo/bar/passwordFile";

5.0 Разработчики провайдера

J2SE 5.0 представляет новые средства в java.security. Провайдер class для реализаций провайдера, чтобы более легко поддерживать PKCS#11 маркеры и криптографические службы вообще. Эти новые средства обсуждаются ниже.

См. Приложение C для примера простого провайдера, разработанного, чтобы демонстрировать новый facilties.

5.1 Службы провайдера

Как описано в вышеупомянутой документации провайдера, до J2SE 5.0, провайдеры были обязаны создавать записи java.util.Property, описывающие службы, которые они поддерживали. Для каждой службы, реализованной провайдером, должно быть свойство, имя которого является типом службы (Cipher, Signature, и т.д.), сопровождаемый периодом и именем алгоритма, к которому применяется служба. Значение свойства должно определить полностью определенное имя class, реализовывая службу. Вот пример свойства установки KeyAgreement.DiffieHellman провайдера, чтобы иметь значение com.sun.crypto.provider.DHKeyAgreement.

put("KeyAgreement.DiffieHellman", 
      "com.sun.crypto.provider.DHKeyAgreement")

J2SE 5.0 представляет новый общедоступный статический вложенный class, Provider.Service, чтобы помочь лучше инкапсулировать свойства службы провайдера (включая ее тип, атрибуты, имя алгоритма, и псевдонимы алгоритма). Провайдеры могут инстанцировать объектов Provider.Service и зарегистрировать их, вызывая метод Provider.putService(). Это эквивалентно созданию записи Property и вызову метода Provider.put() (как был сделан до J2SE 5.0). Отметьте, что наследство записи Property, зарегистрированные через Provider.put, все еще поддерживается.

Вот пример провайдера, создающего объект Service с типом KeyAgreement, для алгоритма DiffieHellman, реализованного class com.sun.crypto.provider.DHKeyAgreement.

Service s = new Service(this, "KeyAgreement", "DiffieHellman",
    "com.sun.crypto.provider.DHKeyAgreement", null, null);
putService(s);

Используя объекты Provider.Servicee вместо наследства записи Property обладает несколькими главными преимуществами. Одно преимущество - то, что это позволяет провайдеру иметь большую гибкость, инстанцируя классов механизма. Другое преимущество - то, что это позволяет провайдеру тестировать законность параметра. Эти функции обсуждаются подробно затем.

5.1.1 Инстанцирование Классов Механизма

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

Чтобы переопределить поведение значения по умолчанию, провайдер переопределяет метод Provider.Service.newInstance(), чтобы добавить его потребительское поведение. Например, провайдер мог бы вызвать пользовательского конструктора, или мог бы выполнить инициализацию, используя информацию, не доступную вне провайдера (или которые только известны провайдером).

5.1.2 Поддержка параметра

Платформа Криптографии Java может делать попытку быстрой проверки, чтобы определить, может ли реализация службы провайдера использовать определенный приложением параметр. Чтобы выполнить эту быструю проверку, платформа вызывает Provider.Service.supportsParameter().

В J2SE 5.0, платформа полагается на этот быстрый тест во время задержанного выбора провайдера. Когда приложение вызывает метод инициализации и передает его объект Key, платформа спрашивает базового провайдера, поддерживает ли он объект, вызывая его метод Service.supportsParameter(). Если supportsParameter() возвраты false, платформа может сразу удалить того провайдера из рассмотрения. Если supportsParameter() возвраты true, платформа передает объект Key к механизму инициализации того провайдера реализация class. Провайдер, который требует программного обеспечения объекты Key, должен переопределить этот метод, чтобы возвратиться false когда это - переданные ключи непрограммного обеспечения. Аналогично, провайдер для PKCS#11 маркер, который содержит неизвлекаемые ключи, должен только возвратиться true поскольку Key возражает, что создал, и которые поэтому соответствуют Key s на его соответствующем маркере.

Отметьте что реализация по умолчанию supportsParameter() возвраты true. Это позволяет существующим провайдерам работать без модификации. Однако, из-за этой снисходительной реализации по умолчанию, платформа должна быть подготовлена поймать исключения, выданные провайдерами, которые отклоняют объект Key в их механизме инициализации реализации class. Платформа обрабатывает эти случаи то же самое как тогда, когда supportsParameter() возвраты false.

Приложение A: Sun PKCS#11 Поддерживаемые Алгоритмы Провайдера

Следующая таблица приводит алгоритмы Java, поддерживаемые Sun PKCS#11 провайдер и соответствующий PKCS#11, механизмы должны были поддерживать их. Когда многократные механизмы перечисляются, им дают в порядке предпочтения, и любой из них является sufficent. Отметьте, что SunPKCS11 может быть проинструктирован, чтобы проигнорировать механизмы при использовании disabledMechanisms и enabledMechanisms конфигурационные директивы.

Для механизмов Эллиптической кривой SunPKCS11 будет только использовать ключи, которые используют namedCurve выбор как кодирующий для параметров и только позволяет несжатый формат точки. Sun PKCS#11 провайдер предполагает, что маркер поддерживает весь стандарт, названный параметрами домена.

Алгоритм Java PKCS#11 Механизмы
Подпись. MD2withRSA CKM_MD2_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509
Подпись. MD5withRSA CKM_MD5_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509
Подпись. SHA1withRSA CKM_SHA1_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509
Подпись. SHA256withRSA CKM_SHA256_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509
Подпись. SHA384withRSA CKM_SHA384_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509
Подпись. SHA512withRSA CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509
Подпись. SHA1withDSA CKM_DSA_SHA1, CKM_DSA
Подпись. NONEwithDSA CKM_DSA
Подпись. SHA1withECDSA CKM_ECDSA_SHA1, CKM_ECDSA
Подпись. SHA256withECDSA CKM_ECDSA
Подпись. SHA384withECDSA CKM_ECDSA
Подпись. SHA512withECDSA CKM_ECDSA
Подпись. NONEwithECDSA CKM_ECDSA
Шифр. RSA/ECB/PKCS1Padding CKM_RSA_PKCS
Шифр. ARCFOUR CKM_RC4
Шифр. DES/CBC/NoPadding CKM_DES_CBC
Шифр. DESede/CBC/NoPadding CKM_DES3_CBC
Шифр. AES/CBC/NoPadding CKM_AES_CBC
Шифр. Blowfish/CBC/NoPadding CKM_BLOWFISH_CBC
Шифр. RSA/ECB/NoPadding CKM_RSA_X_509
Шифр. AES/CTR/NoPadding CKM_AES_CTR
KeyAgreement. ECDH CKM_ECDH1_DERIVE
KeyAgreement. DiffieHellman CKM_DH_PKCS_DERIVE
KeyPairGenerator. RSA CKM_RSA_PKCS_KEY_PAIR_GEN
KeyPairGenerator. DSA CKM_DSA_KEY_PAIR_GEN
KeyPairGenerator. EC CKM_EC_KEY_PAIR_GEN
KeyPairGenerator. DiffieHellman CKM_DH_PKCS_KEY_PAIR_GEN
KeyGenerator. ARCFOUR CKM_RC4_KEY_GEN
KeyGenerator. DES CKM_DES_KEY_GEN
KeyGenerator. DESede CKM_DES3_KEY_GEN
KeyGenerator. AES CKM_AES_KEY_GEN
KeyGenerator. Шифр CKM_BLOWFISH_KEY_GEN
Mac. HmacMD5 CKM_MD5_HMAC
Mac. HmacSHA1 CKM_SHA_1_HMAC
Mac. HmacSHA256 CKM_SHA256_HMAC
Mac. HmacSHA384 CKM_SHA384_HMAC
Mac. HmacSHA512 CKM_SHA512_HMAC
MessageDigest. MD2 CKM_MD2
MessageDigest. MD5 CKM_MD5
MessageDigest. SHA1 CKM_SHA_1
MessageDigest. SHA 256 CKM_SHA256
MessageDigest. SHA 384 CKM_SHA384
MessageDigest. SHA 512 CKM_SHA512
KeyFactory. RSA Любой поддерживал механизм RSA
KeyFactory. DSA Любой поддерживаемый механизм DSA
KeyFactory. EC Любой поддерживал механизм EC
KeyFactory. DiffieHellman Любой поддерживал механизм Diffie-Hellman
SecretKeyFactory. ARCFOUR CKM_RC4
SecretKeyFactory. DES CKM_DES_CBC
SecretKeyFactory. DESede CKM_DES3_CBC
SecretKeyFactory. AES CKM_AES_CBC
SecretKeyFactory. Шифр CKM_BLOWFISH_CBC
SecureRandom. PKCS11 У CK_TOKEN_INFO есть набор битов CKF_RNG
KeyStore. PKCS11 Всегда доступный

Приложение B: Sun PKCS#11 Требования KeyStore провайдера

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

Доступ только для чтения

Чтобы отобразить существующие объекты, хранившие на PKCS#11 маркер к записям KeyStore, Sun PKCS#11, реализация KeyStore Провайдера выполняет следующие операции.

  1. Поиск всех объектов с закрытым ключом на маркере выполняется, вызывая C_FindObjects [Init|Final]. Шаблон поиска включает следующие атрибуты:
  2. Поиск всех объектов сертификата на маркере выполняется, вызывая C_FindObjects [Init|Final]. Шаблон поиска включает следующие атрибуты:
  3. Каждый объект с закрытым ключом является соответствующим с его соответствующим сертификатом, получая их соответствующие атрибуты CKA_ID. Соответствующая пара должна совместно использовать тот же самый уникальный CKA_ID.

    Для каждой пары соответствия цепочка сертификата создается следующим выпускающий-> подчиненный путь. От сертификата объекта конца вызов fo C_FindObjects [Init|Final] выполняется с шаблоном поиска, который включает следующие атрибуты:

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

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

    Если у сертификата объекта конца нет никакого CKA_LABEL, то псевдоним получается из CKA_ID. Если CKA_ID может быть решен состоять исключительно из печатаемых символов, то Строковый псевдоним создается, декодируя байты CKA_ID, используя набор символов UTF-8. Иначе, шестнадцатеричный Строковый псевдоним создается из байтов CKA_ID ("0xFFFF...", например).

    Если многократные сертификаты совместно используют тот же самый CKA_LABEL, то псевдоним получается из CKA_LABEL плюс выпускающий сертификата объекта конца и порядковый номер ("MyCert/CN=foobar/1234", например).

  4. Каждый сертификат не часть записи с закрытым ключом (как сертификат объекта конца) проверяется, доверяют ли этому. Если атрибут CKA_TRUSTED является истиной, то KeyStore запись сертификата, которой доверяют, создается со значением CKA_LABEL как псевдоним KeyStore. Если у сертификата нет никакого CKA_LABEL, или если многократные сертификаты совместно используют тот же самый CKA_LABEL, то псевдоним получается как описано выше.

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

  5. Любой закрытый ключ или объект сертификата не часть записи с закрытым ключом или полагала, что запись сертификата игнорируется.
  6. Поиск всех объектов секретного ключа на маркере выполняется, вызывая C_FindObjects [Init|Final]. Шаблон поиска включает следующие атрибуты:

    Запись секретного ключа KeyStore создается для каждого объекта секретного ключа со значением CKA_LABEL как псевдоним KeyStore. У каждого объекта секретного ключа должен быть уникальный CKA_LABEL.

Доступ для записи

Чтобы создать новые записи KeyStore на PKCS#11 маркер к записям KeyStore, Sun PKCS#11, реализация KeyStore Провайдера выполняет следующие операции.

  1. Создавая запись KeyStore (во время KeyStore.setEntry, например), C_CreateObject вызывают с CKA_TOKEN=true, чтобы создать маркерные объекты для соответствующего содержания записи.

    Объекты с закрытым ключом хранятся с CKA_PRIVATE=true. (UTF8-закодированный) псевдоним KeyStore устанавливается как CKA_ID и для закрытого ключа и для соответствующего сертификата объекта конца. Псевдоним KeyStore также устанавливается как CKA_LABEL для объекта сертификата объекта конца.

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

    Объекты секретного ключа хранятся с CKA_PRIVATE=true. Псевдоним KeyStore устанавливается как CKA_LABEL.

  2. Если попытка предпринимается, чтобы преобразовать объект сеанса в маркерный объект (например, если KeyStore.setEntry вызывают, и объект с закрытым ключом в указанной записи является сеансом ojbect), то C_CopyObject вызывают с CKA_TOKEN=true.
  3. Если многократные сертификаты в маркере, как находят, совместно используют тот же самый CKA_LABEL, то возможности записи к маркеру отключаются.
  4. Начиная с PKCS#11 спецификация не позволяет регулярным приложениям устанавливать CKA_TRUSTED=true (только маркерные приложения инициализации могут сделать так), доверяемые записи сертификата не могут быть созданы.

Разное

В дополнение к упомянутым выше поискам следующие поискы могут использоваться Sun PKCS#11 реализация KeyStore провайдера, чтобы выполнить внутренние функции. Определенно, C_FindObjects [Init|Final] можно вызвать с любым из следующих шаблонов атрибута:

Приложение C: Провайдер В качестве примера

package com.foo;

import java.io.*;
import java.lang.reflect.*;
import java.security.*;
import javax.crypto.*;

/**
 * Example provider that demonstrates some of the new API features.
 *
 *  . implement multiple different algorithms in a single class.
 *    Previously each algorithm needed to be implemented in a separate class
 *    (e.g. one for MD5, one for SHA-1, etc.)
 *
 *  . multiple concurrent instances of the provider frontend class each
 *    associated with a different backend.
 *
 *  . it uses "unextractable" keys and lets the framework know which key
 *    objects it can and cannot support
 *
 * Note that this is only a simple example provider designed to demonstrate
 * several of the new features.  It is not explicitly designed for efficiency.
 */
public final class ExampleProvider extends Provider {

    // reference to the crypto backend that implements all the algorithms
    final CryptoBackend cryptoBackend;

    public ExampleProvider(String name, CryptoBackend cryptoBackend) {
        super(name, 1.0, "JCA/JCE provider for " + name);
        this.cryptoBackend = cryptoBackend;
        // register the algorithms we support (MD5, SHA1, DES, and AES)
        putService(new MyService
            (this, "MessageDigest", "MD5", "com.foo.ExampleProvider$MyMessageDigest"));
        putService(new MyService
            (this, "MessageDigest", "SHA1", "com.foo.ExampleProvider$MyMessageDigest"));
        putService(new MyCipherService
            (this, "Cipher", "DES", "com.foo.ExampleProvider$MyCipher"));
        putService(new MyCipherService
            (this, "Cipher", "AES", "com.foo.ExampleProvider$MyCipher"));
    }

    // the API of our fictitious crypto backend
    static abstract class CryptoBackend {
        abstract byte[] digest(String algorithm, byte[] data);
        abstract byte[] encrypt(String algorithm, KeyHandle key, byte[] data);
        abstract byte[] decrypt(String algorithm, KeyHandle key, byte[] data);
        abstract KeyHandle createKey(String algorithm, byte[] keyData);
    }

    // the shell of the representation the crypto backend uses for keys
    private static final class KeyHandle {
        // fill in code
    }

    // we have our own ServiceDescription implementation that overrides newInstance()
    // that calls the (Provider, String) constructor instead of the no-args constructor
    private static class MyService extends Service {

        private static final Class[] paramTypes = {Provider.class, String.class};

        MyService(Provider provider, String type, String algorithm,
                String className) {
            super(provider, type, algorithm, className, null, null);
        }

        public Object newInstance(Object param) throws NoSuchAlgorithmException {
            try {
                // get the Class object for the implementation class
                Class clazz;
                Provider provider = getProvider();
                ClassLoader loader = provider.getClass().getClassLoader();
                if (loader == null) {
                    clazz = Class.forName(getClassName());
                } else {
                    clazz = loader.loadClass(getClassName());
                }
                // fetch the (Provider, String) constructor
                Constructor cons = clazz.getConstructor(paramTypes);
                // invoke constructor and return the SPI object
                Object obj = cons.newInstance(new Object[] {provider, getAlgorithm()});
                return obj;
            } catch (Exception e) {
                throw new NoSuchAlgorithmException("Could not instantiate service", e);
            }
        }
    }

    // custom ServiceDescription class for Cipher objects. See supportsParameter() below
    private static class MyCipherService extends MyService {
        MyCipherService(Provider provider, String type, String algorithm,
                String className) {
            super(provider, type, algorithm, className);
        }
        // we override supportsParameter() to let the framework know which
        // keys we can support. We support instances of MySecretKey, if they
        // are stored in our provider backend, plus SecretKeys with a RAW encoding.
        public boolean supportsParameter(Object obj) {
            if (obj instanceof SecretKey == false) {
                return false;
            }
            SecretKey key = (SecretKey)obj;
            if (key.getAlgorithm().equals(getAlgorithm()) == false) {
                return false;
            }
            if (key instanceof MySecretKey) {
                MySecretKey myKey = (MySecretKey)key;
                return myKey.provider == getProvider();
            } else {
                return "RAW".equals(key.getFormat());
            }
        }
    }

    // our generic MessageDigest implementation. It implements all digest
    // algorithms in a single class. We only implement the bare minimum
    // of MessageDigestSpi methods
    private static final class MyMessageDigest extends MessageDigestSpi {
        private final ExampleProvider provider;
        private final String algorithm;
        private ByteArrayOutputStream buffer;
        MyMessageDigest(Provider provider, String algorithm) {
            super();
            this.provider = (ExampleProvider)provider;
            this.algorithm = algorithm;
            engineReset();
        }
        protected void engineReset() {
            buffer = new ByteArrayOutputStream();
        }
        protected void engineUpdate(byte b) {
            buffer.write(b);
        }
        protected void engineUpdate(byte[] b, int ofs, int len) {
            buffer.write(b, ofs, len);
        }
        protected byte[] engineDigest() {
            byte[] data = buffer.toByteArray();
            byte[] digest = provider.cryptoBackend.digest(algorithm, data);
            engineReset();
            return digest;
        }
    }

    // our generic Cipher implementation, only partially complete. It implements
    // all cipher algorithms in a single class. We implement only as many of the
    // CipherSpi methods as required to show how it could work
    private static abstract class MyCipher extends CipherSpi {
        private final ExampleProvider provider;
        private final String algorithm;
        private int opmode;
        private MySecretKey myKey;
        private ByteArrayOutputStream buffer;
        MyCipher(Provider provider, String algorithm) {
            super();
            this.provider = (ExampleProvider)provider;
            this.algorithm = algorithm;
        }
        protected void engineInit(int opmode, Key key, SecureRandom random)
                throws InvalidKeyException {
            this.opmode = opmode;
            myKey = MySecretKey.getKey(provider, algorithm, key);
            if (myKey == null) {
                throw new InvalidKeyException();
            }
            buffer = new ByteArrayOutputStream();
        }
        protected byte[] engineUpdate(byte[] b, int ofs, int len) {
            buffer.write(b, ofs, len);
            return new byte[0];
        }
        protected int engineUpdate(byte[] b, int ofs, int len, byte[] out, int outOfs) {
            buffer.write(b, ofs, len);
            return 0;
        }
        protected byte[] engineDoFinal(byte[] b, int ofs, int len) {
            buffer.write(b, ofs, len);
            byte[] in = buffer.toByteArray();
            byte[] out;
            if (opmode == Cipher.ENCRYPT_MODE) {
                out = provider.cryptoBackend.encrypt(algorithm, myKey.handle, in);
            } else {
                out = provider.cryptoBackend.decrypt(algorithm, myKey.handle, in);
            }
            buffer = new ByteArrayOutputStream();
            return out;
        }
        // code for remaining CipherSpi methods goes here
    }

    // our SecretKey implementation. All our keys are stored in our crypto
    // backend, we only have an opaque handle available. There is no
    // encoded form of these keys.
    private static final class MySecretKey implements SecretKey {

        final String algorithm;
        final Provider provider;
        final KeyHandle handle;

        MySecretKey(Provider provider, String algorithm, KeyHandle handle) {
            super();
            this.provider = provider;
            this.algorithm = algorithm;
            this.handle = handle;
        }
        public String getAlgorithm() {
            return algorithm;
        }
        public String getFormat() {
            return null; // this key has no encoded form
        }
        public byte[] getEncoded() {
            return null; // this key has no encoded form
        }
        // Convert the given key to a key of the specified provider, if possible
        static MySecretKey getKey(ExampleProvider provider, String algorithm, Key key) {
            if (key instanceof SecretKey == false) {
                return null;
            }
            // algorithm name must match
            if (!key.getAlgorithm().equals(algorithm)) {
                return null;
            }
            // if key is already an instance of MySecretKey and is stored
            // on this provider, return it right away
            if (key instanceof MySecretKey) {
                MySecretKey myKey = (MySecretKey)key;
                if (myKey.provider == provider) {
                    return myKey;
                }
            }
            // otherwise, if the input key has a RAW encoding, convert it
            if (!"RAW".equals(key.getFormat())) {
                return null;
            }
            byte[] encoded = key.getEncoded();
            KeyHandle handle = provider.cryptoBackend.createKey(algorithm, encoded);
            return new MySecretKey(provider, algorithm, handle);
        }
    }
}

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