Spec-Zone .ru
спецификации, руководства, описания, API
|
Provider
КлассSecurity
КлассSecureRandom
КлассMessageDigest
КлассSignature
КлассCipher
КлассCipher
На основе КлассыMac
КлассKey
ИнтерфейсыKeyPair
КлассKey
Интерфейсы спецификации и КлассыKeyFactory
КлассSecretKeyFactory
КлассKeyPairGenerator
КлассKeyGenerator
КлассKeyAgreement
КлассCertificateFactory
КлассMessageDigest
ОбъектKey
Спецификации и KeyFactory
Платформа Java придает особое значение безопасности, включая безопасность языка, криптографию, инфраструктуру управления открытыми ключами, аутентификацию, безопасную передачу, и управление доступом.
JCA является главной частью платформы, и содержит архитектуру "провайдера" и ряд API для цифровых подписей, обзоры сообщения (hashs), сертификаты и проверка допустимости сертификата, шифрование (симметричный/асимметричный блок/поточные шифры), генерация ключей и управление, и безопасная генерация случайных чисел, чтобы назвать некоторых. Эти API позволяют разработчикам легко интегрировать безопасность в свой код программы. Архитектура была разработана вокруг следующих принципов:
Другие криптографические коммуникационные библиотеки, доступные в JDK, используют архитектуру провайдера JCA, но описываются в другом месте. Расширение Защищенного сокета Java™ (JSSE) обеспечивает доступ к Уровню защищенных сокетов (SSL) и Безопасность Транспортного уровня (TLS) реализации. Java Универсальные Службы безопасности (JGSS) (через Kerberos) API, и Простой Уровень Аутентификации и Безопасности (SASL) может также использоваться для того, чтобы надежно обмениваться сообщениями между связывающимися приложениями.
java.security
, javax.crypto
, javax.crypto.spec
, и javax.crypto.interfaces
.Sun
, SunRsaSign
, SunJCE
, которые содержат фактические криптографические реализации.Всякий раз, когда определенный провайдер JCA упоминается, он будет упомянут явно именем провайдера.
ПРЕДУПРЕЖДЕНИЕ: JCA облегчает включать средства защиты в Ваше приложение. Однако, этот документ не касается теории безопасности/криптографии вне элементарного введения в понятия, необходимые, чтобы обсудить API. Этот документ также не касается сильных мест/слабых мест определенных алгоритмов, не делает он покрывает проект протокола. Криптография является усовершенствованной темой, и нужно консультироваться с телом, предпочтительно недавним, ссылочным, чтобы лучше всего использовать эти инструменты.
Следует всегда понимать то, что Вы делаете и почему: DO НЕ просто копирует случайный код и ожидает, что это полностью решит Ваш сценарий использования. Много приложений были развернуты, которые содержат существенную безопасность или проблемы производительности, потому что неправильный инструмент или алгоритм были выбраны.
JCA был разработан вокруг этих принципов:
Независимость реализации и независимость алгоритма дополнительны; можно использовать криптографические службы, такие как цифровые подписи и передать обзоры, не волнуясь о деталях реализации или даже алгоритмах, которые формируют основание для этих понятий. В то время как полная независимость алгоритма не возможна, JCA обеспечивает стандартизированные, специфичные для алгоритма API. Когда независимость реализации не является требуемой, JCA позволяет разработчикам указывать на определенную реализацию.
Независимость алгоритма достигается, определяя типы криптографических "механизмов" (службы), и определяя классы, которые обеспечивают функциональность этих криптографических механизмов. Эти классы вызывают классами механизма, и примеры MessageDigest
, Signature
, KeyFactory
, KeyPairGenerator
, и Cipher
классы.
Независимость реализации достигается, используя "провайдера" на основе архитектура. Провайдер криптографических служб термина (CSP) (используемый взаимозаменяемо с "провайдером" в этом документе) обращается к пакету или набору пакетов, которые реализуют один или более криптографические службы, такие как алгоритмы цифровой подписи, алгоритмы обзора сообщения, и манипулируют службы преобразования. Программа может просто запросить определенный тип объекта (такого как a Signature
объект), реализация определенной службы (такой как алгоритм подписи DSA) и получают реализацию от одного из установленных провайдеров. При желании программа может вместо этого запросить реализацию от определенного провайдера. Провайдеры могут быть обновлены прозрачно к приложению, например когда более быстрые или более безопасные версии доступны.
Функциональная совместимость реализации означает, что различные реализации могут работать друг с другом, используйте ключи друг друга, или проверьте подписи друг друга. Это означало бы, например, что для тех же самых алгоритмов, ключ, сгенерированный одним провайдером, будет применим другим, и подпись, сгенерированная одним провайдером, была бы поддающейся проверке другим.
Расширяемость алгоритма означает, что новые алгоритмы, которые помещаются в один из поддерживаемых классов механизма, могут быть добавлены легко.
java.security.Provider
базовый класс для всех поставщиков систем обеспечения безопасности. Каждый CSP содержит экземпляр этого класса, который содержит имя провайдера и перечисляет все службы/алгоритмы безопасности, которые это реализует. Когда экземпляр определенного алгоритма необходим, платформа 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.
Криптографические реализации на солнце JDK распределяются через несколько различных провайдеров (Sun
, SunJSSE
, SunJCE
, SunRsaSign
) прежде всего по историческим причинам, но до меньшей степени типом функциональности и алгоритмов они обеспечивают. Другие среды выполнения Java, возможно, не обязательно содержат этих провайдеров Sun, таким образом, приложения не должны запросить специфичную для провайдера реализацию, если не известно, что определенный провайдер будет доступен.
JCA предлагает ряд API, которые позволяют пользователям запрашивать, какие провайдеры устанавливаются и что обслуживает, они поддерживают.
Эта архитектура также облегчает для конечных пользователей добавлять дополнительных провайдеров. Много сторонних реализаций провайдера уже доступны. См. Provider
Класс для получения дополнительной информации о том, как провайдеры пишутся, установил, и зарегистрировался.
Как отмечалось ранее независимость алгоритма достигается, определяя универсальный высокоуровневый Прикладной программный интерфейс (API) что все использование приложений, чтобы получить доступ к типу службы. Независимость реализации достигается при наличии всех реализаций провайдера, соответствуют четко определенным интерфейсам. Экземпляры классов механизма таким образом "поддерживаются" классами реализации, у которых есть те же самые сигнатуры методов. Вызовы приложения направляются через класс механизма и поставляются базовой реализации поддержки. Реализация обрабатывает запрос, и возвратите надлежащие результаты.
Методы API приложения в каждом классе механизма направляются к реализациям провайдера через классы, которые реализуют соответствующий Интерфейс Поставщика услуг (SPI). Таким образом, для каждого класса механизма есть соответствующий абстрактный класс SPI, который определяет методы, которые должен реализовать алгоритм каждого провайдера криптографических служб. Имя каждого класса SPI является тем же самым как тем из соответствующего класса механизма, сопровождаемого Spi
. Например, Signature
класс механизма обеспечивает доступ к функциональности алгоритма цифровой подписи. Фактическая реализация провайдера предоставляется в подклассе SignatureSpi
. Приложения вызывают методы API класса механизма, которые поочередно вызывают методы SPI в фактической реализации.
Каждый класс SPI абстрактен. Чтобы предоставить реализацию определенного типа службы для определенного алгоритма, провайдер должен разделить соответствующий класс SPI на подклассы и обеспечить реализации для всех абстрактных методов.
Для каждого класса механизма в API экземпляры реализации требуют и инстанцируются, вызывая getInstance()
метод фабрики в классе механизма. Метод фабрики является статическим методом, который возвращает экземпляр класса. Классы механизма используют механизм выбора провайдера платформы, описанный выше, чтобы получить фактическую реализацию поддержки (SPI), и затем создает фактический объект механизма. Каждый экземпляр класса механизма инкапсулирует (как частное поле) экземпляр соответствующего класса SPI, известного как объект SPI. Все методы API объекта API объявляются финалом, и их реализации вызывают соответствующие методы SPI инкапсулировавшего объекта SPI.
Чтобы сделать это более четким, рассмотрите следующий код и иллюстрацию:
import javax.crypto.*; Cipher c = Cipher.getInstance("AES"); c.init(ENCRYPT_MODE, key);
Здесь приложение хочет "AES" javax.crypto.Cipher
экземпляр, и не заботится, какой провайдер используется. Приложение вызывает getInstance()
методы фабрики Cipher
класс механизма, который поочередно просит, чтобы платформа JCA нашла первый экземпляр провайдера, который поддерживает "AES". Платформа консультируется с каждым установленным провайдером, и получает экземпляр провайдера Provider
класс. (Вспомните что Provider
класс является базой данных доступных алгоритмов.) Платформа ищет каждого провайдера, наконец находя подходящую запись в CSP3. Эта база данных точки входа к классу реализации com.foo.AESCipher
который расширяется CipherSpi
, и является таким образом подходящим для использования Cipher
класс механизма. Экземпляр com.foo.AESCipher
создается, и инкапсулируется в недавно создаваемом экземпляре javax.crypto.Cipher
, который возвращается к приложению. Когда приложение теперь делает init()
работа на Cipher
экземпляр, Cipher
класс механизма направляет запрос в соответствие engineInit()
поддержка метода в com.foo.AESCipher
класс.
Приложение списки Стандартные имена определяется для среды Java. Другие сторонние провайдеры могут определить свои собственные реализации этих служб, или даже дополнительных служб.
База данных, названная "keystore", может использоваться, чтобы управлять репозитарием ключей и сертификатов. Keystores доступны приложениям, которые нуждаются в данных для аутентификации, шифрования, или подписания целей.
Приложения могут получить доступ к keystore через реализацию KeyStore
класс, который находится в java.security
пакет. Значение по умолчанию KeyStore
реализация обеспечивается Sun Microsystems. Это реализует keystore как файл, используя собственный тип keystore (формат), названный "jks". Другие форматы keystore доступны, таковы как "jceks", который является альтернативным собственным форматом keystore с намного более сильным шифрованием чем "jks", и "pkcs12", который основан на RSA
Приложения могут выбрать различные keystore реализации из различных провайдеров, используя тот же самый механизм провайдера, описанный выше.
См. раздел управления ключами для получения дополнительной информации.
Этот раздел представляет главные API JCA.
Класс механизма обеспечивает интерфейс для определенного типа криптографической службы, независимой от определенного криптографического алгоритма или провайдера. Механизмы любой обеспечивает:
Следующие классы механизма доступны:
SecureRandom
: используемый, чтобы генерировать случайные или псевдослучайные числа.MessageDigest
: используемый, чтобы вычислить обзор сообщения (хеш) указанных данных.Signature
: initilialized с ключами, они используются, чтобы подписать данные и проверить цифровые подписи.Cipher
: инициализированный с ключами, они используемые для того, чтобы шифровать/дешифровать данные. Есть различные типы алгоритмов: симметричное шифрование больших объемов данных (например, AES, DES, DESede, Шифр, ИДЕЯ), поточное шифрование (например. RC4), асимметричное шифрование (например. RSA), и основанное на пароле шифрование (PBE).MessageDigest
s, они также генерируют значения хэш-функции, но сначала инициализируются с ключами, чтобы защитить целостность сообщений.KeyFactory
: используемый, чтобы преобразовать существующие непрозрачные криптографические ключи типа Key
в ключевые спецификации (прозрачные представления базового ключевого материала), и наоборот.SecretKeyFactory
: используемый, чтобы преобразовать существующие непрозрачные криптографические ключи типа SecretKey
в ключевые спецификации (прозрачные представления базового ключевого материала), и наоборот. SecretKeyFactory
s специализируются KeyFactory
s, которые создают секретные (симметричные) ключи только.KeyPairGenerator
: используемый, чтобы генерировать новую пару открытых и закрытых ключей, подходящих для использования с указанным алгоритмом.KeyGenerator
: используемый, чтобы генерировать новые секретные ключи для использования с указанным алгоритмом.KeyAgreement
: используемый двумя или больше сторонами, чтобы согласовать и установить определенный ключ, чтобы использовать для определенной криптографической работы.AlgorithmParameters
: используемый, чтобы сохранить параметры для определенного алгоритма, включая кодирование параметра и декодирование.AlgorithmParameterGenerator
: используемый, чтобы генерировать ряд AlgorithmParameters, подходящего для указанного алгоритма. KeyStore
: используемый, чтобы создать и управлять keystore. keystore является базой данных ключей. У закрытых ключей в keystore есть цепочка сертификата, связанная с ними, который аутентифицирует соответствующий открытый ключ. keystore также содержит сертификаты от доверяемых объектов.CertificateFactory
: используемый, чтобы создать сертификаты с открытым ключом и Списки аннулированных сертификатов (CRL).CertPathBuilder
: используемый, чтобы создать цепочки сертификата (также известный как пути сертификации).CertPathValidator
: используемый, чтобы проверить цепочек сертификата.CertStore
: используемый, чтобы получить Certificate
s и CRL
s от репозитария.Этот раздел обсуждает базовые классы и интерфейсы, обеспеченные в JCA:
Provider
и Security
классы,SecureRandom
, MessageDigest
, Signature
, Cipher
, Mac
, KeyFactory
, SecretKeyFactory
, KeyPairGenerator
, KeyGenerator
, KeyAgreement
, AlgorithmParameters
, AlgorithmParameterGenerator
, KeyStore
, и CertificateFactory
, классы механизма,Key
интерфейсы и классы,CertPathBuilder
, CertPathValidator
, и CertStore
классы механизма, пожалуйста, см. Java (ТМ) Руководство Программиста PKI. Provider
, Security
, SecureRandom
, MessageDigest
, Signature
, Cipher
, и Mac
), затем копайтесь в различных классах поддержки. Пока, достаточно просто сказать, что Ключи (общедоступный, частный, и секретный) сгенерированы и представлены различными классами JCA, и используются высокоуровневыми классами в качестве части их работы. Этот раздел показывает подписи основных методов в каждом классе и интерфейсе. Примеры для некоторых из этих классов (MessageDigest
, Signature
, KeyPairGenerator
, SecureRandom
, KeyFactory
, и ключевые классы спецификации), предоставляются в соответствующих разделах В качестве примера.
Полная справочная документация для соответствующих пакетов API Безопасности может быть найдена в сводках пакета:
Provider
КлассТермин "Провайдер криптографических служб" (используемый взаимозаменяемо с "провайдером" в этом документе) относится к пакету или набору пакетов, которые предоставляют конкретную реализацию подмножества функций криптографии API Безопасности JDK. Provider
класс является интерфейсом к такому пакету или набору пакетов. У этого есть методы для того, чтобы получить доступ к имени провайдера, номеру версии, и другой информации. Пожалуйста, отметьте это в дополнение к регистрирующимся реализациям криптографических служб, Provider
класс может также использоваться, чтобы зарегистрировать реализации других служб безопасности, которые могли бы быть определены как часть API Безопасности JDK или одно из его расширений.
Чтобы предоставить реализации криптографических служб, объект (например, группа разработки) пишет, что реализация кодирует, и создает подкласс Provider
класс. Конструктор Provider
разделите на подклассы устанавливает значения различных свойств; API Безопасности JDK использует эти значения, чтобы искать службы, которые реализует провайдер. Другими словами подкласс определяет имена классов, реализовывая службы.
Есть несколько типов служб, которые могут быть реализованы пакетами провайдера; для получения дополнительной информации см. Классы Механизма и Алгоритмы.
У различных реализаций могут быть различные характеристики. Некоторые могут быть основаны на программном обеспечении, в то время как другие могут быть основаны на аппаратных средствах. Некоторые могут быть независимыми от платформы, в то время как другие могут быть специфичными для платформы. Некоторый исходный код провайдера может быть доступным для анализа и оценки, в то время как некоторые не могут. JCA позволяет и конечным пользователям и разработчикам, решают, каковы их потребности.
В этом разделе мы объясняем, как конечные пользователи устанавливают реализации криптографии, которые соответствуют их потребностям, и как разработчики запрашивают реализации, которые соответствуют их.
getInstance
методы на классе механизма, определяя имя требуемого алгоритма и, дополнительно, имя провайдера (или Provider
класс), чья реализация требуется. 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
. Предположите что:
PROVIDER_1
реализации SHA1withDSA, SHA 1, MD5, DES, и DES3.PROVIDER_1
имеет привилегированный порядок 1 (самый высокий приоритет).PROVIDER_2
реализации SHA1withDSA, MD5withRSA, MD2withRSA, MD2, MD5, RC4, RC5, DES, и RSA.PROVIDER_2
имеет привилегированный порядок 2.PROVIDER_1
реализация возвращается с тех пор PROVIDER_1
имеет самый высокий приоритет и ищется сначала.PROVIDER_1
сначала ищется это. Никакая реализация не находится, таким образом, PROVIDER_2
ищется. Так как реализация находится, она возвращается.NoSuchAlgorithmException
бросается. getInstance
методы, которые включают параметр провайдера, для разработчиков, которые хотят определить, от какого провайдера они хотят алгоритм. Федеральное агентство, например, будет хотеть использовать реализацию провайдера, которая получила федеральную сертификацию. Давайте предполагать что реализация SHA1withDSA от PROVIDER_1
не получил такую сертификацию, в то время как реализация DSA PROVIDER_2
получил это.
У программы федерального агентства тогда был бы следующий вызов, определяя PROVIDER_2
так как у этого есть сертифицированная реализация:
Signature dsa = Signature.getInstance("SHA1withDSA", "PROVIDER_2");
В этом случае, если PROVIDER_2
не был установлен, a NoSuchProviderException
был бы брошен, даже если другой установленный провайдер реализует алгоритм, который требуют.
У программы также есть опция получения списка всех установленных провайдеров (использующий getProviders
метод в Security
класс) и выбор того от списка.
Чтобы использоваться, криптографический провайдер должен сначала быть установлен, затем зарегистрировался или статически или динамически. Есть множество провайдеров Sun, поставленных с этим выпуском (SUN
, SunJCE
, SunJSSE
, SunRsaSign
, и т.д.), которые уже устанавливаются и регистрируются. Следующие разделы описывают, как установить и зарегистрировать дополнительных провайдеров.
Есть два возможных способа установить классы провайдера:
Поместите zip или файл JAR, содержащий классы куда угодно в Вашем пути к классу. Некоторые (Шифры) типов алгоритмов требуют, чтобы провайдер был файлом Фляги со знаком.
Провайдера будут считать установленным расширением, если он будет помещен в стандартный каталог расширения. В 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
должен определить полностью определенное имя мастер класса провайдера. Документация провайдера определит свой мастер класс. Этот класс всегда является подклассом Provider
класс. Конструктор подкласса устанавливает значения различных свойств, которые требуются для API Криптографии Java искать алгоритмы или другие средства реализации провайдера.
JDK прибывает стандарт с автоматически установленными и сконфигурированными провайдерами, такими как "SUN" и "SunJCE". Мастер класс провайдера "SUN" SUN
класс в sun.security.provider
пакет, и соответствующая java.security запись файла следующие:
security.provider.5=sun.security.provider.Sun
Чтобы использовать другого провайдера JCA, добавьте строку, ссылающуюся на альтернативного провайдера, определите привилегированный порядок (вносящий соответствующие корректировки в заказы других провайдеров, если нужно).
Предположите, что мастер класс провайдера CompanyX com.companyx.provider.ProviderX
, и это требуется сконфигурировать этого провайдера как наиболее предпочтенное восьмое. Чтобы сделать так, Вы добавили бы следующую строку к java.security
файл:
security.provider.8=com.companyx.provider.ProviderX
addProvider
или insertProviderAt
метод в Security
класс. Этот тип регистрации не является персистентным через экземпляры VM, и может только быть сделан программами, которым "доверяют", с соответствующим полномочием. См. Безопасность. Всякий раз, когда провайдеры шифрования используются (то есть, те, которые предоставляют реализации Шифра, KeyAgreement, KeyGenerator, Mac, или SecretKeyFactory), и провайдер не является установленным расширением, которое Полномочия, возможно, должны быть предоставлены для того, когда апплеты или приложения, используя JCA выполняются, в то время как менеджер безопасности устанавливается. обычно есть менеджер безопасности, установленный всякий раз, когда апплет работает, и менеджер безопасности может быть установлен для приложения или через код в приложении непосредственно или через параметр командной строки. Полномочия не должны предоставить установленным расширениям, так как системный конфигурационный файл политики по умолчанию предоставляет все полномочия установленным расширениям (то есть, установленный в каталоге расширений).
Документация от поставщика каждого провайдера, которого Вы будете использовать, должна включать информацию, относительно которого полномочий это требует, и как предоставить такие полномочия. Например, следующие полномочия могут быть необходимы провайдеру, если это не установленное расширение, и менеджер безопасности устанавливается:
java.lang.RuntimePermission "getProtectionDomain"
получить домены защиты класса. Провайдер, возможно, должен получить свой домен собственной защиты в процессе выполнения проверки самоцелостности.java.security.SecurityPermission "putProviderProperty.{name}"
установить свойства провайдера, где {name}
заменяется фактическим именем провайдера.Например, демонстрационное предоставление оператора полномочия к провайдеру, имя которого является "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
у экземпляра класса есть (в настоящий момент чувствительное к регистру) имя, номер версии, и строковое описание провайдера и его служб. Можно запросить Provider
экземпляр для этой информации, вызывая следующие методы:
public String getName() public double getVersion() public String getInfo()
Security
Класс Security
класс управляет установленными провайдерами и свойствами всей безопасности. Это только содержит статические методы и никогда не инстанцируется. Методы для добавления или удаления провайдеров, и для того, чтобы установить Security
свойства, может только быть выполнен доверяемой программой. В настоящий момент "доверяемая программа" также
Выполняемый код, как всегда полагают, прибывает из определенного "источника кода". Источник кода включает не только расположение (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
класс можно использовать, чтобы запросить который Provider
s устанавливаются, так же как установить или удалить провайдеров во время выполнения.
Метод | Описание |
---|---|
static Provider[] getProviders() |
Возвращает массив, содержащий всех установленных провайдеров (технически, Provider подкласс для каждого провайдера пакета). Порядок Provider s в массиве их привилегированный порядок. |
static Provider getProvider |
Возвраты Provider именованный providerName . Это возвращается null если Provider не находится. |
Метод | Описание |
---|---|
static int addProvider(Provider provider) |
Добавляет a Provider до конца списка установленных Provider s. Это возвращает привилегированную позицию в который Provider был добавлен, или -1 если Provider не был добавлен, потому что это было уже установлено. |
static int insertProviderAt (Provider provider, int position) |
Добавляет новое Provider в указанной позиции. Если данный провайдер устанавливается в требуемой позиции, провайдер прежде в той позиции и всех провайдерах с позицией, больше чем position смещаются одна позиция (к концу списка). Этот метод возвращает привилегированную позицию в который Provider был добавлен, или -1 если Provider не был добавлен, потому что это было уже установлено. |
Метод | Описание |
---|---|
static void removeProvider(String name) |
Удаляет Provider с указанным именем. Это возвращается тихо, если провайдер не устанавливается. Когда указанный провайдер удаляется, все провайдеры, расположенные в позиции, больше чем, где указанный провайдер был, смещаются вниз одна позиция (к главе списка установленных провайдеров). |
ОТМЕТЬТЕ: Если Вы хотите изменить привилегированную позицию провайдера, следует сначала удалить ее, и затем вставить ее, въезжают задним ходом в новой привилегированной позиции.
Security
класс поддерживает список свойств безопасности в масштабе всей системы. Эти свойства подобны 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
класс является классом механизма, который обеспечивает функциональность Генератора случайных чисел (RNG). Это отличается от Random
класс в этом это производит криптографически сильные случайные числа. Если есть недостаточная случайность в генераторе, она делает намного легче поставить под угрозу Ваши механизмы защиты. Случайные числа используются всюду по криптографии, такой как генерирование криптографических ключей или алгоритмических параметров.
SecureRandom
ОбъектSecureRandom
объект состоит в том, чтобы вызвать один из getInstance()
статические методы фабрики в SecureRandom
класс. SecureRandom
Объект SecureRandom
реализация пытается полностью рандомизировать внутреннее состояние генератора непосредственно, если вызывающая сторона не следует за звонком a getInstance
метод со звонком в один из setSeed
методы:
synchronized public void setSeed(byte[] seed) public void setSeed(long seed)Однажды
SecureRandom
объект был отобран, он произведет биты столь же случайные как исходные семена. В любое время a SecureRandom
объект может быть повторно отобран, используя один из setSeed
методы. Данные дополнения семени, а не замены, существующее семя; поэтому, повторные вызовы, как гарантируют, никогда не не уменьшат случайность.
SecureRandom
ОбъектЧтобы получить случайные байты, вызывающая сторона просто передает массив любой длины, которая тогда заполнена случайными байтами:
synchronized public void nextBytes(byte[] bytes)
generateSeed
метод, чтобы генерировать данное число байтов семени (чтобы отобрать другие генераторы случайных чисел, например): byte[] generateSeed(int numBytes)
MessageDigest
Класс MessageDigest
класс является классом механизма, разработанным, чтобы обеспечить функциональность криптографически безопасных обзоров сообщения, таких как SHA 1 или MD5. Криптографически безопасный обзор сообщения берет ввод произвольного размера (байтовый массив), и генерирует вывод фиксированного размера, названный обзором или хешем.
Например, алгоритм MD5 производит 16-байтовый обзор, и SHA1's составляет 20 байтов.
У обзора есть два свойства:
Обзоры сообщения используются, чтобы произвести уникальные и надежные идентификаторы данных. Их иногда вызывают "контрольными суммами" или "цифровыми отпечатками" данных. Изменения только к одному биту сообщения должны произвести различное значение обзора.
Обзоры сообщения имеют много использования и могут определить, когда данные были изменены, преднамеренно или нет. Недавно, было значительное усилие определить, есть ли какие-либо слабые места в популярных алгоритмах со смешанными результатами. Выбирая алгоритм обзора, нужно всегда консультироваться с недавней ссылкой, чтобы определить ее состояние и уместность для задачи под рукой.
MessageDigest
ОбъектПервый шаг для того, чтобы вычислить обзор должен создать экземпляр обзора сообщения. MessageDigest
объекты получаются при использовании одного из getInstance()
статические методы фабрики в MessageDigest
класс. Метод фабрики возвращает инициализированный объект обзора сообщения. Это таким образом не нуждается в дальнейшей инициализации.
Следующий шаг для того, чтобы вычислить обзор некоторых данных должен снабдить данными к инициализированному объекту обзора сообщения. Это может быть обеспечено внезапно, или в блоках. Части могут питаться к обзору сообщения, вызывая один из 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
класс является классом механизма, разработанным, чтобы обеспечить функциональность криптографического алгоритма цифровой подписи, такого как DSA или RSAwithMD5. Криптографически безопасный алгоритм подписи берет ввод произвольного размера и закрытый ключ и генерирует относительно короткое (часто фиксированный размер) строка байтов, названных подписью, со следующими свойствами: A Signature
объект инициализируется для того, чтобы подписаться с Закрытым ключом и дается данные, которые будут подписаны. Получающиеся байты подписи обычно сохраняются с данными со знаком. Когда проверка необходима, другой Signature
объект создается и инициализируется для проверки и дается соответствующий Открытый ключ. Данные и байты подписи питаются к объекту подписи, и если данные и соответствие подписи, Signature
объект сообщает об успехе.
Даже при том, что подпись кажется подобной обзору сообщения, у них есть совсем другие цели в типе защиты, которую они обеспечивают. Фактически, алгоритмы, такие как "SHA1WithRSA" используют обзор сообщения "SHA1", чтобы первоначально "сжать" большие наборы данных в более управляемую форму, затем подписывают получающийся 20-байтовый обзор сообщения с алгоритмом "RSA".
Пожалуйста, см. раздел В качестве примера для примера подписания и проверки данных.
Signature
Объектные государстваSignature
объекты являются модальными объектами. Это означает это a Signature
объект всегда находится в данном состоянии, где он может только сделать один тип работы. Государства представляются как заключительные целочисленные константы, определенные в их соответствующих классах. Три состояния a Signature
объект может иметь:
UNINITIALIZED
SIGN
VERIFY
Signature
объект находится в UNINITIALIZED
состояние. Signature
класс определяет два метода инициализации, initSign
и initVerify
, которые изменяют состояние на SIGN
и VERIFY
, соответственно. Signature
ОбъектSignature
экземпляр. Signature
объекты получаются при использовании одного из Signature
getInstance()
статические методы фабрики. 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
класс обеспечивает функциональность криптографического шифра, используемого для шифрования и дешифрования. Шифрование является процессом взятия данных (названный открытым текстом) и ключ, и создание данных (шифрованный текст), бессмысленный к стороннему, кто не знает ключ. Дешифрование является обратным процессом: это взятия шифрованного текста и ключа и создания открытого текста.
Асимметричные алгоритмы (такие как RSA) обычно намного медленнее чем симметричные. Эти алгоритмы не разрабатываются для того, чтобы эффективно защитить большие объемы данных. Практически, асимметричные алгоритмы используются, чтобы обмениваться меньшими секретными ключами, которые используются, чтобы инициализировать симметричные алгоритмы.
Шифруя использование простого блочного шифра, два идентичных блока простого текста будут всегда производить идентичный блок шифрованного текста. У криптоаналитиков, пытающихся повредить шифрованный текст, будет более легкое задание, если они отметят блоки повторяющегося текста. Чтобы добавить больше сложности к тексту, режимы обратной связи используют предыдущий блок вывода, чтобы изменить входные блоки прежде, чем применить алгоритм шифрования. Первый блок будет нуждаться в начальном значении, и это значение вызывают вектором инициализации (IV). Так как IV просто изменяет данные прежде, чем любое шифрование, IV должен будет быть случайным, но должен будет не обязательно держаться в секрете. Есть множество режимов, таких как CBC (Сцепление блоков шифра), CFB (Режим Обратной связи Шифра), и OFB (Выходной Режим Обратной связи). ECB (Электронный Режим Поваренной книги) является режимом без обратной связи.
Некоторые алгоритмы, такие как AES и RSA учитывают ключи различных длин, но другие фиксируются, такие как DES и 3DES. Шифрование используя ключ большей длины обычно подразумевает более сильное сопротивление, чтобы передать восстановление. Как обычно есть компромисс между безопасностью и время, так выберите длину ключа соответственно.
Большинство алгоритмов использует двоичные ключи. У большинства людей нет возможности помнить длинные последовательности двоичных чисел, даже когда представлено в шестнадцатеричном. Символьные пароли намного легче напомнить. Поскольку символьные пароли обычно выбираются из небольшого количества символов (например, [a-zA-Z0-9]), протоколы, такие как "Основанное на пароле Шифрование" (PBE) были определены, которые берут символьные пароли и генерируют сильные двоичные ключи. Чтобы сделать задачу из получения от пароля, чтобы манипулировать очень отнимающий много времени для атакующего (через так называемые "атаки с подбором по словарю", где общее слово словаря-> отображения значения предварительно вычисляются), большинство реализаций PBE смешается в случайном числе, известном как соль, чтобы увеличить ключевую случайность.
Более новые режимы шифра, такие как Аутентифицируемое Шифрование со Связанными Данными (AEAD) (например,
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
класс. На режимы могут сослаться их символьные имена, которые показывают ниже наряду с описанием цели каждого режима:
java.security.Key
в байты так, чтобы ключ мог быть надежно транспортирован.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
:
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
параметры использования провайдера:
javax.crypto.spec.IvParameterSpec
класс может использоваться, чтобы инициализировать объект Шифра с данным IV.javax.crypto.spec.PBEParameterSpec
класс может использоваться, чтобы инициализировать объект Шифра, реализующий PBEWithMD5AndDES с данной солью и итеративным количеством.Отметьте, что Вы не должны волноваться о хранении или передаче никаких параметров алгоритма для использования работой дешифрования, если Вы используете SealedObject
класс. Этот класс присоединяет параметры, используемые для того, чтобы изолировать (шифрование) к зашифрованному объектному содержанию, и использует те же самые параметры для того, чтобы распечатать (дешифрование).
Часть из update
и doFinal
методы Шифра позволяют вызывающей стороне определять буфер вывода, в который можно зашифровать или дешифровать данные. В этих случаях важно передать буфер, который является достаточно большим, чтобы содержать результат работы дешифрования или шифрования.
Следующий метод шифром может использоваться, чтобы определить, насколько большой буфер вывода должен быть:
public int getOutputSize(int inputLen)
Cipher
На основе КлассыCipher
s, чтобы обеспечить легкий доступ к общему использованию шифра. Этот класс является a FilterInputStream
это шифрует или дешифрует данные, проходящие через это. Это составляется из InputStream
, или один из его подклассов, и a Cipher
. CipherInputStream представляет безопасный входной поток, в который был вставлен объект Шифра. read
методы CipherInputStream возвращают данные, которые читаются из базового InputStream, но были дополнительно обработаны встроенным объектом Шифра. Объект Шифра должен быть полностью инициализирован прежде, чем быть используемым CipherInputStream.
Например, если встроенный Шифр был инициализирован для дешифрования, CipherInputStream попытается дешифровать данные, которые это читает из базового InputStream прежде, чем возвратить их приложению.
Этот класс придерживается строго семантики, особенно семантика отказа, ее классов предка java.io.FilterInputStream
и java.io.InputStream
. Этот класс имеет точно те методы, определенные в его классах предка, и переопределяет их всех, так, чтобы данные были дополнительно обработаны встроенным шифром. Кроме того этот класс ловит все исключения, которые не выдаются его классами предка. В частности skip(long)
метод пропускает только данные, которые были обработаны Шифром.
Для программиста, использующего этот класс крайне важно не использовать методы, которые не определяются или переопределяются в этом классе (таком как новый метод или конструктор, который позже добавляется к одному из классов высшего качества), потому что разработка и реализация тех методов вряд ли рассмотрит воздействие безопасности относительно 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.
Этот класс является a FilterOutputStream
это шифрует или дешифрует данные, проходящие через это. Это составляется из OutputStream
, или один из его подклассов, и a Cipher
. CipherOutputStream представляет безопасный поток вывода, в который был вставлен объект Шифра. write
методы CipherOutputStream сначала обрабатывают данные со встроенным объектом Шифра перед выписыванием их к базовому OutputStream. Объект Шифра должен быть полностью инициализирован прежде, чем быть используемым CipherOutputStream.
Например, если встроенный Шифр был инициализирован для шифрования, CipherOutputStream зашифрует свои данные перед выписыванием их к базовому потоку вывода.
Этот класс придерживается строго семантики, особенно семантика отказа, ее классов предка java.io.OutputStream
и java.io.FilterOutputStream
. Этот класс имеет точно те методы, определенные в его классах предка, и переопределяет их всех, так, чтобы все данные были дополнительно обработаны встроенным шифром. Кроме того этот класс ловит все исключения, которые не выдаются его классами предка.
Для программиста, использующего этот класс крайне важно не использовать методы, которые не определяются или переопределяются в этом классе (таком как новый метод или конструктор, который позже добавляется к одному из классов высшего качества), потому что разработка и реализация тех методов вряд ли рассмотрит воздействие безопасности относительно 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
методы этого класса, который становится еще более релевантным, если инкапсулировавший объект Шифра реализует алгоритм блочного шифра с дополнением включенного:
flush
сбрасывает базовый OutputStream, вызывая любые буферизованные выходные байты, которые были уже обработаны инкапсулировавшим объектом Шифра, который будет выписан. Любые байты, буферизованные инкапсулировавшим объектом Шифра и ожидающий, чтобы быть обработанными этим, не будут выписаны.close
закрывает базовый OutputStream и выпускает любые системные ресурсы, связанные с этим. Это вызывает doFinal
метод инкапсулировавшего объекта Шифра, вызывая любые байты, буферизованные этим быть обработанным и выписанным к базовому потоку, вызывая flush
метод.Этот класс позволяет программисту создать объект и защитить его конфиденциальность с криптографическим алгоритмом.
Учитывая любой объект, который реализует 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);
Исходный объект, который был изолирован, может быть восстановлен двумя различными способами:
Cipher
объект, который был инициализирован с тем же самым алгоритмом, ключом, дополняя схему, и т.д., которые использовались, чтобы изолировать объект: c.init(Cipher.DECRYPT_MODE, sKey); try { String s = (String)so.getObject(c); } catch (Exception e) { // do something };
У этого подхода есть преимущество, что сторона, кто распечатывает изолированный объект, не требует знания ключа расшифровки. Например, после того, как одна сторона инициализировала объект шифра с необходимым ключом расшифровки, это могло передать объект шифра к другой стороне, кто тогда распечатывает изолированный объект.
try { String s = (String)so.getObject(sKey); } catch (Exception e) { // do something };
В этом подходе, getObject
метод создает объект шифра для соответствующего алгоритма дешифрования и инициализирует его с данным ключом расшифровки и параметрами алгоритма (если любой), которые были сохранены в изолированном объекте. У этого подхода есть преимущество, что сторона, кто распечатывает объект, не должна отследить параметры (например, IV), которые использовались, чтобы изолировать объект.
Подобный a MessageDigest
, Код аутентификации сообщений (MAC) обеспечивает способ проверить целостность информации, переданной или сохраненный в ненадежном носителе, но включает секретный ключ в вычисление. Только кто-то с надлежащим ключом будет в состоянии проверить полученное сообщение. Как правило, коды аутентификации сообщений используются между двумя сторонами, которые совместно используют секретный ключ, чтобы проверить информации, переданной между этими сторонами.
Механизм MAC, который основан на криптографических хеш-функциях, упоминается как HMAC. HMAC может использоваться с любой криптографической хеш-функцией, например, MD5 или SHA 1, в комбинации с секретом совместно использованный ключ.
Mac
класс обеспечивает функциональность Кода аутентификации сообщений (MAC). Пожалуйста, обратитесь к примеру кода.
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 некоторых данных в единственном шаге, вызовите следующий 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
методы определяются в соответствующем классе спецификации.
У всех непрозрачных ключей есть три характеристики:
AES
, DSA
или RSA
), который будет работать с теми алгоритмами и со связанными алгоритмами (такой как MD5withRSA
, SHA1withRSA
, и т.д.), имя алгоритма ключа получается, используя этот метод: String getAlgorithm()
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
класс является простым держателем для пары ключей (открытый ключ и закрытый ключ). У этого есть два открытых метода, один для того, чтобы возвратить закрытый ключ, и другой для того, чтобы возвратить открытый ключ:
PrivateKey getPrivate() PublicKey getPublic()
Key
объекты и ключевые спецификации (KeySpec
s) два различных представления ключевых данных. Cipher
s использование Key
объекты инициализировать их алгоритмы шифрования, но ключи, возможно, должны быть преобразованы в более переносимый формат для передачи или хранения.
Прозрачное представление ключей означает, что можно получить доступ к каждой ключевой материальной ценности индивидуально, через один из get
методы определяются в соответствующем классе спецификации. Например, 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
классы могут использоваться, чтобы преобразовать между непрозрачными и прозрачными ключевыми представлениями (то есть, между Key
s и KeySpec
s, предполагая, что работа возможна. (Например, закрытые ключи на смарт-картах не могли бы быть в состоянии, оставляют карту. Такой Key
s не конвертируемы.)
В следующих разделах мы обсуждаем ключевые интерфейсы спецификации и классы в java.security.spec
пакет.
KeySpec
ИнтерфейсЭтот интерфейс не содержит методов или констант. Его единственная цель состоит в том, чтобы сгруппировать и обеспечить безопасность типов для всех ключевых спецификаций. Все ключевые спецификации должны реализовать этот интерфейс.
KeySpec
ПодынтерфейсыKey
интерфейс, есть подобный набор KeySpec
интерфейсы. EncodedKeySpec
КлассKeySpec
интерфейс), представляет или закрытый ключ с открытым ключом в закодированном формате. getEncoded
метод возвращает закодированный ключ: abstract byte[] getEncoded();и
getFormat
метод возвращает имя формата кодирования: abstract String getFormat();
См. следующие разделы для конкретных реализаций PKCS8EncodedKeySpec
и X509EncodedKeySpec
.
PKCS8EncodedKeySpec
КлассEncodedKeySpec
, представляет кодирование DER закрытого ключа, согласно формату, определенному в стандарте PKCS8. getEncoded
метод возвращает ключевые байты, закодированные согласно стандарту PKCS8. getFormat
метод возвращает строку "PKCS#8". X509EncodedKeySpec
КлассEncodedKeySpec
, представляет кодирование DER открытого ключа, согласно формату, определенному в стандарте X.509. getEncoded
метод возвращает ключевые байты, закодированные согласно стандарту X.509. getFormat
метод возвращает строку "X.509". Генераторы используются, чтобы генерировать совершенно новые объекты. Генераторы могут быть инициализированы или зависимым от алгоритма или независимым от алгоритма способом. Например, чтобы создать Diffie-Hellman (DH) пара ключей, приложение могло определить необходимые значения P и Г, или генератор мог просто быть инициализирован с соответствующей длиной ключа, и генератор выберет соответствующие значения P и Г. В обоих случаях генератор произведет совершенно новые ключи, основанные на параметрах.
С другой стороны фабрики используются, чтобы преобразовать данные от одного существующего объектного типа до другого. Например, приложение могло бы иметь доступный компоненты закрытого ключа DH и может упаковать их как a KeySpec
, но потребности преобразовать их в a PrivateKey
объект, который может использоваться a KeyAgreement
объект, или наоборот. Или они могли бы иметь байтовый массив сертификата, но должны использовать a CertificateFactory
преобразовать это в a X509Certificate
объект. Приложения используют объекты фабрики сделать преобразование.
KeyFactory
КлассKeyFactory
класс является классом механизма, разработанным, чтобы выполнить преобразования между криптографическим непрозрачным Key
s и ключевые спецификации (прозрачные представления базового ключевого материала).
Ключевые фабрики двунаправлены. Они позволяют Вам создавать непрозрачный ключевой объект из данной ключевой спецификации (манипулируйте материал), или получать базовый ключевой материал ключевого объекта в подходящем формате.
Многократные совместимые ключевые спецификации могут существовать для того же самого ключа. Например, открытый ключ DSA может быть определен его компонентами y
, p
, q
, и g
(см. java.security.spec.DSAPublicKeySpec
), или это может быть определено, используя его DER, кодирующий согласно стандарту X.509 (см. X509EncodedKeySpec
).
Ключевая фабрика может использоваться, чтобы преобразовать между совместимыми ключевыми спецификациями. Ключевой парсинг может быть достигнут через преобразование между совместимыми ключевыми спецификациями, например, когда Вы преобразовываете из X509EncodedKeySpec
к DSAPublicKeySpec
, Вы в основном анализируете закодированный ключ в его компоненты. Для примера см. конец Подписей Генерирования/Проверки Используя Ключевые Спецификации и KeyFactory
раздел.
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
идентифицирует класс спецификации, в котором должен быть возвращен ключевой материал. Это могло, например, быть DSAPublicKeySpec.class
, указать, что ключевой материал должен быть возвращен в экземпляре DSAPublicKeySpec
класс. Пожалуйста, см. раздел В качестве примера для большего количества деталей.
Этот класс представляет фабрику для секретных ключей. В отличие от этого KeyFactory
, a javax.crypto.SecretKeyFactory
объект работает только на секретных (симметричных) ключах, тогда как a java.security.KeyFactory
возразите обрабатывает компоненты с закрытым ключом и с открытым ключом пары ключей.
Ключевые фабрики используются, чтобы преобразовать Key
s (непрозрачные криптографические ключи типа 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
класс, который реализует javax.crypto.SecretKey
интерфейс:
byte[] desKeyData = { (byte)0x01, (byte)0x02, ...}; SecretKeySpec secretKey = new SecretKeySpec(desKeyData, "DES");
SecretKeyFactory
ОбъектSecretKeyFactory
объекты получаются при использовании одного из SecretKeyFactory
getInstance()
статические методы фабрики.
Если у Вас есть ключевая спецификация для секретного ключа, можно получить непрозрачное SecretKey
объект от спецификации при использовании generateSecret
метод:
SecretKey generateSecret(KeySpec keySpec)
Если у Вас есть a Secret Key
объект, можно получить соответствующий ключевой объект спецификации, вызывая getKeySpec
метод:
KeySpec getKeySpec(Key key, Class keySpec)
keySpec
идентифицирует класс спецификации, в котором должен быть возвращен ключевой материал. Это могло, например, быть DESKeySpec.class
, указать, что ключевой материал должен быть возвращен в экземпляре DESKeySpec
класс. KeyPairGenerator
Класс KeyPairGenerator
класс является классом механизма, используемым, чтобы генерировать пар открытых и закрытых ключей.
Есть два способа генерировать пару ключей: независимым от алгоритма способом, и специфичным для алгоритма способом. Единственной разницей между этими двумя является инициализация объекта.
Пожалуйста, см. раздел В качестве примера для примеров звонков в методы, задокументированные ниже.
KeyPairGenerator
Вся генерация пары ключей запускается с a KeyPairGenerator
. KeyPairGenerator
объекты получаются при использовании одного из KeyPairGenerator
getInstance()
статические методы фабрики.
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
объекты получаются при использовании одного из KeyGenerator
getInstance()
статические методы фабрики. Ключевой генератор для определенного алгоритма с симметричным ключом создает симметричный ключ, который может использоваться с тем алгоритмом. Это также связывает специфичные для алгоритма параметры (если любой) со сгенерированным ключом.
Есть два способа генерировать ключ: независимым от алгоритма способом, и специфичным для алгоритма способом. Единственной разницей между этими двумя является инициализация объекта:
Все ключевые генераторы совместно используют понятие размера ключа и источник случайности. Есть init
метод, который берет эти два универсально совместно используемых типа параметров. Есть также тот, который берет только a keysize
параметр, и использование обеспеченный системой источник случайности, и тот, который берет только источник случайности:
public void init(SecureRandom random); public void init(int keysize); public void init(int keysize, SecureRandom random);
Так как никакие другие параметры не определяются, когда Вы вызываете вышеупомянутое независимое от алгоритма init
методы, это до провайдера, что сделать о специфичных для алгоритма параметрах (если любой), чтобы быть связанным со сгенерированным ключом.
Для ситуаций, где ряд специфичных для алгоритма параметров уже существует, есть два init
методы, которые имеют AlgorithmParameterSpec
параметр. У каждого также есть a SecureRandom
параметр, в то время как источник случайности предусматривается на систему другой:
public void init(AlgorithmParameterSpec params); public void init(AlgorithmParameterSpec params, SecureRandom random);
В случае, если клиент явно не инициализирует KeyGenerator (через звонок init
метод), каждый провайдер должен предоставить (и документ) инициализацию по умолчанию.
public SecretKey generateKey();
Каждая сторона инициализирует их объект согласования ключей с их закрытым ключом, и затем вводит открытые ключи для каждой стороны, которая будет участвовать в передаче. В большинстве случаев есть только две стороны, но алгоритмы, такие как Diffie-Hellman учитывают многократные стороны (3 или больше), чтобы участвовать. Когда все открытые ключи были введены, каждый KeyAgreement
объект генерирует (согласуют) тот же самый ключ.
Класс KeyAgreement обеспечивает функциональность протокола согласования ключей. Ключи, включенные в установление совместно используемого секрета, создаются одним из ключевых генераторов (KeyPairGenerator
или KeyGenerator
), a KeyFactory
, или в результате от промежуточной фазы протокола согласования ключей.
Каждая сторона, включенная в согласование ключей, должна создать объект KeyAgreement. KeyAgreement
объекты получаются при использовании одного из KeyAgreement
getInstance()
статические методы фабрики.
Вы инициализируете объект 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);
Каждый протокол согласования ключей состоит из многих фаз, которые должны быть выполнены каждой стороной, включенной в согласование ключей.
Чтобы выполнить следующую фазу в согласовании ключей, вызовите 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
в корневом каталоге пользователя, как определено "user.home" системным свойством. На системах Соляриса "user.home" значения по умолчанию к корневому каталогу пользователя. На системах Win32, учитывая имя пользователя uName, "user.home" значения по умолчанию к:
В дополнение к 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. Для там возможно быть многократными различными конкретными реализациями, где каждая реализация состоит в том что для определенного типа keystore. В настоящий момент есть два инструмента командной строки, которые используют KeyStore
: keytool
и jarsigner
, и также основанный на GUI инструмент называют policytool
. Это также используется Policy
ссылочная реализация, когда это обрабатывает файлы политики, определяющие полномочия (предоставленные доступы к системным ресурсам), чтобы быть предоставленным кодировать из различных источников. С тех пор KeyStore
публично доступно, пользователи JDK могут записать дополнительные приложения безопасности, которые используют это.
Приложения могут выбрать различные типы keystore реализаций от различных провайдеров, используя getInstance
метод фабрики в KeyStore
класс. Тип 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
параметр командной строки). Sun "jceks" реализация может проанализировать и преобразовать "jks" keystore файл к формату "jceks". Можно обновить свой keystore типа "jks" к keystore типа "jceks", изменяя пароль записи с закрытым ключом в Вашем keystore и определения "-storetype jceks"
как тип keystore. Чтобы применяться криптографически сильный (er) ключевая защита, предоставленная закрытому ключу, названному "signkey" в Вашем значении по умолчанию keystore, используйте следующую команду, которая запросит Вас старые и новые ключевые пароли:
keytool -keypasswd -alias signkey -storetype jceksСм. Средства обеспечения безопасности для получения дополнительной информации о
keytool
и о keystores и как ими управляют.Реализации Keystore основаны на провайдере. Разработчики, заинтересованные в письменной форме, их собственные реализации KeyStore должны консультироваться, Как Реализовать Провайдера для Архитектуры Криптографии Java для получения дополнительной информации об этой теме.
KeyStore
КлассKeyStore
класс является классом механизма, который предоставляет четко определенные интерфейсы, чтобы получить доступ и изменить информацию в keystore.
Этот класс представляет набор в памяти ключей и сертификатов. KeyStore
управляет двумя типами записей:
Этот тип keystore записи содержит очень чувствительную информацию криптографического ключа, которая хранится в защищенном формате, чтобы предотвратить несанкционированный доступ. Как правило, ключ, сохраненный в этом типе записи, является секретным ключом, или закрытым ключом, сопровождаемым цепочкой сертификата аутентификация соответствующего открытого ключа.
Закрытые ключи и цепочки сертификата используются данным объектом для самоаутентификации, используя цифровые подписи. Например, организации распределения программного обеспечения в цифровой форме подписывают файлы JAR как часть выпуска и/или лицензирования программного обеспечения.
Этот тип записи содержит единственный сертификат с открытым ключом, принадлежащий другой стороне. Это вызывают доверяемым сертификатом, потому что keystore владелец полагает, что открытый ключ в сертификате действительно принадлежит идентификационным данным, идентифицированным предметом (владелец) сертификата.
Этот тип записи может использоваться, чтобы аутентифицировать другие стороны.
Являются ли keystores персистентными, и механизмы, используемые keystore, если это является персистентным, не определяются здесь. Это соглашение позволяет использование множества методов для того, чтобы защитить чувствительный (например, частный или секретный) ключи. Смарт-карты или другие интегрированные криптографические механизмы (SafeKeyper) являются одной опцией, и более простые механизмы, такие как файлы могут также использоваться (во множестве форматов).
Основное KeyStore
методы описываются ниже.
KeyStore
ОбъектKeyStore
объекты получаются при использовании одного из KeyStore
getInstance()
статические методы фабрики.
KeyStore
объект может использоваться, фактические keystore данные должны быть загружены в память через load
метод: final void load(InputStream stream, char[] password)Дополнительный пароль используется, чтобы проверить целостность keystore данных. Если никакой пароль не предоставляется, никакая проверка целостности не выполняется.
Чтобы создать пустой keystore, Вы передаете null
как InputStream
параметр load
метод.
Ко всем keystore записям получают доступ через уникальные псевдонимы. aliases
метод возвращает перечисление имен псевдонима в keystore:
final Enumeration aliases()
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)
getKey
метод возвращает ключ, связанный с данным псевдонимом. Ключ восстанавливается, используя данный пароль: final Key getKey(String alias, char[] password)Следующие методы возвращают сертификат, или цепочку сертификата, соответственно, связанный с данным псевдонимом:
final Certificate getCertificate(String alias) final Certificate[] getCertificateChain(String alias)Можно определить имя (
alias
) из первой записи, сертификат которой соответствует данный сертификат через следующее: final String getCertificateAlias(Certificate cert)
store
метод: final void store(OutputStream stream, char[] password)Пароль используется, чтобы вычислить контрольную сумму целостности keystore данных, которые добавляются к keystore данным.
Key
s и Keyspec
s, параметры инициализации алгоритма представляются также AlgorithmParameter
s или AlgorithmParameterSpec
s. В зависимости от ситуации с использованием алгоритмы могут использовать параметры непосредственно, или параметры, возможно, должны были бы быть преобразованы в более переносимый формат для передачи или хранения. Прозрачное представление ряда параметров (через AlgorithmParameterSpec
) средства, что можно получить доступ к каждому значению параметра в наборе индивидуально. Можно получить доступ к этим значениям через один из get
методы, определенные в соответствующем классе спецификации (например, DSAParameterSpec
определяет getP
, getQ
, и getG
методы, к доступу p
, q
, и g
, соответственно).
Напротив, AlgorithmParameters
класс предоставляет непрозрачное представление, в котором у Вас нет никакого прямого доступа к полям параметра. Можно только получить имя алгоритма, связанного с набором параметра (через getAlgorithm
) и некоторое кодирование для набора параметра (через getEncoded
).
AlgorithmParameterSpec
ИнтерфейсAlgorithmParameterSpec
интерфейс к прозрачной спецификации криптографических параметров. Этот интерфейс не содержит методов или констант. Его единственная цель состоит в том, чтобы сгруппировать (и обеспечить безопасность типов для), все спецификации параметра. Все спецификации параметра должны реализовать этот интерфейс. Интерфейсы спецификации параметра алгоритма и классы в java.security.spec
и javax.crypto.spec
пакеты описываются в JDK javadocs:
Следующие спецификации параметра алгоритма используются определенно для цифровых подписей как часть
AlgorithmParameters
КлассAlgorithmParameters
класс является классом механизма, который обеспечивает непрозрачное представление криптографических параметров. Можно инициализировать AlgorithmParameters
класс используя определенное 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
идентифицирует класс спецификации, в котором должны быть возвращены параметры. Класс спецификации мог быть, например, DSAParameterSpec.class
указать, что параметры должны быть возвращены в экземпляре DSAParameterSpec
класс. (Этот класс находится в java.security.spec
пакет.) AlgorithmParameterGenerator
КлассAlgorithmParameterGenerator
класс является классом механизма, используемым, чтобы генерировать ряд совершенно новых параметров, подходящих для определенного алгоритма (алгоритм определяется когда 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
класс является классом механизма, который определяет функциональность фабрики сертификата, которая используется, чтобы генерировать список аннулированных сертификатов и список аннулированных сертификатов (CRL) объекты от их кодировок. Фабрика сертификата для X.509 должна возвратить сертификаты, которые являются экземпляром java.security.cert.X509Certificate
, и CRL, которые являются экземпляром java.security.cert.X509CRL
.
CertificateFactory
ОбъектCertificateFactory
объекты получаются при использовании одного из getInstance()
статические методы фабрики.
generateCertificate
метод: final Certificate generateCertificate(InputStream inStream)Чтобы возвратиться (возможно пустой) представление набора сертификатов, считанных из данного входного потока, используйте
generateCertificates
метод: final Collection generateCertificates(InputStream inStream)
generateCRL
метод: final CRL generateCRL(InputStream inStream)Чтобы возвратиться (возможно пустой) представление набора CRL, считанных из данного входного потока, используйте
generateCRLs
метод: final Collection generateCRLs(InputStream inStream)
CertPath
ОбъектыРеализация хранилища сертификата для того, чтобы получить сертификаты и CRL из каталогов Collection и LDAP, используя PKIX LDAP V2 Схема также доступна от IETF как
Генерировать 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()Кодировка по умолчанию будет перечислена сначала.
Предположите, что эта реализация SSL/TLS будет сделана доступной как провайдер JSSE. Конкретная реализация Provider
класс сначала пишется, который будет в конечном счете зарегистрирован в Security
список класса провайдеров. Этот провайдер, главным образом, обеспечивает отображение от имен алгоритма до фактических классов реализации. (который является: "SSLContext. TLS"-> "com.foo. TLSImpl"), Когда приложение запрашивает экземпляр "TLS" (через SSLContext.getInstance("TLS")
, со списком провайдера консультируются для требуемого алгоритма, и соответствующий экземпляр создается.
Прежде, чем обсудить детали фактического квитирования, быстрый анализ части архитектуры JSSE необходим. Основа архитектуры JSSE SSLContext
. Контекст в конечном счете создает объекты конца (SSLSocket
и SSLEngine
) которые фактически реализуют протокол SSL/TLS. SSLContext
s инициализируются с двумя классами обратного вызова, 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, основанные на выборе комплекта. Мы будем использовать аутентификацию только для сервера в следующих примерах.
В первом примере сервер пытается использовать 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 PrivateKey
s. Сервер отправляет свои части с открытым ключом в сообщении ServerKeyExchange (защищенный алгоритмом подписи DSA, и клиент отправляет его открытый ключ в сообщении ClientKeyExchange. Когда открытые ключи повторно собираются, используя другого KeyFactory
, они питаются в объекты соглашения. KeyAgreement
объекты тогда генерируют согласованный байты, которые тогда используются, чтобы установить фактические ключи шифрования.
Как только фактические ключи шифрования были установлены, секретный ключ используется, чтобы инициализировать симметричное Cipher
объект, и этот шифр используются, чтобы защитить все данные в пути. Помочь определить, были ли данные изменены, a MessageDigest
создается и получает копию данных, предназначенных для сети. Когда пакет полон, обзор (хеш) добавляется к данным, и весь пакет шифруется Cipher
. Если блочный шифр, такой как AES используется, данные должны быть дополнены, чтобы сделать полный блок. На удаленной стороне просто инвертируются шаги.
Заголовок | Данные | Обзор | Дополнение (если любой) |
---|
Снова, это значительно simplied, но дает общее представление, один из как эти классы могли бы быть объединены, чтобы создать высокоуровневый протокол.
Платформа JCA включает возможность осуществить ограничения относительно криптографических алгоритмов и максимальных криптографических сильных мест, доступных апплетам/приложениям в различных контекстах юрисдикции (расположения). Любые такие ограничения определяются в "файлах политики юрисдикции".
Должный импортировать ограничения управления правительствами нескольких стран, файлы политики юрисдикции, поставленные с Java, Комплект разработчика 6 SE из Sun Microsystems определяет, что "сильная" но ограниченная криптография может использоваться. "Неограниченная сила" версия этих файлов, не указывающих ни на какие ограничения на криптографические сильные места, доступна для тех, которые живут в имеющих право странах (который является большинством стран). Но только "сильная" версия может быть импортирована в те страны, правительства которых передают под мандат ограничения. Платформа JCA осуществит ограничения, определенные в установленных файлах политики юрисдикции.
Возможно, что правительства некоторых или всех таких стран могут позволить определенным приложениям становиться освобожденными от некоторых или всех криптографических ограничений. Например, они могут рассмотреть определенные типы приложений как "особенные" и таким образом освободить. Или они могут освободить любое приложение, которое использует "механизм освобождения,", такие как ключевое восстановление. Приложения, которые, как считают, были освобождены, могли добраться, доступ к более сильной криптографии чем это учитывал неосвобожденные приложения в таких странах.
Для приложения, которое будет распознано как "освобожденный" во время выполнения, это должно встретить следующие условия:
Ниже демонстрационные шаги, требуемые, чтобы подать заявку, освобожденную от некоторых или всех криптографических ограничений. Это - основная схема, которая включает информацию о том, что требуется JCA, чтобы распознать и обработать приложения, как являющиеся освобожденным. Вы должны будете знать требования освобождения определенной страны или стран, в которых требуется, чтобы Ваше приложение было в состоянии быть выполненными, но чьи правительства требуют криптографических ограничений. Вы должны будете также знать требования поставщика платформы JCA, у которого есть процесс на месте для того, чтобы обработать освобожденные приложения. Консультируйтесь с таким поставщиком для дополнительной информации. (ОТМЕТЬТЕ: SunJCE
провайдер не предоставляет реализацию класса ExemptionMechanismSpi.)
Когда у приложения есть файл политики разрешения, связанный с этим (в том же самом файле 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
вызовите и запись действительно определяет, что механизм освобождения должен быть осуществлен, тогда освобожденный файл (ы) политики юрисдикции исследуется. Если освобожденные полномочия включают запись для соответствующего алгоритма и механизма освобождения, и та запись подразумевается полномочиями в файле политики разрешения, связанном приложением, и если есть реализация указанного механизма освобождения, доступного от одного из зарегистрированных провайдеров, то максимальный размер ключа и значения параметра алгоритма для Шифра определяются от освобожденной записи разрешения.
Если нет никакой освобожденной записи разрешения, подразумеваемой соответствующей записью в файле политики разрешения, связанном приложением, или если нет никакой реализации указанного механизма освобождения, доступного ни от одного из зарегистрированных провайдеров, то приложению только позволяют стандартные криптографические полномочия по умолчанию.
MessageDigest
ОбъектСначала создайте объект обзора сообщения, как в следующем примере:
MessageDigest sha = MessageDigest.getInstance("SHA-1");Этот вызов присваивает должным образом инициализированный объект обзора сообщения
sha
переменная. Реализация реализует Безопасный Хеш-алгоритм (SHA 1), как определено в Национальном Институте Стандартов и Технология (NIST) Затем, предположите, что у нас есть три байтовых массива, 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
вызовы), теряется. Некоторые реализации хеша могут поддерживать промежуточные хеши посредством клонирования. Предположите, что мы хотим вычислить отдельные хеши для:
i1
i1 and i2
i1, i2, and i3
Способ сделать это:
/* 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
методы инициализации класса в минимуме нуждаются в размере ключа. Если источник случайности явно не обеспечивается, 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
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();Предположите, что Элис хочет использовать данные, которые Вы подписали. Для нее, чтобы сделать так, и проверить Вашу подпись, Вы должны отправить ей три вещи:
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
класс (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-закодированными сертификатами, которые каждый ограничиваются вначале
-----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
методы фабрики класса Шифра. Мы должны определить имя требуемого преобразования, которое включает следующие компоненты, разделенные наклонными чертами (/):
В этом примере мы создаем шифр 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
класс берет (и возвраты) пароль как массив случайной работы. См. класс ReadPassword в примере кода в Приложении 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 сторонами.
API Безопасности JDK требует и использует ряд стандартных имен для алгоритмов, сертификата и типов keystore. Спецификация называет ранее найденным здесь в Приложении A и в других спецификациях безопасности (JSSE/CertPath/etc). были объединены в документе Стандартных имен. Этот документ также содержит больше информации о спецификациях алгоритма. Определенная информация о провайдере может быть найдена в Документации Провайдера солнца.
Криптографические реализации на солнце JDK распределяются через несколько различных провайдеров прежде всего по историческим причинам (Sun
, SunJSSE
, SunJCE
, SunRsaSign
). Отметьте, что эти провайдеры, возможно, не доступны на всех реализациях JDK, и поэтому, действительно переносимые приложения должны вызвать getInstance()
не определяя определенных провайдеров. Приложения, определяющие определенного провайдера, возможно, не в состоянии использовать в своих интересах собственных провайдеров, настроенных для базовой операционной среды (таких как PKCS или CAPI Microsoft).
SunPKCS11
сам провайдер не содержит криптографических алгоритмов, но вместо этого, направляет запросы в базовую реализацию PKCS11. Со Справочником PKCS11 и базовой реализацией PKCS11 нужно консультироваться, чтобы определить, будет ли требуемый алгоритм доступен через провайдера PKCS11. Аналогично, на системах Windows, SunMSCAPI
провайдер не обеспечивает криптографической функциональности, но вместо этого направляет запросы к базовой Операционной системе для того, чтобы обработать.
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>
в шаблоне выше фактически было бы определенное имя класса полномочий, такой как javax.crypto.CryptoPermission
. crypto класс полномочий отражает возможность приложения/апплета использовать определенные алгоритмы с определенными размерами ключа в определенных средах. Есть два crypto класса полномочий: CryptoPermission
и CryptoAllPermission
. Специальное предложение CryptoAllPermission
класс подразумевает все связанные с криптографией полномочия, то есть, он определяет, что нет никаких связанных с криптографией ограничений.
<alg_name>, когда использующийся, заключенная в кавычки строка, определяющая стандартное имя (см. Приложение A) алгоритма криптографии, такого как "DES" или "RSA".
<Имя механизма освобождения>, когда определено, является заключенной в кавычки строкой, указывающей на механизм освобождения, который, если осуществлено, включает сокращению криптографических ограничений. Имена механизма освобождения, которые могут использоваться, включают "KeyRecovery" "KeyEscrow", и "KeyWeakening".
<maxKeySize> является целым числом, определяющим, что максимальный размер ключа (в битах) учитывал указанный алгоритм.
Для некоторых алгоритмов, возможно, не достаточно определить стойкость алгоритма с точки зрения только размера ключа. Например, в случае алгоритма "RC5", число раундов нужно также рассмотреть. Для алгоритмов, сила которых должна быть выражена как больше чем размер ключа, запись разрешения должна также определить имя класса AlgorithmParameterSpec (такой как javax.crypto.spec.RC5ParameterSpec
) и список параметров для того, чтобы создать указанный объект AlgorithmParameterSpec.
Элементы, которые появляются в записи разрешения, должны появиться в указанном порядке. Запись завершается с точкой с запятой.
Случай незначителен для идентификаторов (grant
, permission
) но является существенным для <crypto permission class name>
или для любой строки, в которой передают как значение.
ОТМЕТЬТЕ: "*" может использоваться в качестве подстановочного знака для любой опции записи разрешения. Например, "*" (без кавычек) для <alg_name> опции означает "все алгоритмы."
Должный импортировать ограничения управления, файлы политики юрисдикции, поставленные с Java Комплект разработчика SE, позволяют "сильной" но ограниченной криптографии использоваться. Для большего количества информации, пожалуйста, см. Пределы Импорта на Криптографических алгоритмах.
/* * 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); }
/* * 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()); } }
/* * 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()); } }
/* * @(#)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, ' '); } } } }