Руководство программиста КриптоПро JCP

127018, Москва, ул.Сущевский Вал д.18
Тел./факс:
+7 (495) 780 4820
+7 (495) 660 2330
сайт: http://www.cryptopro.ru
e-mail: info@cryptopro.ru

Средство Криптографической Защиты Информации | КриптоПро JCP Версия

Руководство программиста ЖТЯИ.00088-01 33 01

© OOO "Крипто-Про", 2005-2013. Все права защищены.

Авторские права на средство криптографической защиты информации КриптоПро JCP и эксплуатационную документацию зарегистрированы в Российском агентстве по патентам и товарным знакам (Роспатент).

Документ входит в комплект поставки программного обеспечения КриптоПро JCP, и на него распространяются все условия лицензионного соглашения. Без специального письменного разрешения OOO "Крипто-Про" документ или его часть в электронном или печатном виде не могут быть скопированы и переданы третьим лицам с коммерческой целью.

Java Cryptography Architecture

Описание стандартного интерфейса JCA.

Руководство администратора безопасности

Общее описание средства криптографической защиты информации (СКЗИ) КриптоПро JCP

Обратная связь

Связь с разработчиком.
Поддержка.
Форум.

# Содержание

1. Введение
2. Использование основной функциональности криптопровайдера КриптоПро JCP через стандартный интерфейс JCA

- Генерация ключевой пары ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001

- Создание объекта генерации ключевой пары ЭП (генератора)
- Определение параметров генерации ключевой пары ЭП
- Создание ключевой пары ЭП

- Работа с ключевыми носителями

- Запись ключей ЭП с алгоритмом ГОСТ Р 34.10-2001 на ключевые носители

- Определение типа используемого ключевого носителя
- Загрузка содержимого ключевого носителя
- Запись ключа ЭП на носитель
- Сохранение содержимого ключевого носителя

- Чтение ключей ЭП с алгоритмом ГОСТ Р 34.10-2001 с ключевых носителей
- Запись сертификата ключа проверки ЭП на ключевой носитель в соответствии с хранящемся на нем ключом ЭП
- Чтение сертификата ключа проверки ЭП с ключевого носителя
- Удаление ключа ЭП с ключевого носителя
- Изменение путей к хранилищам "FloppyStore" и "HDImageStore"

- Работа с хранилищем доверенных сертификатов

- Запись сертификатов в хранилище доверенных сертификатов

- Инициализация хранилища доверенных сертификатов
- Загрузка содержимого хранилища
- Запись сертификата в хранилище
- Сохранение содержимого хранилища

- Чтение сертификатов из хранилища доверенных сертификатов

- Генерация случайных чисел

- Создание генератора случайных чисел
- Использование генератора случайных чисел
- Доинициализация датчика
- Возможные ошибки датчика
- Биодатчик

- Хеширование данных в соответствии с алгоритмом ГОСТ Р 34.11-94

- Создание объекта хеширования данных
- Определение параметров хеширования данных
- Копирование объекта хеширования данных
- Вычисление хеша данных в соответствии с алгоритмом ГОСТ Р 34.11-94

- Обработка хешируемых данных
- Завершение операции хеширования

- Формирование электронной подписи в соответствии с алгоритмом ГОСТ Р 34.10-2001

- Создание объекта формирования ЭП
- Инициализация объекта формирования ЭП
- Определение параметров формирования ЭП
- Формирование электронной подписи

- Обработка подписываемых данных
- Вычисление значения ЭП

- Проверка электронной подписи в соответствии с алгоритмом ГОСТ Р 34.10-2001

- Создание объекта проверки ЭП
- Инициализация объекта проверки ЭП
- Определение параметров проверки ЭП
- Проверка электронной подписи

- Обработка подписанных данных
- Проверка ЭП

- Работа с сертификатами через стандартный интерфейс JCA

- Генерация X509-сертификатов
- Кодирование сертификата в DER-кодировку
- Получение ключа проверки ЭП из сертификата
- Создание и проверка цепочек сертификатов

- Совместимость с КриптоПро УЦ при проверке цепочки сертификатов
- Проверка цепочек сертификатов с использованием OCSP

- Работа с временным хранилищем ключей и сертификатов

3. Работа с параметрами в криптопровайдере КриптоПро JCP

- Работа с набором параметров для генерация ключей ЭП
- Работа с параметрами алгоритма подписи ГОСТ Р 34.10-2001
- Работа с параметрами алгоритма хеширования ГОСТ Р 34.11-94
- Работа с параметрами алгоритма шифрования ГОСТ 28147-89

4. Дополнительные возможности работы с сертификатами

- Инициализация генератора запросов и сертификатов
- Генерация запроса на сертификат

- Определение параметров ключа проверки ЭП субъекта
- Определение имени субъекта
- Печать подписанного запроса

- Отправка запроса центру сертификации и получение соответствующего запросу сертификата от центра

- Получение сертификата непосредственно после генерации запроса
- Получение сертификата из запроса, представленного в DER-кодировке
- Получение сертификата из запроса, представленного в BASE64-кодировке
- Получение корневого сертификата центра сертификации

- Генерация самоподписанного сертификата

5. Работа с электронной подписью для XML-документов
6. КриптоПро JCP и Cryptographic Message Syntax(CMS)

- Особенности встречной работы при использовании CAPICOM и Java Script

7. Использование утилиты keytool

- Просмотр содержимого ключевого носителя и соответствующего ему хранилища доверенных сертификатов
- Генерация ключа и соответствующего ему самоподписанного сертификата и запись их на носитель
- Генерация запроса на сертификат ключа проверки ЭП в соответствии с хранящимся на носителе ключом ЭП и запись запроса в файл
- Генерация самоподписанного сертификата ключа проверки ЭП в соответствии с хранящимся на носителе ключом ЭП и запись сертификата на носитель
- Чтение сертификата ключа проверки ЭП с носителя и запись его в файл
- Чтение сертификата ключа проверки ЭП из файла и запись его на носитель в соответствии с хранящимся на носителе ключом ЭП
- Чтение доверенного сертификата из хранилища и запись его в файл
- Чтение доверенного сертификата из файла и запись его в хранилище
- Удаление ключа и соответствующего ему самоподписанного сертификата с носителя
- Удаление доверенного сертификата из хранилища

8. Использование утилиты ComLine

- Проверка установки и настроек провайдеров.
- Проверка работоспособности провайдеров.
- Работа с ключами и сертификатами

- Генерация ключевой пары и соответствующего ей самоподписанного сертификата. Запись их на носитель. Генерация запроса на сертификат и запись его в файл.
- Получение сертификата из запроса. Запись сертификата в хранилище и в файл.
- Построение цепочки сертификатов.
- Формирование электронной подписи.
- Проверка электронной подписи.

- Использование КриптоПро JTLS

- Запуск сервера из командной строки.
- Запуск клиента из командной строки.

9. Криптопровайдер JCSP. Особенности

- Генерация ключевой пары ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001

- Создание объекта генерации ключевой пары ЭП (генератора)
- Определение параметров генерации ключевой пары ЭП

- Работа с ключевыми носителями

- Определение типа используемого ключевого носителя
- Запись ключа ЭП на носитель

- Работа с хранилищем доверенных сертификатов
- Чтение ключей ЭП с алгоритмом ГОСТ Р 34.10-2001 с ключевых носителей
- Дополнительные возможности работы с сертификатами

- Запись сертификата ключа проверки ЭП на ключевой носитель в соответствии с хранящемся на нем ключом ЭП
- Инициализация генератора запросов и сертификатов

- Использование утилиты ComLine
- Особенности использования с другими модулями

# Введение

Настоящее руководство содержит описание основной функциональности криптопровайдера КриптоПро JCP и примеры его использования (основной класс провайдера ru.CryptoPro.JCP.JCP).

Криптопровайдер КриптоПро JCP является средством криптографической защиты информации (СКЗИ КриптоПро JCP ), реализующим российские криптографические алгоритмы и функционирующим под управлением виртуальной машины Java 2 Runtime Environment версии 1.4.2 и выше, соответствующей спецификации Sun Java 2 TM Virtual Machine.

Криптопровайдер КриптоПро JCP должен использоваться с сертифицированными SUN Java-машинами, соответствующим требованиям безопасности SUN. Защищенность криптографических объектов, создаваемых и обрабатываемых криптопровайдером, зависит от степени защищенности и корректности Java-машины, и может быть снижена при использовании виртуальных машин, не имеющих сертификата SUN. Список сертифицированных Java-машин находится на сайте SUN по адресу: http://java.sun.com/j2se/licensees/index.html

Криптопровайдер КриптоПро JCP реализует стандартный интерфейс Java Cryptography Architecture (JCA) в соответствии с российскими криптографическими алгоритмами и в соответствии с этим интерфейсом обеспечивает выполнение следующих операций:

- генерация ключей ЭП (256 бит) и ключей проверки ЭП (512 бит) в соответствии с алгоритмом ГОСТ Р 34.10-2001;
- запись ключей ЭП с алгоритмом ГОСТ Р 34.10-2001 на носители (интерфейс хранилища ключей JCA);
- чтение ключей ЭП с алгоритмом ГОСТ Р 34.10-2001 с перечисленных носителей (интерфейс хранилища ключей JCA);
- запись сертификата ключа проверки ЭП на ключевой носитель в соответствии с хранящимся на носителе
- ключом ЭП (интерфейс хранилища ключей JCA);
- чтение сертификатов ключей проверки ЭП с ключевых носителей (интерфейс хранилища ключей JCA);
- запись доверенных корневых сертификатов в стандартное хранилище JCA и чтение из него;
- генерация ключей с различными параметрами в соответствии с ГОСТ Р 34.10-2001;
- хеширование данных с различными параметрами в соответствии с ГОСТ Р 34.11-94;
- формирование электронной подписи с различными параметрами в соответствии с ГОСТ Р 34.10-2001;
- проверка электронной подписи с различными параметрами в соответствии с ГОСТ Р 34.10-2001.

Помимо перечисленных операций, осуществляемых в соответствии со стандартным интерфейсом JCA, криптопровайдер КриптоПро JCP предоставляет дополнительные возможности работы с сертификатами:

- генерация запроса на сертификат;
- отправка запроса серверу и получение от сервера соответствующего запросу сертификата;
- генерация самоподписанных сертификатов.

Основные технические данные и характеристики СКЗИ, а также информацию о совместимости с другими продуктами КриптоПро см. в Руководстве администратора безопасности

# Использование основной функциональности криптопровайдера КриптоПро JCP через стандартный интерфейс JCA

## Генерация ключевой пары ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001

Криптопровайдер КриптоПро JCP осуществляет генерация ключевой пары ЭП, соответствующей алгоритму ГОСТ Р 34.10-2001, через стандартный интерфейс JCA при помощи класса KeyPairGenerator. Генерация ключей любого другого алгоритма при помощи криптопровайдера КриптоПро JCP запрещается.

### Создание объекта генерации ключевой пары ЭП (генератора)

Объект генерации ключевой пары ЭП (далее генератор) создается посредством вызова метода getInstance() класса KeyPairGenerator. Этот метод является статическим и возвращает ссылку на класс KeyPairGenerator, который обеспечивает выполнение требуемой операции.

Для создания генератора ключевой пары ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001 методу getInstance() необходимо в качестве параметра передать имя, идентифицирующее данный алгоритм ("GOST3410" или JCP.GOST_DEGREE_NAME). При таком вызове метода getInstance() совместно с определением требуемого алгоритма генерации ключевой пары осуществляется также определение требуемого типа криптопровайдера (КриптоПро JCP). Также стандартный интерфейс JCA позволяет в качестве параметра функции getInstance() класса KeyPairGenerator вместе с именем алгоритма передавать имя криптопровайдера, используемого для выполнения требуемой операции. Таким образом, создание генератора ключевой пары ЭП осуществляется одним из следующих способов:

         KeyPairGenerator kg = KeyPairGenerator.getInstance("GOST3410");

         KeyPairGenerator kg = KeyPairGenerator.getInstance("GOST3410", "JCP");

         KeyPairGenerator kg = KeyPairGenerator.getInstance(JCP.GOST_DEGREE_NAME, JCP.PROVIDER_NAME);

Генерация ключевых пар ЭП при помощи такого генератора `kg` будет осуществляться в соответствии с алгоритмом ГОСТ Р 34.10-2001 и с установленными в контрольной панели параметрами (параметрами по умолчанию). Если существует необходимость использования другого набора параметров (отличного от параметров по умолчанию), то следует установить требуемый набор параметров созданному генератору. Следует помнить, что допустимым набором устанавливаемых параметров для генерации ключевой пары ЭП является набор, у которого параметры подписи соответствуют алгоритму ГОСТ Р 34.10-2001.

### Определение параметров генерации ключевой пары ЭП

После того, как генератор ключевой пары был создан, может возникнуть необходимость установить некий набор параметров генерации ключевой пары ЭП, отличный от параметров, установленных в контрольной панели. Операция изменения существующего набора параметров допустима только в том случае, если параметры подписи устанавливаемого набора параметров соответствуют алгоритму ГОСТ Р 34.10-2001, и осуществляется при помощи метода initialize() класса KeyPairGenerator. Этому методу в качестве параметра передается объект `AlgIdInterface`, представляющий собой интерфейс набора устанавливаемых параметров (создание объектов такого типа описывается ниже). Тогда изменение набора параметров генератора ключевой пары производится следующим образом:

         AlgIdInterface keyParams; // интерфейс набора параметров ключа

         kg.initialize(keyParams); // установка параметров, определенных интерфейсом keyParams

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

Стандартный интерфейс JCA допускает вызовы метода initialize() класса KeyPairGenerator и с другими параметрами (например, длина ключа), но при использовании криптопровайдера КриптоПро JCP такие вызовы не имеют смысла, поскольку они не изменяют набора параметров, установленного ранее генератору.

### Создание ключевой пары ЭП

Генерация ключевой пары ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001 осуществляется только после создания генератора и, если это необходимо, определения его параметров. Вызов метода generateKeyPair() класса KeyPairGenerator возвращает новую ключевую пару ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001 и установленным набором параметров (или с параметрами по умолчанию):

         KeyPair pair = kg.generateKeyPair();

Пример генерации ключевой пары см. samples/samples_src.jar/userSamples/KeyPairGen.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

## Работа с ключевыми носителями

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

Поскольку генерация ключей ЭП и ключей проверки ЭП разрешено только для алгоритма ГОСТ Р 34.10-2001, то и запись ключей ЭП на ключевые носители разрешена только для ключей этого алгоритма. Чтение ключей ЭП с носителей допустимо для ключей, соответствующих алгоритму ГОСТ Р 34.10-2001. Запись и чтение сертификатов ключей проверки ЭП допустимы для обоих алгоритмов и удовлетворяет следующим правилам:

- для каждого ключа ЭП, хранящегося на ключевом носителе, допустимо хранение одного соответствующего ключу сертификата на этом носителе;
- если на ключевом носителе уже имеется сертификат, соответствующий ключу ЭП, то при записи нового сертификата существующий сертификат уничтожается;
- если записываемый сертификат не соответствует ни одному из ключей ЭП, хранящихся на носителе, то сертификат записывается в хранилище доверенных сертификатов.

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

### Запись ключей ЭП с алгоритмом ГОСТ Р 34.10-2001 на ключевые носители

После того, как ключ ЭП, соответствующий алгоритму ГОСТ Р 34.10-2001, был создан, криптопровайдер КриптоПро JCP позволяет записать его на один из перечисленных ключевых носителей. Также как и генерация, сохранение на ключевые носители разрешается только для ключей ЭП, соответствующих алгоритму ГОСТ Р 34.10-2001.

Осуществление операций с ключевыми носителями (в том числе и запись ключа ЭП) производится через стандартный интерфейс хранилища ключей ЭП JCA (интерфейс класса KeyStore) посредством выполнения следующих действий:

#### Определение типа используемого ключевого носителя

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

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

- имя "HDImageStore" определяет жесткий диск;
- имя "FloppyStore" определяет дискету;
- имена "OCFStore", "J6CFStore" определяют карточки.

При таком вызове метода getInstance() совместно с определением требуемого типа ключевого носителя осуществляется также определение требуемого типа криптопровайдера (КриптоПро JCP). Также стандартный интерфейс JCA позволяет в качестве параметра функции getInstance() класса KeyStore вместе с типом носителя указывать имя криптопровайдера, используемого для выполнения требуемой операции. Таким образом, определение типа используемого ключевого носителя осуществляется одним из следующих способов:

         KeyStore ks = KeyStore.getInstance("HDImageStore");

         KeyStore ks = KeyStore.getInstance("HDImageStore", "JCP");

         KeyStore ks = KeyStore.getInstance("FloppyStore");

         KeyStore ks = KeyStore.getInstance("FloppyStore", "JCP");

         KeyStore ks = KeyStore.getInstance("OCFStore");

         KeyStore ks = KeyStore.getInstance("OCFStore", "JCP");

         KeyStore ks = KeyStore.getInstance("J6CFStore");

         KeyStore ks = KeyStore.getInstance("J6CFStore", "JCP");

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

#### Загрузка содержимого ключевого носителя

Согласно интерфейсу стандартного ключевого хранилища JCA перед началом выполнения каких либо операций требуется загрузка всего содержимого хранилища, следовательно, перед выполнением операций с ключевым носителем следует загрузить его содержимое. Загрузка содержимого стандартного хранилища JCA осуществляется посредством вызова метода load() класса KeyStore. Согласно интерфейсу JCA функции load() следует передавать два параметра: поток, из которого осуществляется чтение содержимого ключевого хранилища, и пароль на хранилище.

Поскольку работа с ключевыми носителями (чтение/запись ключей ЭП и соответствующих им сертификатов) и с хранилищем сертификатов (чтение/запись доверенных сертификатов) в криптопровайдере КриптоПро JCP реализована согласно общему интерфейсу JCA класса KeyStore, то в некоторых случаях вызов функции load() осуществляет как загрузку содержимого ключевого носителя, так и содержимого хранилища сертификатов, проинициализированного именем данного носителя. Ввиду этого возникают особенности использования параметров функции load():

- Первый параметр (входной поток из которого осуществляется загрузка содержимого хранилища) используется криптопровайдером КриптоПро JCP только в случае работы с хранилищем сертификатов. Поэтому, при осуществлении операции записи на ключевой носитель или чтения с него в качестве данного параметра, можно указывать `null`. Если проинициализированное именем носителя стандартное хранилище KeyStore используется как для работы с данным ключевым носителем, так и для работы с хранилищем сертификатов, то в качестве данного параметра следует указывать поток содержимого хранилища сертификатов. Тогда загруженное содержимое потока будет использоваться только при работе с хранилищем сертификатов, а при работе с носителями будет игнорироваться. Если проинициализированного именем данного носителя хранилища сертификатов на момент вызова функции load() не существует, то в качестве этого параметра следует указывать `null`.
- Второй параметр является паролем на хранилище сертификатов, которое было проинициализировано именем данного носителя. При операциях с ключевыми носителями этот параметр фактически не используется, но ввиду общего интерфейса для носителей и хранилища сертификатов, при любых операциях с ключевым носителем пароль следует указывать. Если на момент вызова метода load() не существует хранилища сертификатов, проинициализированного именем данного носителя, то в качестве этого параметра следует указывать `null`.

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

         ks.load(null, null);    // не существует хранилища сертификатов,

                                 // проинициализированного именем данного

                                 // ключевого носителя

         char[] passwd;

         ks.load(null, passwd);  // хранилище сертификатов существует,

                                 // на него установлен пароль passwd,

                                 // но последующие операции будут производиться

                                 // только с носителем

         InputStream stream;

         ks.load(stream, passwd);// хранилище сертификатов существует,

                                 // на него установлен пароль passwd,

                                 // последующие операции будут производиться

                                 // как с носителем, так и с хранилищем

                                 // сертификатов. Содержимое хранилища

                                 // записано в stream.

#### Запись ключа ЭП на носитель

После того, как содержимое носителя (и, если это требуется, содержимое проинициализированного именем носителя хранилища сертификатов) было загружено, осуществляется собственно запись ключа ЭП на носитель. Данная операция реализуется при помощи вызова метода setKeyEntry() класса KeyStore. Согласно стандартному интерфейсу JCA существует два способа вызова данного метода с различными наборами параметров. Криптопровайдер КриптоПро JCP допускает только один набор параметров:

        String alias;       // идентификатор (уникальное имя) ключа и

                            // соответствующего ему сертификата

                            // ключа проверки ЭП

        PrivateKey key;     // ключ ЭП

        char[] password;    // пароль на ключ (в общем случае отличается

                            // от пароля на хранилище, используемого при загрузке)

        Certificate[] chain;// цепочка сертификатов, начиная с корневого и

                            // и заканчивая сертификатом ключа ЭП,

                            // соответствующего ключу ЭП

        ks.setKeyEntry(alias, key, password, chain);

Следует отметить некоторые особенности вызова функции setKeyEntry():

- параметр `alias` является уникальным именем записываемого ключа ЭП и соответствующей ему цепочки сертификатов. Если на носителе уже существует ключ ЭП и, возможно, соответствующая ему цепочка сертификатов, то при попытке записи на этот носитель нового ключа с тем же самым `alias` произойдет полное очищение области носителя, относящейся к существующему ключу, и на ее место запишется новый ключ и новая цепочка. Кроме того, если в хранилище доверенных сертификатов содержится сертификат с заданным `alias`, то этот сертификат будет удален из хранилища доверенных сертификатов;
- как отмечалось выше, ключ ЭП `key` должен соответствовать типу ГОСТ Р 34.10-2001. Запись ключа любого другого алгоритма запрещается;
- в общем случае в качестве пароля `password` может выступать любой символьный массив, допустимо также отсутствие пароля, т.е. `null`. Таким образом, этот пароль является исключительно паролем на записываемый ключ и не имеет ничего общего с паролем на носитель (если таковой имеется, см. выше). Особенность использования данного параметра возникает лишь в случае использования карточки в качестве носителя (при инициализации ключевого хранилища JCA именем "OCFStore" или "J6CFStore"). В этом случае пароль на хранимый на носителе ключ должен совпадать с паролем доступа к контейнеру. Этот пароль в свою очередь не обязан совпадать с паролем доступа к хранилищу (к носителю), необходимым при загрузке носителя;
- в качестве параметра `chain` выступает цепочка сертификатов, состоящая либо из единственного сертификата, ключ проверки электронной подписи которого соответствует записываемому ключу ЭП, либо из собственно цепочки сертификатов, в которой сертификат соответствующий ключу находится в нулевом элементе массива. Сертификатом, соответсвующим ключу, может быть как самоподписанный сертификат, так и сертификат, заверенный доверенным центром сертификации. Если при этом передаваемый сертификат не соответствует ключу ЭП `key`, то метод setKeyEntry() вызовет исключение.

#### Сохранение содержимого ключевого носителя

Согласно стандартному интерфейсу класса KeyStore после любой операции, изменяющей содержимое стандартного хранилища JCA, его следует перезаписать. Операция сохранения осуществляется вызовом функции store() класса KeyStore. Если изменения касались только содержимого ключевого носителя, то вызов данной функции не является обязательным (записываемые ключи ЭП сохраняются на носителе автоматически, однако в этом случае также можно воспользоваться функцией store(null, null)). Если же изменения касались содержимого хранилища сертификатов, проинициализированного именем данного носителя, то функцию store() следует вызывать с двумя параметрами: выходной поток, в который записывается новое содержимое хранилища сертификатов и пароль на это хранилище (этот пароль в последствии будет использоваться для доступа к носителю, именем которого проинициализировано хранилище сертификатов, а также для доступа к самому хранилищу). Передаваемый в качестве параметра пароль на это хранилище не должен быть `null`.

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

        OutputStream stream;    // поток, в который записывается

                                // измененное содержимое хранилища

        char[] password;        // пароль для последующего доступа

                                // к данному хранилищу

        ks.store(stream, password);

Пример записи ключа ЭП на носитель см. samples/samples_src.jar/userSamples/KeyPairGen.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

### Чтение ключей ЭП с алгоритмом ГОСТ Р 34.10-2001 с ключевых носителей

Чтение ключей ЭП производится через стандартный интерфейс хранилища ключей ЭП JCA (через интерфейс класса KeyStore) посредством выполнения следующих действий:

- определение типа используемого ключевого носителя;
- загрузка содержимого ключевого носителя;
- чтение ключа ЭП с носителя;
- сохранение содержимого ключевого носителя.

После того, как содержимое носителя (и, если это требуется, содержимое проинициализированного именем носителя хранилища сертификатов) было загружено, осуществляется собственно чтение ключа ЭП с носителя. Данная операция реализуется при помощи вызова метода getKey() класса KeyStore, возвращающего требуемый ключ ЭП, следующим образом:

        String alias;   // идентификатор (уникальное имя) получаемого ключа ЭП,

                        // установленный при записи ключа на носитель

        char[] password;// пароль на ключ, установленный при записи ключа на носитель

        PrivateKey key = (PrivateKey)ks.getKey(alias, password);

Следует отметить некоторые особенности вызова функции getKey():

- параметр `alias` является уникальным именем получаемого ключа ЭП, которое было установлено при записи ключа на носитель. Если на заданном носителе не существует ключа ЭП с передаваемым именем `alias`, то вызов getKey() вернет `null`;
- параметр `password` представляет собой пароль на запрашиваемый ключ ЭП, который был установлен при записи этого ключа в контейнер. Как отмечалось выше, для карточек (при инициализации ключевого хранилища JCA именем "OCFStore" или "J6CFStore") пароли на все ключи, хранимые на карточке, совпадают с паролем, прошитым в карточке при ее создании.

### Запись сертификата ключа проверки электронной подписи на ключевой носитель в соответствии с хранящемся на нем ключом ЭП

Криптопровайдер КриптоПро JCP позволяет осуществлять запись на ключевые носители сертификатов ключей ЭП, соответствующих хранящимся на носителе ключам ЭП. Таким образом, операция записи сертификатов ключей ЭП допустима для ключей, соответствующих алгоритму ГОСТ Р 34.10-2001, и приводит к следующим результатам:

- добавление сертификата на ключевой носитель в соответствии с хранящимся на носителе ключом ЭП, если ранее на носителе не было такого сертификата;

· перезапись существующего на носителе сертификата ключа проверки ЭП, соответствующего ключу ЭП, новым сертификатом.

При этом осуществляется проверка соответствия ключа проверки ЭП записываемого сертификата ключу электронной подписи.

Операция записи сертификата ключа проверки ЭП подписи производится через стандартный интерфейс хранилища ключей ЭП JCA (через интерфейс класса KeyStore) посредством выполнения следующих действий:

- определение типа используемого ключевого носителя;
- загрузка содержимого ключевого носителя;
- запись сертификата ключа проверки ЭП на носитель;
- сохранение содержимого ключевого носителя.

После того, как содержимое носителя (и, если это требуется, содержимое проинициализированного именем носителя хранилища сертификатов) было загружено, осуществляется собственно запись сертификата ключа проверки ЭП на носитель. Данная операция реализуется при помощи вызова метода setCertificateEntry() класса KeyStore следующим образом:

        String alias;        // идентификатор (уникальное имя) ключа ЭП,

                             // которому соответствует ключ проверки ЭП сертификата

        Certificate cert;    // записываемый сертификат

        ks.setCertificateEntry(alias, cert);

Следует отметить некоторые особенности вызова функции setCertificateEntry():

- параметр `alias` является уникальным именем ключа ЭП, которому соответствует ключ проверки ЭП записываемого сертификата. Если ключу с заданным именем `alias` уже соответствует некоторый сертификат на носителе, то этот сертификат будет перезаписан новым. В противном случае передаваемый сертификат будет просто добавлен на носитель. При этом после записи сертификату будет присвоено имя соответствующего ему ключа ЭП - передаваемый методу setCertificateEntry() в качестве параметра `alias`. Если же на носителе не существует ключа ЭП с заданным `alias`, то передаваемый сертификат будет добавлен в хранилище доверенных сертификатов;
- параметр `cert` представляет собой записываемый на носитель сертификат. Ключ проверки ЭП этого сертификата должен соответствовать ключу ЭП с именем `alias`, если он существует, в противном случае метод setCertificateEntry() сгенерирует исключение.

### Чтение сертификата ключа проверки ЭП с ключевого носителя

Криптопровайдер КриптоПро JCP позволяет осуществлять чтение с ключевых носителей сертификатов ключей проверки ЭП, соответствующих алгоритму ГОСТ Р 34.10-2001 через стандартный интерфейс хранилища ключей ЭП JCA (интерфейс класса KeyStore) посредством выполнения следующих действий:

- определение типа используемого ключевого носителя;
- загрузка содержимого ключевого носителя;
- чтение сертификата ключа ЭП с носителя;
- сохранение содержимого ключевого носителя.

После того, как содержимое носителя (и, если это требуется, содержимое проинициализированного именем носителя хранилища сертификатов) было загружено, осуществляется собственно чтение сертификата ключа проверки ЭП с носителя. Данная операция реализуется при помощи вызова метода getCertificate() класса KeyStore, возвращающего запрашиваемый сертификат, следующим образом:

        String alias;    // идентификатор (уникальное имя) сертификата,

                         // установленный при записи сертификата на носитель

        Certificate cert = ks.getCertificate(alias);

Следует отметить некоторые особенности вызова функции getCertificate() с передаваемым параметром `alias`, являющимся уникальным именем запрашиваемого сертификата:

- если на носителе существует сертификат с заданным именем `alias`, то метод getCertificate() вернет сертификат с носителя;
- если на носителе не существует сертификата с именем `alias`, но в хранилище сертификатов есть сертификат с таким именем, то метод getCertificate() вернет сертификат из хранилища сертификатов;
- если сертификата с заданным именем `alias` не существует ни на носителе, ни в хранилище сертификатов, то метод getCertificate() вернет `null`.

### Удаление секретного ключа с ключевого носителя

Удаление секретного ключа с ключевого носителя осуществляется вызовом функции deleteEntry с передаваемым параметром `alias`, являющимся уникальным именем ключа. Для носителей требующих пароля для удаления контейнера (например, смарт-карт Оскар), в качестве имени ключа необходимо передать строку, состоящую из имени ключа, 4 символов двоеточия ("::::") и пароля доступа к ключу.

### Изменение путей к хранилищам "FloppyStore" и "HDImageStore"

Изменить пути к хранилищам "FloppyStore" и "HDImageStore" можно из контрольной панели КриптоПро JCP или программно:

        //Установка нового пути

        FloppyStore.setDir(String pathFloppy)

        HDImageStore.setDir(String pathHD)

        //Получение текущего пути

        String dirFloppy = FloppyStore.getDir()

        String dirHD = HDImageStore.getDir()

## Работа с хранилищем доверенных сертификатов

Криптопровайдер КриптоПро JCP осуществляет хранение доверенных сертификатов в определяемым пользователем хранилище сертификатов через стандартный интерфейс JCA (класс KeyStore). Следует заметить, что использование интерфейса этого класса является общим как для работы хранилищем сертификатов, так и для работы с ключевыми носителями. Особенности работы с хранилищем сертификатов описаны ниже.

### Запись сертификатов в хранилище доверенных сертификатов

Криптопровайдер КриптоПро JCP позволяет осуществлять запись доверенных сертификатов в определяемое пользователем хранилище доверенных сертификатов, соответствующее стандартному интерфейсу хранилища JCA (класс KeyStore). Для этого необходимо выполнить последовательность действий, аналогичную последовательности при работе с ключевыми носителями:

#### Инициализация хранилища доверенных сертификатов

Аналогично определению типа используемого ключевого носителя.

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

        KeyStore ks = KeyStore.getInstance("CertStore");

        KeyStore ks = KeyStore.getInstance("CertStore", "JCP");

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

#### Загрузка содержимого хранилища

Согласно интерфейсу стандартного хранилища JCA перед началом выполнения каких либо операций требуется загрузка всего содержимого хранилища. Загрузка содержимого стандартного хранилища JCA осуществляется посредством вызова метода load() класса KeyStore. Согласно интерфейсу JCA функции load() следует передавать два параметра: поток, из которого осуществляется чтение содержимого ключевого хранилища, и пароль на хранилище.

Особенности вызова метода load() ввиду общего интерфейса работы с ключевыми носителями и с хранилищем сертификатов подробно описаны выше.

#### Запись сертификата в хранилище

После того, как содержимое хранилища сертификатов было загружено, осуществляется собственно запись доверенного сертификата. Данная операция реализуется при помощи вызова метода setCertificateEntry() класса KeyStore следующим образом:

        String alias;       // идентификатор (уникальное имя) устанавливаемого

                            // в хранилище сертификата

        Certificate cert;   // записываемый сертификат

        ks.setCertificateEntry(alias, cert);

Следует отметить некоторые особенности вызова функции setCertificateEntry(). с передачей ему параметра `alias`, являющегося уникальным именем записываемого сертификата.

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

#### Сохранение содержимого хранилища

Производится аналогично сохранению содержимого ключевого носителя.

Пример записи сертификата в хранилище доверенных сертификатов см. samples/samples_src.jar/userSamples/Certificates.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

### Чтение сертификатов из хранилища доверенных сертификатов

Криптопровайдер КриптоПро JCP позволяет осуществлять чтение доверенных корневых сертификатов из хранилища, определенного пользователем через стандартный интерфейс JCA класса KeyStore, посредством выполнения следующих действий:

- инициализация хранилища доверенных сертификатов;
- загрузка содержимого хранилища;
- чтение сертификата из хранилища;
- сохранение содержимого хранилища .

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

        String alias;   // идентификатор (уникальное имя) сертификата,

                        // установленный при записи сертификата в хранилище

        Certificate cert = ks.getCertificate(alias);

Следует отметить некоторые особенности вызова функции getCertificate() с передаваемым параметром `alias`, являющимся уникальным именем запрашиваемого сертификата.

- если в хранилище существует сертификат с заданным именем `alias`, то метод getCertificate() вернет сертификат из хранилища сертификатов;
- если в хранилище нет сертификата именем `alias`, но такой сертификат есть на носителе, чьим именем было проинициализировано хранилище сертификатов, то метод getCertificate() вернет сертификат с носителя;
- если сертификата с заданным именем `alias` не существует ни в хранилище сертификатов, ни на носителе, то метод getCertificate() вернет `null`.

Пример чтения сертификата из хранилища доверенных сертификатов см. samples/samples_src.jar/userSamples/Certificates.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

Примечание: Согласно интерфейсу JCA существует возможность загрузки хранилища сертификатов без пароля `ks.load(stream, null)`. При этом провайдер КриптоПро JCP позволяет осуществлять все операции связанные с чтением и запрещает операции связанные с изменением хранилища (изменять хранилище можно только при загрузке его с паролем).

## Генерация случайных чисел

Криптопровайдер КриптоПро JCP позволяет осуществлять генерацию случайных чисел на основе алгоритма ГОСТ 28147-89, через стандартный интерфейс JCA при помощи класса SecureRandom.

### Создание генератора случайных чисел

Генератор случайных чисел создается посредством вызова метода getInstance() класса SecureRandom. Этот метод является статическим и возвращает ссылку на созданный объект класса SecureRandom.

Для создания генератора методу getInstance() необходимо в качестве параметра передать имя, идентифицирующее алгоритм ("CPRandom" или JCP.CP_RANDOM). При таком вызове метода getInstance() совместно с определением требуемого алгоритма осуществляется также определение требуемого типа криптопровайдера (КриптоПро JCP). Стандартный интерфейс JCA позволяет в качестве параметра функции getInstance() класса SecureRandom вместе с именем алгоритма указывать имя криптопровайдера, используемого для выполнения операции. Таким образом, создание генератора осуществляется одним из следующих способов:

        SecureRandom rnd = SecureRandom.getInstance("CPRandom");

        SecureRandom rnd = SecureRandom.getInstance("CPRandom", "JCP");

        SecureRandom rnd = SecureRandom.getInstance(JCP.CP_RANDOM, JCP.PROVIDER_NAME);

### Использование генератора случайных чисел

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

    void initSign(PrivateKey privateKey, SecureRandom random).

При генерации ключевой пары в класс KeyPairGenerator можно установить конкретный генератор функцией

    void initialize(AlgorithmParameterSpec params, SecureRandom random).

Однако, чтобы обеспечить необходимое качество случайных последовательностей, КриптоПро JCP игнорирует генераторы, переданные таким способом в качестве параметров. Поэтому для увеличения производительности не стоит создавать новые генераторы только для того, чтобы проинициализировать ими другие классы JCA/JCE.

Для других целей, после того, как генератор случайных чисел был создан, можно получить случайную последовательность функцией void nextBytes(byte[] bytes)

### Доинициализация датчика

В любой момент времени созданный генератор можно доинициализировать с помощью функции public byte[] generateSeed(int numBytes) любой последовательностью. Это довольно долгая операция и не стоит ей злоупотреблять в приложениях, требующих высокой производительности.

### Возможные ошибки датчика

В процессе работы генератор случайных чисел КриптоПро JCP контролирует качество выходной последовательности и проводит периодический контроль целостности. В случае обнаружения нарушения целостности, генератор возбуждает исключение ru.CryptoPro.JCP.Random.RandomRefuseException. Возникновение этой ошибки возможно в любом месте, где используется генератор. Например, при генерации ключа, при подписи. Использование криптопровайдера КриптоПро JCP в этом случае не допускается.

### Биодатчик

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

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

- ru.CryptoPro.JCP.Random.BioRandomConsole - консольный биодатчик
- ru.CryptoPro.JCP.Random.BioRandomFrame - графический биодатчик

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

Пример использования генератора случайных чисел с использованием класса SecureRandom см. samples/samples_src.jar/userSamples/Random.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

## Хеширование данных в соответствии с алгоритмом ГОСТ Р 34.11-94

Криптопровайдер КриптоПро JCP осуществляет хеширование данных в соответствии с алгоритмом ГОСТ Р 34.11-94, через стандартный интерфейс JCA при помощи класса MessageDigest.

### Создание объекта хеширования данных

Объект хеширования данных в соответствии с алгоритмом ГОСТ Р 34.11-94 создается посредством вызова метода getInstance() класса MessageDigest. Этот метод является статическим и возвращает ссылку на класс MessageDigest, который обеспечивает выполнение требуемой операции.

Для создания объекта хеширования в соответствии с алгоритмом ГОСТ Р 34.11-94 методу getInstance() необходимо в качестве параметра передать имя, идентифицирующее данный алгоритм ("GOST3411" или JCP.GOST_DIGEST_NAME). При таком вызове метода getInstance() совместно с определением требуемого алгоритма хеширования данных осуществляется также определение требуемого типа криптопровайдера (КриптоПро JCP). Также стандартный интерфейс JCA позволяет в качестве параметра функции getInstance() класса MessageDigest вместе с именем алгоритма указывать имя криптопровайдера, используемого для выполнения требуемой операции. Таким образом, создание генератора ключевой пары осуществляется одним из следующих способов:

        MessageDigest digest = MessageDigest.getInstance("GOST3411");

        MessageDigest digest = MessageDigest.getInstance("GOST3411", "JCP");

        MessageDigest digest = MessageDigest.getInstance(JCP.GOST_DIGEST_NAME, JCP.PROVIDER_NAME);

Хеширование данных при помощи созданного таким образом объекта `digest` будет осуществляться в соответствии с алгоритмом ГОСТ Р 34.11-94 и с установленными в контрольной панели параметрами (параметрами по умолчанию). Стандартный интерфейс JCA класса MessageDigest не позволяет изменять параметры созданного объекта хеширования, но если существует такая необходимость, то при помощи дополнительных возможностей криптопровайдера КриптоПро JCP можно установить требуемые параметры хеширования (отличные от параметров, установленных в контрольной панели).

### Определение параметров хеширования данных

После того, как объект хеширования данных был создан, может возникнуть необходимость изменить параметры хеширования, установленные ранее в контрольной панели. Операция изменения существующего набора параметров не может быть осуществлена при помощи стандартного интерфейса JCA класса MessageDigest, поэтому для ее реализации следует привести созданный объект хеширования к типу `GostDigest` и уже для объекта этого класса воспользоваться методом reset(), передавая данному методу идентификатор устанавливаемых параметров (`OID`):

        // ВНИМАНИЕ! для совместимости с другими продуктами КриптоПро

        // допустимо использовать только параметры по умолчанию:

        // "1.2.643.2.2.30.1"

        OID digestOid = new OID("1.2.643.2.2.30.1");

        /* преобразование к типу GostDigest */

        GostDigest gostDigest = (GostDigest)digest;

        /* установка требуемых параметров */

        gostDigest.reset(digestOid);

Метод reset() (без параметров) стандартного интерфейса JCA класса MessageDigest изменяет установленные параметры хеширования на параметры по умолчанию.

Использование метода изменения параметров хеширования см. samples/samples_src.jar/userSamples/Digest.java (входит в комплект поставки программного обеспечения КриптоПро JCP). Данная операция имеет смысл только до начала выполнения непосредственной операции создания хеша данных.

### Копирование объекта хеширования данных

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

Для этих целей используется метод clone() класса MessageDigest, который возвращает точную копию существующего объекта хеширования. Этот метод может быть вызван на любом этапе выполнения операции хеширования после того, как объект хеширования был проинициализирован и до того, как операция хеширования была завершена. Cм. samples/samples_src.jar/userSamples/Digest.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

### Вычисление хеша данных в соответствии с алгоритмом ГОСТ Р 34.11-94

После того, как объект хеширования был создан, вычисление хеша данных в соответствии с алгоритмом ГОСТ Р 34.11-94 производится в два этапа: обработка данных и последующее завершение операции хеширования.

#### Обработка хешируемых данных

Обработка хешируемых данных может быть осуществлена двумя способами:

- при помощи метода update() класса MessageDigest;
- при помощи метода read() класса DigestInputStream.

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

- Использование метода update().

Метод update() класса MessageDigest осуществляет обработку хешируемых данных, представленных в виде байтового массива и подаваемых ему в качестве параметра. Существует 3 варианта обработки байтового массива данных при помощи этого метода:

1. Последовательная обработка каждого байта данных (при этом количество вызовов метода update(byte b) равно длине массива данных):

    2.

    3.      byte[] data;

    4.      for(int i = 0; i < data.length; i++)

    5.          digest.update(data[i]);

6. Блочная обработка данных (данные обрабатываются блоками определенной длины):

    7.

    8.      byte[] data;

    9.      int BLOC_LEN = 1024;

    10.

    11.    // если длина исходных данных меньше длины блока

    12.    if(data.length/BLOC_LEN == 0)

    13.        digest.update[data];

    14.    else {

    15.        // цикл по блокам

    16.        for (int i = 0; i < data.length/BLOC_LEN; i++) {

    17.            byte[] bloc = new byte[BLOC_LEN];

    18.            for(int j = 0; j < BLOC_LEN; j++) bloc[j] = data[j + i * BLOC_LEN];

    19.            digest.update(bloc);

    20.        }

    21.

    22.        // обработка остатка

    23.        byte[] endBloc = new byte[data.length % BLOC_LEN];

    24.        for(int j = 0; j < data.length % BLOC_LEN; j++)

    25.            bloc[j] = data[j + data.length - data.length % BLOC_LEN - 1];

    26.        digest.update(bloc);

    27.    }

28. Обработка данных целиком:

    29.

    30.    byte[] data;

    31.    digest.update(data);

Допускается комбинирование первого и второго варианта, обработка блоками различной длины, а также использование метода update(byte[]data, int offset, int len) - обработка массива данных со смещением. Но в любом случае следует помнить, что для корректного подсчета хеша на этапе завершения операции хеширования необходимо обработать все байты массива данных.

- Использование метода read().

Помимо использования метода update() класса MessageDigest обработка хешируемых данных может быть осуществлена посредством метода read() класса DigestInputStream. Фактически, этот метод в зависимости от способа обработки данных (см. ниже) вызывает соответствующий вариант обработки при помощи метода update(). Для осуществления обработки данных из исходного байтового массива данных необходимо создать новый объект типа ByteArrayInputStream, а затем из него и созданного ранее объекта хеширования данных получить новый объект типа DigestInputStream:

                 byte[] data;

                 ByteArrayInputStream stream = new ByteArrayInputStream(data);

                 DigestInputStream digestStream = new DigestInputStream(stream, digest);

После того, как объект типа DigestInputStream создан, обработка хешируемых данных осуществляется при помощи метода read() класса DigestInputStream. При этом, как и в случае метода update(), существует 3 варианта использования метода read():

1. Последовательная обработка каждого байта данных (при этом количество вызовов метода read(byte b) равно длине массива данных):

    2.

    3.      while (digestStream.available() != 0)

    4.      digestStream.read();

5. Блочная обработка данных (данные обрабатываются блоками определенной длины, при этом считанные данные записываются в передаваемый функции read() массив):

    6.

    7.      int BLOC_LEN = 1024;

    8.      int DATA_LEN = digestStream.available();

    9.      // если длина исходных данных меньше длины блока

    10.    if(DATA_LEN/BLOC_LEN == 0) {

    11.        byte[] data = new byte[DATA_LEN];

    12.        digestStream.read(data, 0, DATA_LEN);

    13.    }

    14.    else {

    15.        // цикл по блокам

    16.        for (int i = 0; i < DATA_LEN/BLOC_LEN; i++) {

    17.            byte[] bloc = new byte[BLOC_LEN];

    18.            digestStream.read(bloc, 0, BLOC_LEN);

    19.        }

    20.

    21.        // обработка остатка

    22.        byte[] endBloc = new byte[DATA_LEN % BLOC_LEN];

    23.        digestStream.read(endBloc, 0, DATA_LEN % BLOC_LEN);

    24.    }

25. Обработка данных целиком (при этом считанные данные записываются в передаваемый функции read() массив):

    26.

    27.    byte[] data = new byte[digestStream.available()];

    28.    digestStream.read(data, 0, digestStream.available());

Допускается комбинирование первого и второго варианта, обработка блоками различной длины, а также использование метода read(byte[]data, int offset, int len) - запись считанных данных в массив со смещением. Но в любом случае следует помнить, что для корректного подсчета хеша на этапе завершения операции хеширования необходимо обработать все байты массива данных.

#### Завершение операции хеширования

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

1. Вызовом метода без параметров - digest().
   В этом случае метод возвращает байтовый массив, содержащий значение хеша;

2. Вызовом метода с параметрами - digest(byte[] buf, int offset, int len).
В этом случае метод записывает значение хеша в передаваемый ему массив со смещением.

Примеры хеширования данных в соответствии с алгоритмом ГОСТ Р 34.11-94 см. samples/samples_src.jar/userSamples/Digest.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

## Формирование электронной подписи в соответствии с алгоритмом ГОСТ Р 34.10-2001

Криптопровайдер КриптоПро JCP осуществляет формирование электронной подписи данных, соответствующей алгоритму ГОСТ Р 34.10-2001, через стандартный интерфейс JCA при помощи класса Signature. Формирование ЭП для любого другого алгоритма при помощи криптопровайдера КриптоПро JCP запрещается.

В криптопровайдере КриптоПро JCP кроме хэша по алгоритму ГОСТ Р 34.11-94, можно подписывать непосредственно данные. Данная опция возможна, начиная с версии 1.0.52. Подпись данных осуществляет блок Raw-алгоритмов.

Перед формированием электронной подписи необходимо осуществить проверку ключа электронной подписи, гарантирующую не истекший срок действия ключа. Для этого используется метод valid() класса ru.CryptoPro.reprov.x509.PrivateKeyUsageExtension.

### Создание объекта формирования ЭП

Объект формирования ЭП данных создается посредством вызова метода getInstance() класса Signature. Этот метод является статическим и возвращает ссылку на класс Signature, который обеспечивает выполнение требуемой операции.

Для создания объекта формирования ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001 (а точнее, алгоритм подписи ГОСТ Р 34.10-2001 с алгоритмом хеширования ГОСТ Р 34.11-94) методу getInstance() необходимо в качестве параметра передать имя, идентифицирующее данный алгоритм:

- "GOST3411withGOST3410EL" или JCP.GOST_EL_SIGN_NAME
- "CryptoProSignature" или JCP.CRYPTOPRO_SIGN_NAME (для совместимости с КриптоПро CSP)

При таком вызове метода getInstance() совместно с определением требуемого алгоритма формирования ЭП осуществляется также определение требуемого типа криптопровайдера (КриптоПро JCP). Также стандартный интерфейс JCA позволяет в качестве параметра функции getInstance() класса Signature вместе с именем алгоритма передавать имя криптопровайдера, используемого для выполнения требуемой операции.

Таким образом, создание объекта формирования ЭП осуществляется одним из следующих способов:

        Signature sig = Signature.getInstance("GOST3411withGOST3410EL");

        Signature sig = Signature.getInstance("GOST3411withGOST3410EL", "JCP");

        Signature sig = Signature.getInstance(JCP.GOST_EL_SIGN_NAME, JCP.PROVIDER_NAME);

        //для совместимости с КриптоПро CSP (подпись имеет обратный порядок байт)

        Signature sig = Signature.getInstance("CryptoProSignature");

        Signature sig = Signature.getInstance("CryptoProSignature", "JCP");

        Signature sig = Signature.getInstance(JCP.CRYPTOPRO_SIGN_NAME, JCP.PROVIDER_NAME);

Для создания объекта формирования ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001 без хэширования данных (Raw-алгоритмы), необходимо методу getInstance() передать имя, идентифицирующее данный алгоритм:

- "NONEwithGOST3410EL" или JCP.RAW_GOST_EL_SIGN_NAME
- "NONEwithCryptoProSignature" или JCP.RAW_CRYPTOPRO_SIGN_NAME (для совместимости с КриптоПро CSP)

В данном случае также можно определять и криптопровайдер:

        Signature sig = Signature.getInstance("NONEwithGOST3410EL");

        Signature sig = Signature.getInstance("NONEwithGOST3410EL", "JCP");

        Signature sig = Signature.getInstance(JCP.RAW_GOST_EL_SIGN_NAME, JCP.PROVIDER_NAME);

        //для совместимости с КриптоПро CSP (подпись имеет обратный порядок байт)

        Signature sig = Signature.getInstance("NONEwithCryptoProSignature");

        Signature sig = Signature.getInstance("NONEwithCryptoProSignature", "JCP");

        Signature sig = Signature.getInstance(JCP.RAW_CRYPTOPRO_SIGN_NAME, JCP.PROVIDER_NAME);

### Инициализация объекта формирования ЭП

После того, как объект формирования ЭП был создан, необходимо определить набор параметров алгоритма ГОСТ Р 34.10-2001, в соответствии с которыми будет осуществляться операция формирования ЭП. Определение параметров ЭП осуществляется во время инициализации операции создания подписи методом initSign() класса Signature. в соответствии с параметрами ключа ЭП, передаваемыми данному методу. Этот ключ не только определяет параметры формирования ЭП, но и используется в процессе ее формирования.

Необходимо помнить, что ключи ЭП, подаваемые на инициализацию объекта формирования ЭП, созданного описанным выше способом, должны соответствовать алгоритму ГОСТ Р 34.10-2001. Способ генерации таких ключей описан выше. Создание подписи для любых других ключей запрещено.

Таким образом, инициализация операции формирования ЭП, во время которой происходит определение параметров подписи, осуществляется следующим образом:

        PrivateKey privateKey; // обязательно ключ с алгоритмом "GOST3410"

                               // (соответствующий алгоритму ГОСТ Р 34.10-2001)

        sig.initSign(privateKey);

### Определение параметров формирования ЭП

После инициализации объекта формирования ЭП ключом подписи может возникнуть необходимость изменить параметры формирования ЭП (установить параметры, отличные от параметров ключа ЭП). Изменять разрешается только параметры хеширования, используемые в процессе формирования ЭП, причем изменение этих параметров допустимо только до начала операции формирования ЭП. Изменение параметров хеширования осуществляется при помощи метода setParameter() класса Signature. Этому методу в качестве параметра передается объект `ParamsInterface`, являющийся интерфейсом устанавливаемых параметров хеширования (создание объектов такого типа описывается ниже). Тогда изменение параметров хеширования для формирования ЭП осуществляется следующим образом:

        ParamsInterface digestParams; // интерфейс параметров хеширования

        sig.setParameter(digestParams); // установка параметров, определенных интерфейсом digestParams

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

### Формирование электронной подписи

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

#### Обработка подписываемых данных

Обработка подписываемых данных осуществляется при помощи метода update() класса Signature. Этот метод осуществляет обработку подписываемых данных, представленных в виде байтового массива и подаваемых ему в качестве параметра. Существует 3 варианта обработки байтового массива данных при помощи этого метода:

1. Последовательная обработка каждого байта данных (при этом количество вызовов метода update(byte b) равно длине массива данных):

    2.

    3.      byte[] data;

    4.      for(int i = 0; i < data.length; i++)

    5.      sig.update(data[i]);

6. Блочная обработка данных (данные обрабатываются блоками определенной длины):

    7.

    8.      byte[] data;

    9.      int BLOC_LEN = 1024;

    10.

    11.    // если длина исходных данных меньше длины блока

    12.    if(data.length/BLOC_LEN == 0)

    13.        sig.update[data];

    14.    else {

    15.        // цикл по блокам

    16.        for (int i = 0; i < data.length/BLOC_LEN; i++) {

    17.            byte[] bloc = new byte[BLOC_LEN];

    18.            for(int j = 0; j < BLOC_LEN; j++) bloc[j] = data[j + i * BLOC_LEN];

    19.            sig.update(bloc);

    20.        }

    21.

    22.        // обработка остатка

    23.        byte[] endBloc = new byte[data.length % BLOC_LEN];

    24.        for(int j = 0; j < data.length % BLOC_LEN; j++)

    25.            bloc[j] = data[j + data.length - data.length % BLOC_LEN - 1];

    26.        sig.update(bloc);

    27.    }

28. Обработка данных целиком:

    29.

    30.    byte[] data;

    31.    sig.update(data);

Допускается комбинирование первого и второго варианта, обработка блоками различной длины, а также использование метода update(byte[]data, int offset, int len) - обработка массива данных со смещением. Но в любом случае следует помнить, что для корректного вычисления подписи на этапе завершения операции создания подписи необходимо обработать все байты массива данных.

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

#### Вычисление значения ЭП

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

1. Вызов метода без параметров - sign(). В этом случае метод возвращает байтовый массив, содержащий значение подписи;
2. Вызов метода с параметрами - sign(byte[] buf, int offset, int len). В этом случае метод записывает значение подписи в передаваемый ему массив со смещением.

Оба метода для Raw-алгоритмов подписывают данные, переданные методами update, интерпретируя их как значение хэша. Алгоритмы, использующие ГОСТ Р 34.11-94, вычисляют хэш переданных данным, а затем его подписывают.

## Проверка электронной подписи в соответствии с алгоритмом ГОСТ Р 34.10-2001

Криптопровайдер КриптоПро JCP осуществляет проверку ЭП данных, соответствующую алгоритму ГОСТ Р Р 34.10-2001, через стандартный интерфейс JCA при помощи класса Signature.

### Создание объекта проверки ЭП

Объект проверки ЭП данных создается посредством вызова метода getInstance() класса Signature. Этот метод является статическим и возвращает ссылку на класс Signature, который обеспечивает выполнение требуемой операции.

Для создания объекта проверки ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001 (а точнее, алгоритм подписи ГОСТ Р 34.10-2001 с алгоритмом хеширования ГОСТ Р 34.11-94) методу getInstance() необходимо в качестве параметра передать имя, идентифицирующее требуемый алгоритм проверки ЭП (см. создание объекта формирования ЭП; для алгоритма ГОСТ Р 34.10-2001 - "GOST3411withGOST3410EL" или JCP.GOST_EL_SIGN_NAME).

Для создания объекта проверки ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001 без подсчета хэша, методу getInstance() необходимо в качестве параметра передать имя, идентифицирующее требуемый алгоритм проверки ЭП (см. создание объекта формирования ЭП; для алгоритма ГОСТ Р 34.10-2001 - "NONEwithGOST3410EL" или JCP.RAW_GOST_EL_SIGN_NAME).

### Инициализация объекта проверки ЭП

После того, как объект проверки ЭП был создан, необходимо определить набор параметров заданного при создании объекта алгоритма (ГОСТ Р 34.10-2001), в соответствии с которыми будет осуществляться операция проверки ЭП. Определение параметров ЭП осуществляется во время инициализации операции проверки подписи методом initVerify() класса Signature. в соответствии с параметрами ключа проверки ЭП, передаваемыми данному методу. Этот ключ не только определяет параметры проверки ЭП, но и используется в самом процессе проверки.

Необходимо помнить, что ключи проверки ЭП, подаваемые на инициализацию объекта проверки ЭП, созданного описанным выше способом должны соответствовать алгоритму этого объекта (соответственно, алгоритму ГОСТ Р ГОСТ Р 34.10-2001). Способ генерации ключей для алгоритма ГОСТ Р 34.10-2001 описан выше. Помимо этого для корректной проверки ЭП требуется, чтобы ключ проверки ЭП соответствовал ключу ЭП, на котором осуществлялось формирование подписи.

Таким образом, инициализация операции проверки ЭП, во время которой происходит определение параметров ЭП, осуществляется следующим образом:

        PublicKey publicKey;  // алгоритм ГОСТ Р ГОСТ Р 34.10-2001

        sig.initVerify(publicKey);

### Определение параметров проверки ЭП

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

### Проверка электронной подписи

После того, как объект проверки подписи был создан и проинициализирован, операция проверки подписи производится в два этапа: обработка данных и последующая проверка подписи, завершающая текущую операцию.

#### Обработка подписанных данных

Обработка подписанных данных осуществляется при помощи метода update() класса Signature и полностью аналогична обработке данных при создании подписи.

#### Проверка ЭП

После того, как все данные были обработаны, следует завершить операцию проверки ЭП. Завершение осуществляется при помощи метода verify() класса Signature. Этой функции передается проверяемое значение подписи и в результате ее работы возвращается логическое значение: true - подпись верна, false - подпись не верна. Значение проверяемой подписи можно передать двумя способами:

- в качестве байтового массива - verify(byte[] signature);
- в качестве байтового массива со смещением - verify(byte[] signature, int offset, int length);

Примеры создания и проверки подписи см. samples/samples_src.jar/userSamples/SignAndVerify.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

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

## Работа с сертификатами через стандартный интерфейс JCA

Для осуществления операций, реализуемых криптопровайдером КриптоПро JCP, зачастую требуется использование стандартных методов JCA работы с сертификатами. Такими операциями, например, являются:

- запись ключа ЭП на носитель;
- запись на носитель сертификата ключа проверки ЭП, в соответствии с хранящимся на носителе ключом ЭП, и сертификата с носителя;
- запись сертификата в хранилище доверенных сертификатов и чтение сертификата из хранилища;
- проверка ЭП при помощи ключа проверки ЭП, читаемого из сертификата;
- построение и проверка цепочек сертификатов.

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

### Генерация X509-сертификатов

Генерация X509-сертификатов осуществляется при помощи метода generateCertificate() класса CertificateFactory следующим образом:

        InputStream inStream;

        CertificateFactory cf = CertificateFactory.getInstance("X509");

        //или

        //CertificateFactory cf = CertificateFactory.getInstance(JCP.CERTIFICATE_FACTORY_NAME);

        Certificate cert = cf.generateCertificate(inStream);

Метод generateCertificate() получает в качестве параметра входной поток, в который записан закодированный в DER-кодировке сертификат, и возвращает объект класса Certificate. Инициализацию объекта класса CertificateFactory следует производить именем "X509" или JCP.CERTIFICATE_FACTORY_NAME (как показано выше). В этом случае выдаваемый методом generateCertificate() сертификат будет удовлетворять стандарту X.509, а значит являться объектом класса X509Certificate (этот класс является расширением класса Certificate). Криптопровайдер КриптоПро JCP поддерживает только стандарт X.509.

Генерация X509-сертификатов используется в тех операциях, которые согласно стандартному интерфейсу JCA требуют для своего выполнения объекты класса Certificate. Такими операциями являются, например, запись ключа ЭП на носитель и запись сертификата в хранилище доверенных сертификатов или на носитель.

Закодированный в DER-кодировке сертификат, передаваемый функции generateCertificate() во входном потоке может быть получен при помощи методов класса `GostCertificateRequest` (см. дополнительные возможности работы с сертификатами). Получение закодированного сертификата при помощи класса `GostCertificateRequest` используется в тех случаях, когда требуется соответствие ключа проверки ЭП сертификата только что созданному ключу ЭП (например, при осуществлении записи ключа ЭП на носитель). Если же ключ ЭП не известен (например, при проверке ЭП), либо ключ ЭП, которому соответствует ключ проверки ЭП сертификата был создан ранее (например, при записи сертификата на носитель, на котором уже существует ключ ЭП), то в этом случае закодированный сертификат, передаваемый функции generateCertificate(), может быть прочитан из файла.

### Кодирование сертификата в DER-кодировку

Кодирование существующего сертификата (объекта класса Certificate) осуществляется при помощи метода getEncoded() класса Certificate следующим образом:

        Certificate cert;

        byte[] encoded = cert.getEncoded();

Закодированный в DER-кодировке методом getEncoded() сертификат возвращается в виде байтового массива. Сертификат `cert`, для которого осуществляется кодирование, может быть получен различными методами: генерацией X509-сертификата, чтением сертификата ключа проверки ЭП с носителя, либо чтением доверенного сертификата из хранилища (все эти методы возвращают объект класса Certificate).

Операция кодирования сертификата используется в случае, когда требуется сохранить в файл только что сгенерированный или прочитанный с носителя (или из хранилища) сертификат. Пример записи сертификата в файл см. samples/samples_src.jar/userSamples/Certificates.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

### Получение ключа проверки ЭП из сертификата

Получение ключа проверки ЭП из сертификата (объекта класса Certificate) осуществляется при помощи метода getPublicKey() класса Certificate следующим образом:

        Certificate cert;

        PublicKey publicKey = cert.getPublicKey();

Сертификат `cert`, из которого получается ключ проверки ЭП`publicKey`, может быть получен различными методами: генерацией X509-сертификата, чтением сертификата ключа проверки ЭП с носителя, либо чтением доверенного сертификата из хранилища (все эти методы возвращают объект класса Certificate).

Операция получения ключа проверки ЭП из сертификата используется при осуществлении проверки ЭП

### Построение и проверка цепочки сертификатов

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

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

#### Совместимость с КриптоПро УЦ при проверке цепочки сертификатов

Для проверки цепочки в режиме совместимости с КриптоПро УЦ в состав КриптоПро JCP входит провайдер RevCheck (JCPRevCheck.jar). Для его вызова в примерах, описанных ниже, следует заменить вызов алгоритма "PKIX" на вызов алгоритма "CPPKIX"

        //для проверки цепочки online

        System.setProperty("com.sun.security.enableCRLDP", "true");//если используется SUN JVM

        или

        System.setProperty("com.ibm.security.enableCRLDP", "true");//если используется IBM JVM

        //для построения цепочки

        CertPathBuilder builder = CertPathBuilder.getInstance("CPPKIX");

        и

        //для проверки цепочки

        CertPathValidator validator = CertPathValidator.getInstance("CPPKIX");

В остальных случаях применения в JTLS (cpSSL.jar) процедура проверки цепочки сертификатов регулируется с помощью панели JCP (вкладка "Настройки сервера").

Пример построения и проверки цепочки сертификатов см. samples/samples_src.jar/userSamples/Certificates.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

#### Проверка цепочки сертификатов с использованием OCSP

Начиная с версии java 1.5 появилась возможность проверять цепочку сертификатов используя On-Line Certificate Status Protocol (OCSP). Для проверки используются стандартные средства java-машины.

Пример проверки см. samples/samples_src.jar/userSamples/OCSPValidateCert.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

## Работа с временным хранилищем ключей и сертификатов

Криптопровайдер КриптоПро JCP дает возможность работы с временным хранилищем ключей и сертификатов. Данное хранилище существует только в памяти, его нельзя записать на носитель.
Для использования данного хранилища необходимо обеспечить недоступность сторонних лиц к java-машине!
Если есть возможность доступа сторонних лиц к java-машине, то использование данного типа хранилища ЗАПРЕЩЕНО, т.к. иначе существует возможность доступа к секретным ключам (касается "MemoryStoreX", см. далее).
Осуществление операций с хранилищем производится через стандартный интерфейс хранилища ключом ЭП JCA (интерфейс класса KeyStore). Определение типа используемого хранилища осуществляется одним из следующих способов:

        KeyStore ks = KeyStore.getInstance("MemoryStore");

        KeyStore ks = KeyStore.getInstance("MemoryStore0");

        //существует 10 хранилищ данного типа : MemoryStore0-MemoryStore9

При инициализации "MemoryStore" каждый раз возвращается новый объект, а при инициализации типа "MemoryStoreX" возвращается ссылка на ранее созданный объект. Далее работа аналогична работе с ключевыми носителями.

        //загрузка хранилища (осуществляется для инициализации стандартного объекта KeyStore)

        ks.load(null, null);

        //запись ключа в хранилище

        String alias;          // идентификатор (уникальное имя) ключа

        PrivateKey key;        // ключ ЭП

        char[] password;       // пароль на ключ

        Certificate[] chain;   // цепочка сертификатов

        ks.setKeyEntry(alias, key, password, chain);

        //Чтение ключа ЭП из хранилища

        String alias;          // идентификатор (уникальное имя) получаемого ключа ЭП,

                               // установленный при записи ключа

        char[] password;       // пароль на ключ, установленный при записи ключа

        PrivateKey key = (PrivateKey)ks.getKey(alias, password);

        //Запись сертификата в хранилище

        String aliasCert;      // идентификатор сертификата

        Certificate cert;      // записываемый сертификат

        ks.setCertificateEntry(aliasCert, cert);

        //Чтение сертификата из хранилища

        String aliasCert;      // идентификатор сертификата, установленный при записи сертификата

        Certificate cert = ks.getCertificate(aliasCert);

        //Удаление

        String alias;          //идентификатор ключа или сертификата

        ks.deleteEntry(alias);

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

# Работа с параметрами в криптопровайдере КриптоПро JCP

Зачастую при работе с ключами ЭП возникает необходимость изменить набор параметров того или иного алгоритма для выполнения требуемой операции. Для этих целей в криптопровайдере КриптоПро JCP реализован интерфейс `ParamsInterface` параметров алгоритма, являющийся реализацией стандартного класса AlgorithmParameterSpec. Объект типа `ParamsInterface`, в зависимости от способа его создания, определяет

- интерфейс набора параметров ключа подписи;
- интерфейс параметров алгоритма подписи ГОСТ Р 34.10-2001;
- интерфейс параметров алгоритма хеширования ГОСТ Р 34.11-94;
- интерфейс параметров алгоритма шифрования ГОСТ 28147-89.

Во всех случаях, интерфейс параметров/набора параметров `ParamsInterface` позволяет:

- получать идентификатор текущих параметров алгоритма / набора параметров ключа при помощи функции getOID();
- получать идентификатор по умолчанию для параметров алгоритма / набора параметров ключа при помощи функции getDefault();
- проверять права на изменение идентификатора по умолчанию для параметров алгоритма / набора параметров ключа при помощи функции setDefaultAvailable();
- устанавливать идентификатор по умолчанию для параметров алгоритма / набора параметров ключа при помощи функции setDefault(OID def);
- получать список допустимых идентификаторов для параметров алгоритма / набора параметров ключа при помощи функции getOIDs();
- получать список строковых представлений допустимых идентификаторов для параметров алгоритма / набора параметров ключа при помощи функции getNames();
- получать строковое представление одного из допустимых идентификаторов для параметров алгоритма / набора параметров ключа при помощи функции getNamebyOID(OID oid);
- получать один из допустимых идентификаторов для параметров алгоритма / набора параметров ключа по его строковому представлению при помощи функции getOIDbyName(String oid).

## Работа с набором параметров для генерации ключей ЭП

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

- идентификатор набора параметров для генерации ключевой пары;
- параметры алгоритма подписи ГОСТ Р 34.10-2001;
- параметры алгоритма хеширования ГОСТ Р 34.11-94;
- параметры алгоритма шифрования ГОСТ 28147-89.

Изменение такого набора параметров осуществляется при помощи интерфейса `AlgIdInterface`, являющегося расширением интерфейса `ParamsInterface`. Объект типа `AlgIdInterface` представляет собой интерфейс устанавливаемого набора параметров. Такой объект может быть создан при помощи класса `AlgIdSpec`, являющегося реализацией этого интерфейса несколькими способами:

        // идентификатор набора параметров для ключа подписи, соответствующего алгоритму ГОСТ Р 34.10-2001

        // "1.2.643.2.2.19" или JCP.GOST_EL_KEY_OID

        String keyOIDStr;

        OID keyOid = new OID(keyOIDStr);

        // идентификаторы параметров алгоритмов

        OID signOid;

        OID digestOid;

        OID cryptOid;

        // параметры алгоритмов

        ParamsInterface signParams;

        ParamsInterface digestParams;

        ParamsInterface cryptParams;

        /* определение набора параметров по умолчанию (установленного в контрольной панели) */

        AlgIdSpec keyParams1 = new AlgIdSpec(null);

        /* определение набора параметров по идентификатору алгоритма генерации ключевой пары

        (в этом случае устанавливается набор параметров по умолчанию, соответствующий этому

        идентификатору). На данный момент единственным допустимым идентификатором набора параметров

        для генерации ключа подписи является "1.2.643.2.2.19" (или JCP.GOST_EL_KEY_OID),

        поэтому такой способ создания идентичен первому способу*/

        AlgIdSpec keyParams2 = new AlgIdSpec(keyOid);

        /* определение набора параметров по идентификатору алгоритма генерации ключевой пары

        и заданным идентификаторам параметров. Получение таких идентификаторов описано ниже.*/

        AlgIdSpec keyParams3 = new AlgIdSpec(keyOid, signOid, digestOid, cryptOid);

        /* определение набора параметров по идентификатору алгоритма генерации ключевой пары

        и заданным параметрам алгоритмов. Получение таких параметров описано ниже.*/

        AlgIdSpec keyParams4 = new AlgIdSpec(keyOid, signParams, digestParams, cryptParams);

## Работа с параметрами алгоритма подписи ГОСТ Р 34.10-2001

Явно изменение параметров алгоритма подписи ГОСТ Р 34.10-2001 не встречается в функциях стандартного интерфейса JCE, но оно может быть использовано в процессе определения набора параметров для генерации ключевых пар подписи (см. выше). Для изменения используемых параметров ЭП, необходимо в первую очередь получить интерфейс параметров алгоритма подписи ГОСТ Р 34.10-2001 по умолчанию (установленных в контрольной панели). Данная операция может быть выполнена при помощи статического метода getDefaultSignParams() класса `AlgIdSpec`, возвращающего ссылку на интерфейс `ParamsInterface`:

        ParamsInterface signParams = AlgIdSpec.getDefaultSignParams();

Получение набора параметров ЭП и установка параметров по умолчанию (будут использоваться в дальнейшем):

        /* получение всех допустимых идентификаторов параметров алгоритма подписи*/

        Enumeration signOids = signParams.getOIDs();

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

        конструктор keyParams3 для класса AlgIdSpec*/

        OID signOid  = (OID)signOids.nextElement();

        /* изменение идентификатора параметров ЭП по умолчанию. Измененные таким образом

        параметры ЭП могут быть переданы в соответствующий

        конструктор keyParams4 для класса AlgIdSpec*/

        signOids.setDefault(signOid);

## Работа с параметрами алгоритма хеширования ГОСТ Р 34.11-94

Изменение параметров алгоритма хеширования может быть использовано в явном виде в процессе создания ЭП, а также в неявном виде в процессе определения набора параметров для генерации ключевых пар подписи (см. выше). Для изменения используемых параметров хеширования, необходимо в первую очередь получить интерфейс параметров алгоритма хеширования ГОСТ Р 34.11-94 по умолчанию (установленных в контрольной панели). Данная операция может быть выполнена при помощи статического метода getDefaultDigestParams() класса `AlgIdSpec`, возвращающего ссылку на интерфейс `ParamsInterface`:

        ParamsInterface digestParams = AlgIdSpec.getDefaultDigestParams();

Получение набора параметров хеширования и установка параметров по умолчанию (будут использоваться в дальнейшем):

        /* получение всех допустимых идентификаторов параметров алгоритма хеширования*/

        Enumeration digestOids = digestParams.getOIDs();

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

        конструктор keyParams3 для класса AlgIdSpec*/

        OID digestOid  = (OID)digestOids.nextElement();

        /* изменение идентификатора параметров хеширования по умолчанию. Измененные таким образом

        параметры хеширования могут быть переданы в соответствующий

        конструктор keyParams4 для класса AlgIdSpec. Помимо этого они могут быть использованы

        для изменения параметров хеширования при создании ЭП.*/

        digestOids.setDefault(digestOid);

## Работа с параметрами алгоритма шифрования ГОСТ 28147-89

Явно изменение параметров алгоритма шифрования ГОСТ 28147-89 не встречается в функциях стандартного интерфейса JCE, но оно может быть использовано в процессе определения набора параметров для генерации ключевых пар подписи (см. выше). Для изменения используемых параметров ЭП, необходимо в первую очередь получить интерфейс параметров алгоритма шифрования ГОСТ 28147-89 по умолчанию (установленных в контрольной панели). Данная операция может быть выполнена при помощи статического метода getDefaultCryptParams класса `AlgIdSpec`, возвращаюшего ссылку на интерфейс `ParamsInterface`:

        ParamsInterface cryptParams = AlgIdSpec.getDefaultCryptParams();

Получение набора параметров шифрования и установка параметров по умолчанию (будут использоваться в дальнейшем):

        /* получение всех допустимых идентификаторов параметров алгоритма шифрования*/

        Enumeration cryptOids = cryptParams.getOIDs();

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

        конструктор keyParams3 для класса AlgIdSpec*/

        OID cryptOid  = (OID)cryptOids.nextElement();

        /* изменение идентификатора параметров шифрования по умолчанию. Измененные таким образом

        параметры шифрования могут быть переданы в соответствующий

        конструктор keyParams4 для класса AlgIdSpec*/

        cryptOids.setDefault(cryptOid);

# Дополнительные возможности работы с сертификатами

Помимо возможности работы с сертификатами через стандартный интерфейс JCA, в криптопровайдере КриптоПро JCP реализованы некоторые дополнительные функции работы с сертификатами:

- генерация запроса на сертификат;

· отправка запроса серверу и получение от сервера соответствующего запросу сертификата;

· генерация самоподписанного сертификата.

Перечисленные операции осуществляются при помощи специального класса `GostCertificateRequest`. Данный класс реализует генерацию запросов и самоподписанных сертификатов в соответствии с алгоритмом подписи ГОСТ Р 34.10-2001 c алгоритмом хеширования ГОСТ Р 34.11-94. Ключи, в соответствии с которыми осуществляется генерацию запросов и самоподписанных сертификатов, также должны соответствовать алгоритму ГОСТ Р 34.10-2001 (способ генерации таких ключей описан выше). Возможна также генерация запросов и сертификатов для ключей обмена.

Структура запроса имеет следующий вид:

        CertificationRequest ::= SEQUENCE {

                certificationRequestInfo  SEQUENCE {

                    version                   INTEGER,

                    subject                   Name,

                    subjectPublicKeyInfo      SEQUENCE {

                            algorithm                 AlgorithmIdentifier,

                            subjectPublicKey          BIT STRING },

                    attributes                [0] IMPLICIT SET OF Attribute },

                signatureAlgorithm        AlgorithmIdentifier,

                signature                 BIT STRING}

Структура самоподписанного сертификата имеет следующий вид:

        Certificate  ::=  SEQUENCE  {

                tbsCertificate       TBSCertificate,

                signatureAlgorithm   AlgorithmIdentifier,

                signature            BIT STRING  }

        TBSCertificate  ::=  SEQUENCE  {

                version         [0]  Version DEFAULT v1,

                serialNumber         CertificateSerialNumber,

                signature            AlgorithmIdentifier,

                issuer               Name,

                validity             Validity,

                subject              Name,

                subjectPublicKeyInfo SubjectPublicKeyInfo,

                issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,

                                    -- If present, version shall be v2 or v3

                subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,

                                    -- If present, version shall be v2 or v3

                extensions      [3]  Extensions OPTIONAL

                                    -- If present, version shall be v3 --  }

        Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }

        CertificateSerialNumber  ::=  INTEGER

        Validity ::= SEQUENCE {

                notBefore      Time,

                notAfter       Time }

        Time ::= CHOICE {

                utcTime        UTCTime,

                generalTime    GeneralizedTime }

        UniqueIdentifier  ::=  BIT STRING

        SubjectPublicKeyInfo  ::=  SEQUENCE  {

                algorithm            AlgorithmIdentifier,

                subjectPublicKey     BIT STRING  }

        Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension

        Extension  ::=  SEQUENCE  {

                extnID      OBJECT IDENTIFIER,

                critical    BOOLEAN DEFAULT FALSE,

                extnValue   OCTET STRING  }

## Инициализация генератора запросов и сертификатов

Когда требуется создать запрос или сертификат сначала надо воспользоваться конструктором:

        GostCertificateRequest request = new GostCertificateRequest();

Установить способ использования ключа keyUsage можно методом `setKeyUsage()`, параметром передается int - битовая маска способов использования ключа. По умолчанию используется комбинация `DIGITAL_SIGNATURE` "цифровая подпись" и `NON_REPUDIATION` "неотрекаемость" или константа `SIGN_DEFAULT`, объединяющая два эти значения. Если Вы создаете запрос для ключа шифрования (т.е. для алгоритма "GOST3410DH") стоит добавить `KEY_ENCIPHERMENT` "шифрование ключей" и `KEY_AGREEMENT` "согласование ключей". Можно воспользоваться константой `CRYPT_DEFAULT` которая объединяет все четыре значения.

    int keyUsage = GostCertificateRequest.DIGITAL_SIGNATURE |

            GostCertificateRequest.NON_REPUDIATION |

            GostCertificateRequest.KEY_ENCIPHERMENT |

            GostCertificateRequest.KEY_AGREEMENT;

    request.setKeyUsage(keyUsage);

Добавить ExtendedKeyUsage "улучшенный ключ" можно методом `addExtKeyUsage()`. Параметр методу `addExtKeyUsage()` можно указывать массивом `int[]{1, 3, 6, 1, 5, 5, 7, 3, 4}` или можно строкой `"1.3.6.1.5.5.7.3.3"` или объектом типа `ru.CryptoPro.JCP.params.OID`. По умолчанию список будет пустым.

        request.addExtKeyUsage(GostCertificateRequest.INTS_PKIX_EMAIL_PROTECTION);

        request.addExtKeyUsage("1.3.6.1.5.5.7.3.2"); // "Проверка подлинности клиента"

Допустимые OIDы для ExtendedKeyUsage и номера битов маски keyUsage описаны в стандарте

В классе `GostCertificateRequest` определены следующие константы:

    public static final int[] INTS_PKIX_SERVER_AUTH = {1, 3, 6, 1, 5, 5, 7, 3, 1};

    public static final int[] INTS_PKIX_CLIENT_AUTH = {1, 3, 6, 1, 5, 5, 7, 3, 2};

    public static final int[] INTS_PKIX_CODE_SIGNING = {1, 3, 6, 1, 5, 5, 7, 3, 3};

    public static final int[] INTS_PKIX_EMAIL_PROTECTION = {1, 3, 6, 1, 5, 5, 7, 3, 4};

    public static final int[] INTS_PKIX_IPSEC_END_SYSTEM = {1, 3, 6, 1, 5, 5, 7, 3, 5};

    public static final int[] INTS_PKIX_IPSEC_TUNNEL = {1, 3, 6, 1, 5, 5, 7, 3, 6};

    public static final int[] INTS_PKIX_IPSEC_USER = {1, 3, 6, 1, 5, 5, 7, 3, 7};

    public static final int[] INTS_PKIX_TIME_STAMPING = {1, 3, 6, 1, 5, 5, 7, 3, 8};

    public static final int[] INTS_PKIX_OCSP_SIGNING = {1, 3, 6, 1, 5, 5, 7, 3, 9};

При необходимости можно в запрос добавить собственное расширение, помимо KeyUsage и ExtendedKeyUsage. Пример добавления расширения основные ограничения BasicConstraints в запрос:

        Extension ext = new Extension();

        int[] extOid = {2, 5, 29, 19};

        ext.extnID = new Asn1ObjectIdentifier(extOid);

        ext.critical = new Asn1Boolean(true);

        byte[] extValue = {48, 6, 1, 1, -1, 2, 1, 5};

        ext.extnValue = new Asn1OctetString(extValue);

        request.addExtension(ext);

Такое расширение автоматически добавляется в сертификат при генерации самоподписанного сертификата (без обращения к центру сертификации) методами класса `GostCertificateRequest` Это расширение имеет значения "Тип субъекта = ЦС", "Ограничение на длину пути = 5" и является критическим.

Использовать метод `addExtension()` для установки в запрос KeyUsage и ExtendedKeyUsage нельзя, для этого надо воспользоваться методами `setKeyUsage()` и `addExtKeyUsage()`

Использовавшийся ранее для инициализации объектов типа `GostCertificateRequest` метод init

         request.init("GOST3410"); // JCP.GOST_DEGREE_NAME - для ключей подписи,

и

         request.init("GOST3410DH", isServer); // JCP.GOST_DH_NAME - для ключей обмена.

начиная с версии 1.0.48 объявлен deprecated и не рекомендуется к использованию. Вызов `init("GOST3410")` эквивалентен вызову

        request.setKeyUsage( GostCertificateRequest.SIGN_DEFAULT);

Вызов `init``("``GOST` `3410` `DH``",` `isServer``)` эквивалентен двум вызовам

        request.setKeyUsage( GostCertificateRequest.CRYPT_DEFAULT);

        request.addExtKeyUsage(GostCertificateRequest.INTS_PKIX_CLIENT_AUTH);

        request.addExtKeyUsage(GostCertificateRequest.INTS_PKIX_SERVER_AUTH); // только для сервера

или трем, если второй параметр метода `init()` установлен в true.

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

Пример генерации запроса на сертификат, отправки запроса центру и получения сертификата, соответствующего запросу от центра см. samples/samples_src.jar/userSamples/Certificates.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

## Генерация запроса на сертификат

Для генерации запроса на сертификат при помощи класса `GostCertificateRequest` необходимо выполнить следующую последовательность действий:

### Определение параметров ключа проверки ЭП субъекта

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

        PublicKey publicKey;

        request.setPublicKeyInfo(publicKey);

Ключ проверки ЭП`publicKey` должен соответствовать алгоритму, которым был проинициализирован генератор.

Функция setPublicKeyInfo() позволяет переустанавливать значение и параметры ключа проверки ЭП, в соответствии с которым создается запрос на сертификат. Но такие изменения допустимы лишь до тех пор, пока запрос не был подписан. В противном случае этот метод выбросит исключение.

### Определение имени субъекта

Для осуществления генерации запроса на сертификат объекту типа `GostCertificateRequest` следует передать всю необходимую информацию о субъекте (ключ проверки ЭП и имя). Определение имени субъекта осуществляется при помощи метода setSubjectInfo(), которому в качестве параметра передается строковое представление имени в соответствии со стандартом X.500 :

        String name = "CN=Ivanov, OU=Security, O=CryptoPro, C=RU";

        request.setSubjectInfo(name);

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

### Кодирование и подпись запроса

После того, как все необходимые данные о субъекте внесены (ключ проверки ЭП и имя), осуществляется непосредственно генерация запроса, заключающееся в подписи переданных объекту типа `GostCertificateRequest` данных и их кодировании. Эта операция осуществляется при помощи метода encodeAndSign(), которому в качестве параметра передается ключ ЭП, используемый для подписи запроса на сертификат:

        PrivateKey privateKey;

        request.encodeAndSign(privateKey);

Передаваемый ключ ЭП `privateKey` должен соответствовать алгоритму, которым был проинициализирован генератор. Каждый создаваемый запрос может быть подписан лишь один раз. При попытке вызова этой функции повторно сгенерируется исключение. В результате вызова функции encodeAndSign() запрос представляется приобретает описанный выше вид, и в памяти он хранится в DER-кодировке.

### Печать подписанного запроса

После того, как запрос был подписан и закодирован (другими словами, сгенерирован), требуется получить его из памяти. Класс `GostCertificateRequest` позволяет получать запрос в трех видах:

        PrintStream stream;                    // выходной поток, в который печатается

                                               // сформированный запрос

        request.printToDER(stream);            // записывается в поток в DER-кодировке

        request.printToBASE64(stream);         // записывается в поток в BASE64-кодировке

        byte[] encoded = request.getEncoded(); // возвращается в виде байтового

                                               // массива в DER-кодировке

Таким образом, сформированный запрос может быть получен как в DER-кодировке, так и в BASE64-кодировке. Запрос может быть записан либо в поток, либо в байтовый массив.

Запись в поток удобна в тех случаях, когда запрос требуется сохранить в некоторый файл (метод printToDER() сохраняет запрос в DER-кодировке, а метод printToBASE64() - в BASE64-кодировке). Если же предполагается дальнейшее использование данного запроса (например, отправка его центру сертификации), то удобнее его получать в виде байтового массива при помощи метода getEncoded().

## Отправка запроса центру сертификации и получение соответствующего запросу сертификата от центра

После того, как запрос был создан, его можно отправить центру сертификации для получения соответствующего запросу сертификата. Класс `GostCertificateRequest` позволяет осуществить эту операцию различными способами:

### Получение сертификата непосредственно после генерации запроса

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

        String httpAddress = "http://www.cryptopro.ru/certsrv/";

        byte[] encodedCert = request.getEncodedCert(httpAddress);

Полученный таким образом закодированный в DER-кодировке сертификат может в дальнейшем использоваться стандартными средствами JCA (например, функциями класса CertificateFactory).

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

### Получение сертификата из запроса, представленного в DER-кодировке

Сохраненный в DER-кодировке запрос может быть отправлен центру сертификации для получения запрашиваемого сертификата при помощи статического метода getEncodedCertFromDER() двумя способами:

        String httpAddress = "http://www.cryptopro.ru/certsrv/";

        InputStrean stream;    // входной поток, в который записан

                               // запрос в DER-кодировке

        byte[] encoded;        // DER-закодированный запрос

        byte[] encodedCert =

            GostCertificateRequest.getEncodedCertFromDER(httpAddress, stream);

        byte[] encodedCert =

            GostCertificateRequest.getEncodedCertFromDER(httpAddress, encoded);

Оба вызова метода getEncodedCertFromDER() получают в качестве одного из параметров http-адрес центра сертификации и возвращают закодированный в DER-кодировке сертификат, соответствующий подписанному запросу, в виде байтового массива.

Полученный таким образом закодированный в DER-кодировке сертификат может в дальнейшем использоваться стандартными средствами JCA (например, функциями класса CertificateFactory).

Разница заключается в том, что первому способу вызова функции getEncodedCertFromDER() в качестве параметра передается входной поток, в который записан закодированный в DER-кодировке запрос. Такой поток обычно направлен на файл, содержащий запрос. Запись же запроса в файл может быть осуществлена при помощи метода printToDER() класса `GostCertificateRequest` (подробнее см. сохранение запроса). Второму же способу вызова функции getEncodedCertFromDER() в качестве параметра передается байтовый массив, содержащий в себе DER-закодированный запрос. Такой массив может быть получен при помощи метода getEncoded() класса `GostCertificateRequest` (подробнее см. сохранение запроса).

### Получение сертификата из запроса, представленного в BASE64-кодировке

Сохраненный в BASE64-кодировке запрос может быть отправлен центру сертификации для получения запрашиваемого сертификата при помощи статического метода getEncodedCertFromDER() следующим образом:

        String httpAddress = "http://www.cryptopro.ru/certsrv/";

        InputStrean stream;     // входной поток, в который записан

                                // запрос в BASE64-кодировке

        byte[] encodedCert =

            GostCertificateRequest.getEncodedCertFromBASE64(httpAddress, stream);

Метод getEncodedCertFromBASE64() получает в качестве параметров http-адрес центра сертификации и входной поток, в который записан закодированный в BASE64-кодировке запрос. Такой поток обычно направлен на файл, содержащий запрос. Запись же запроса в файл может быть осуществлена при помощи метода printToBASE64() класса `GostCertificateRequest` (подробнее см. сохранение запроса). Метод getEncodedCertFromBASE64() возвращает закодированный в DER-кодировке сертификат, соответствующий подписанному запросу, в виде байтового массива.

Полученный таким образом закодированный в DER-кодировке сертификат может в дальнейшем использоваться стандартными средствами JCA (например, функциями класса CertificateFactory).

### Получение корневого сертификата центра сертификации

После того, как соответствующий запросу сертификат был получен от центра, зачастую требуется выполнить построение цепочки сертификатов, начинающейся с корневого сертификата центра, и заканчивающейся полученным от этого центра сертификатом. Класс `GostCertificateRequest` позволяет получать корневой сертификат центра сертификации при помощи статического метода getEncodedRootCert() следующим образом:

        String httpAddress = "http://www.cryptopro.ru/certsrv/";

        byte[] encodedRootCert =

            GostCertificateRequest.getEncodedRootCert(httpAddress);

Функция getEncodedRootCert() получает в качестве параметра http-адрес центра сертификации и возвращает закодированный в DER-кодировке корневой сертификат центра в виде байтового массива.

Полученный таким образом закодированный в DER-кодировке корневой сертификат `encodedRootCert` может в дальнейшем быть обработан функциями класса CertificateFactory, и после может использоваться, например, для построения цепочек. Обработанный такой сертификат может быть добавлен в хранилище доверенных сертификатов.

Пример генерации запроса на сертификат, отправки запроса центру и получения сертификата, соответствующего запросу от центра см. samples/samples_src.jar/userSamples/Certificates.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

## Генерация самоподписанного сертификата

Для осуществления сохранения ключа ЭП на носитель совместно с ключом ЭП также требуется сертификат ключа проверки ЭП, соответствующего ключу ЭП. Для генерации таких сертификатов удобно пользоваться методом getEncodedSelfCert() класса `GostCertificateRequest`. Эта функция получает в качестве параметра ключевую пару субъекта (он же издатель), а также имя субъекта (оно же имя издателя). Передаваемая ключая пара должна соответствовать алгоритму, которым был проинициализирован генератор. Сертификат возвращается в DER-кодировке в виде байтового массива.

После того, как объект класса `GostCertificateRequest` проинициализирован, осуществляется собственно генерация сертификата:

         KeyPair pair;    // ключевая пара субъекта (она же пара издателя)

         String name;     // имя субъекта (оно же имя издателя)

         byte[] encodedCert =

             request.getEncodedSelfCert(pair, name);

Полученный таким образом закодированный в DER-кодировке самоподписанный сертификат `encodedCert` может в дальнейшем быть обработан функциями класса CertificateFactory, и после может использоваться, например, для записи ключа ЭП на носитель.

При генерации самоподписанного сертификата (без обращения к центру сертификации) методами класса `GostCertificateRequest` ему проставляются те же расширения, что и при генерации запроса, а также расширение basicConstraints - основные ограничения. Это расширение имеет значения "Тип субъекта = ЦС", "Ограничение на длину пути = 5" и является критическим.

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

Пример генерации самоподписанного сертификата см. samples/samples_src.jar/userSamples/KeyPairGen.java (входит в комплект поставки программного обеспечения КриптоПро JCP).

# Работа с электронной подписью для XML-документов

Криптопровайдер КриптоПро JCP обеспечивает формирование и проверку ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001 для отдельного объекта XML-документа, для всего XML-документа, а также для двух независимых подписей всего XML-документа.

Криптопровайдер КриптоПро JCP позволяет осуществлять формирование и проверку электронной подписи XML-документа в соответствии с алгоритмом ГОСТ Р 34.10-2001. При этом криптопровайдер КриптоПро JCP использует четыре библиотеки, обеспечивающие работу с электронной подписью XML-документов:

commons-logging.jar

serializer.jar

xalan.jar

xmlsec.jar

Для корректной работы криптопровайдера все эти библиотеки должны быть скачены с сайта http://www.apache.org. Рекомендуется воспользоваться ссылкой http://xml.apache.org/mirrors.cgi, выбирая последнюю версию продукта.

Основные операции осуществляются при помощи функций следующих классов: org.apache.xml.security.algorithms, org.apache.xml.security.exceptions, org.apache.xml.security.keys, org.apache.xml.security.signature, org.apache.xml.security.transforms, org.apache.xml.security.utils. Поскольку криптопровайдер КриптоПро JCP не реализует методы перечисленных выше пакетов, а лишь обеспечивает их поддержку для алгоритма подписи ГОСТ Р 34.10-2001, то в данной документации подробное описание этих методов не приводится.

Перед началом использования классов из библиотеки XML Security необходимо зарегистрировать ГОСТ алгоритмы. Сделать это можно двумя способами:

Во-первых, вызовом метода `ru.CryptoPro.JCPxml.XmlInit.init()` (старый метод `ru.CryptoPro.JCPxml.xmldsig.JCPXMLDSigInit.init()` тоже поддерживается).

Во-вторых, вызовом стандартного инициализатора `org.apache.xml.security.Init.init()`, который обязателен при работе с библиотекий XML Security, но с предварительно установленным свойством `System.setProperty("org.apache.xml.security.resource.config", "resource/jcp.xml")` или указывая это свойство при запуске Java-машины следующим образом: `java -Dorg.apache.xml.security.resource.config=resource/jcp.xml.` Таким образом, регистрация ГОСТ алгоритмов не требует перекомпиляции приложения. Соответствующие константы определены в файле ru.CryptoPro.JCPxml.Consts

    /**

     * имя Property настройки конфигурации.

     */

    public static final String PROPERTY_NAME = "org.apache.xml.security.resource.config";

    /**

     * Имя ресурса конфигурации.

     */

    public static final String CONFIG = "resource/jcp.xml";

    /**

     * алгоритм подписи (ГОСТ Р 34.10-2001)

     */

    public static final String URI_GOST_SIGN = "http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411";

    /**

     * алгоритм хеширования, используемый при подписи (ГОСТ Р 34.11-94)

     */

    public static final String URI_GOST_DIGEST = "http://www.w3.org/2001/04/xmldsig-more#gostr3411";

    /**

     * алгоритм подписи (ГОСТ Р 34.10-2001) по новому стандарту

     */

    public static final String URN_GOST_SIGN = "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34102001-gostr3411";

    /**

     * алгоритм хеширования, ГОСТ Р 34.11-94  по новому стандарту

     */

    public static final String URN_GOST_DIGEST = "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr3411";

Для идентификации российских алгоритмов подписи и хеширования внутри XML в КриптоПро CSP 2.0, 3.0, 3.6 и ранних версиях КриптоПро JCP использовались следущие пространства имен: Для алгоритма хеширования использовалось пространство имен `http://www.w3.org/2001/04/xmldsig-more#gostr3411`, а для алгоритма подписи `http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411`. Эти пространства имен использовать не рекомендуется, хотя работоспособность полностью сохранена для совместимости. С появлением нового проекта стандарта рекомендуется использовать для алгоритма подписи `urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34102001-gostr3411` и для алгоритма хеширования `urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr3411`.

На основе методов перечисленных выше пакетов криптопровайдер КриптоПро JCP позволяет осуществлять формирование подписи как отдельного объекта XML-документа, так и всего содержимого XML-документа (соответственно, проверку подписи как объекта, так и всего содержимого документа). Помимо этого существует возможность формирования и проверки двух независимых подписей одного XML-документа. Все перечисленные способы создания и проверки электронной подписи XML-документа для алгоритма ГОСТ Р 34.10-2001 подробно описываются в примерах, которые входят в комплект поставки программного обеспечения КриптоПро JCP (`samples/samples_src.jar/xmlSign/`).

Внимание! Библиотека JCPxml.jar должна находиться вместе с библиотекой xmlsec.jar, так чтобы ClassLoader при загрузке класса, реализующего алгоритм ГОСТ из библиотеки JCPxml.jar, имел доступ к базовому классу, который находится в библиотеке xmlsec.jar. Например, если серверное приложение, которое должно проверять подпись, запущено на сервере J2EE и включает в себя библиотеку xmlsec.jar, а JCPxml.jar установлена в lib/ext, появится конфликт, который сделает невозможной подпись/проверку. Системный ExtClassLoader, который осуществляет загрузку из lib/ext, не будет иметь доступ к базовому классу и не сможет загрузить классы из JCPxml.jar. В свою очередь ClassLoader приложения (WebappClassLoader) не будет иметь доступ к классам из JCPxml.jar. Для устранения конфликта можно переложить библиотеку JCPxml.jar в приложение к библиотеке xmlsec.jar.

# КриптоПро JCP и Cryptographic Message Syntax (CMS)

Криптопровайдер КриптоПро JCP позволяет осуществить формирование и проверку ЭП в соответствии с алгоритмом подписи ГОСТ Р 34.10-2001 и алгоритмом хеширования ГОСТ Р 34.11-94 для сообщений, созданных на основе Cryptographic Message Syntax (CMS).

Примеры создания и подписи сообщений CMS, а также проверки подписи входят в комплект поставки программного обеспечения КриптоПро JCP (`samples/samples_src.jar/CMS_samples/`). В соответствии с Cryptographic Message Syntax подпись может быть 2х видов: подпись на данные и подпись на подписываемые атрибуты подписи (если они существуют (см. CMS)), что и реализовано в примерах.

## Особенности встречной работы при использовании CAPICOM и Java Script

При использовании скрипта `samples/samples_src.jar/CMS_samples/CSignData.js` (или аналогичного на VBS из примеров к CSP) для создания отделенной подписи следует помнить, что скрипт при чтении данных кодирует их в UTF-16LE кодировку. Поэтому для проверки такой подписи из java (см. примеры) следует данные (content) закодировать в UTF-16LE. Соответственно для проверки отделенной подписи сгенерированной в java с помощью скрипта необходимо, чтобы подпись была на закодированные в UTF-16LE кодировку данные (см. `samples/samples_src.jar/CMS_samples/CSignDataUse.java`).

# Использование утилиты keytool

При работе криптопровайдером КриптоПро JCP операции

- генерации ключа ЭП с алгоритмом ГОСТ Р 34.10-2001 и соответствующего ему самоподписанного сертификата с записью их на один из носителей;
- генерации запроса на сертификат ключа проверки ЭП в соответствии с хранящимся на носителе ключом ЭП;
- генерации самоподписанного сертификата ключа проверки ЭП в соответствии с хранящимся на носителе ключом ЭП и запись сертификата на носитель;
- чтение сертификата ключа проверки ЭП с носителя и запись его в файл;
- чтение сертификата ключа проверки ЭП из файла и запись его на носитель в соответствии с хранящимся на носителе ключом ЭП;
- чтение доверенного сертификата из хранилища и запись его в файл;
- чтение доверенного сертификата из файла и запись его в хранилище

могут осуществляться не только через стандартный интерфейс JCA, но также при помощи утилиты keytool.

При генерации самоподписанного сертификата при помощи утилиты keytool никакие расширения сертификату не проставляются. Для генерации сертификатов с расширениями следует воспользоваться методами класса `GostCertificateRequest` (см. выше).

Ниже приводятся примеры осуществления перечисленных операций при помощи данной утилиты.

## Просмотр содержимого ключевого носителя и соответствующего ему хранилища доверенных сертификатов

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

Просмотр содержимого осуществляется при помощи команды `-list`, которой в качестве параметров передаются:

- тип провайдера (КриптоПро JCP): `-provider` `ru.CryptoPro.JCP.JCP`

· имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`

· путь к хранилищу доверенных сертификатов, проинициализированному именем носителя: `-keystore` `c:\.keystore`

· пароль на хранилище доверенных сертификатов: `-storepass` `123456`

Таким образом, просмотр содержимого носителя и соответствующего ему хранилища доверенных сертификатов осуществляется:

        keytool -list -provider ru.CryptoPro.JCP.JCP -storetype HDImageStore -keystore c:\.keystore

            -v -storepass 123456

## Генерация ключа и соответствующего ему самоподписанного сертификата и запись их на носитель

В данном примере осуществляется генерация ключа ЭП и соответствующего ему самоподписанного сертификата в соответствии с алгоритмом ГОСТ Р 34.10-2001 и запись их на носитель.

Генерация и запись ключа и сертификата осуществляется при помощи команды `-genkey`, которой в качестве параметров передаются:

- уникальное имя создаваемого ключа и соответствующего ему сертификата: `-alias` `myKey`
- длина создаваемого ключа (в соответствии с алгоритмом ГОСТ Р 34.10.2001): `-keysize` `512`
- тип провайдера (КриптоПро JCP): `-provider` `ru.CryptoPro.JCP.JCP`
- пароль на записываемый ключ: `-keypass` `11111111`
- имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`
- имя создаваемого сертификата по стандарту X.500: `-dname` `CN=myKey,O=CryptoPro,C=RU`
- путь к хранилищу доверенных сертификатов, проинициализированному именем носителя: `-keystore` `c:\.keystore`
- пароль на хранилище доверенных сертификатов: `-storepass` `123456`
- алгоритм генерации ключа ЭП (ГОСТ Р 34.10-2001): `-keyalg` `GOST3410`
- алгоритм подписи сертификата (ГОСТ Р 34.10-2001): `-sigalg` `GOST3411withGOST3410EL`

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

        keytool -genkey -alias myKey -keysize 512 -provider ru.CryptoPro.JCP.JCP -keypass 11111111 -storetype HDImageStore

            -dname CN=myKey,O=CryptoPro,C=RU -keystore c:\.keystore -storepass 123456 -keyalg GOST3410

            -sigalg GOST3411withGOST3410EL

## Генерация ключевой пары запись ее на носитель

В данном примере осуществляется генерация ключевой пары в соответствии с алгоритмом ГОСТ Р 34.10-2001 и запись ее на носитель.

Генерация и запись ключевой пары осуществляется при помощи команды `-genkeypair`, которой в качестве параметров передаются:

- уникальное имя создаваемого ключа и соответствующего ему сертификата: `-alias` `myKey`
- длина создаваемого ключа (в соответствии с алгоритмом ГОСТ Р 34.10.2001): `-keysize` `512`
- имя провайдера (КриптоПро JCP): `-providername` `JCP`
- имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`
- алгоритм генерации ключа ЭП (ГОСТ Р 34.10-2001): `-keyalg` `GOST3410`
- алгоритм подписи сертификата (ГОСТ Р 34.10-2001): `-sigalg` `GOST3411withGOST3410EL`

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

        keytool -genkeypair -alias myKey -keysize 512 -providername JCP -storetype HDImageStore

            -keyalg GOST3410

            -sigalg GOST3411withGOST3410EL

## Генерация запроса на сертификат ключа проверки ЭП в соответствии с хранящимся на носителе ключом ЭП и запись запроса в файл

В данном примере осуществляется генерация запроса на сертификат ключа проверки ЭП в соответствии с хранящимся на носителе ключом ЭП и запись запроса в файл.

Генерация и запись в файл запроса осуществляется при помощи команды `-certreq`, которой в качестве параметров передаются:

- уникальное имя ключа ЭП на носителе, в соответствии с которым осуществляется генерация запроса на сертификат: `-alias` `myKey`
- тип провайдера (КриптоПро JCP): `-provider` `ru.CryptoPro.JCP.JCP`
- пароль на ключ ЭП: `-keypass` `11111111`
- имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`
- путь к хранилищу доверенных сертификатов, проинициализированному именем носителя: `-keystore` `c:\.keystore`
- пароль на хранилище доверенных сертификатов: `-storepass` `123456`
- алгоритм подписи запроса на сертификат (ГОСТ Р 34.10-2001): `-sigalg` `GOST3411withGOST3410EL`
- путь к файлу для записи в него запроса: `-file` `c:\request.bin`

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

        keytool -certreq -alias myKey -provider ru.CryptoPro.JCP.JCP -keypass 11111111 -storetype HDImageStore

            -keystore c:\.keystore -storepass 123456 -sigalg GOST3411withGOST3410EL -file c:\request.bin

## Генерация самоподписанного сертификата ключа проверки ЭП в соответствии с хранящимся на носителе ключом ЭП и запись сертификата на носитель

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

Генерация и запись на носитель самоподписанного сертификата осуществляется при помощи команды `-selfcert`, которой в качестве параметров передаются:

- уникальное имя ключа ЭП на носителе, в соответствии с которым осуществляется генерация самоподписанного сертификата: `-alias` `myKey`
- тип провайдера (КриптоПро JCP): `-provider` `ru.CryptoPro.JCP.JCP`
- пароль на ключ ЭП: `-keypass` `11111111`
- имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`
- путь к хранилищу доверенных сертификатов, проинициализированному именем носителя: `-keystore` `c:\.keystore`
- пароль на хранилище доверенных сертификатов: `-storepass` `123456`
- алгоритм подписи сертификата (ГОСТ Р 34.10-2001): `-sigalg` `GOST3411withGOST3410EL`
- имя создаваемого сертификата по стандарту X.500: `-dname` `CN=myKey,O=CryptoPro,C=RU`

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

    keytool -selfcert -alias myKey -provider ru.CryptoPro.JCP.JCP -keypass 11111111 -storetype HDImageStore

        -keystore c:\.keystore -storepass 123456 -sigalg GOST3411withGOST3410EL -dname CN=myKey,O=CryptoPro,C=RU

## Чтение сертификата ключа проверки ЭП с носителя и запись его в файл

В данном примере осуществляется чтение сертификата ключа проверки ЭП с носителя и запись сертификата в файл.

Чтение сертификата ключа проверки ЭП с носителя и запись его в файл осуществляется при помощи команды `-export`, которой в качестве параметров передаются:

- уникальное имя читаемого с носителя сертификата ключа проверки ЭП: `-alias` `myKey`
- тип провайдера (КриптоПро JCP): `-provider` `ru.CryptoPro.JCP.JCP`
- имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`
- путь к хранилищу доверенных сертификатов, проинициализированному именем носителя: `-keystore` `c:\.keystore`
- пароль на хранилище доверенных сертификатов: `-storepass` `123456`
- путь к файлу для записи в него сертификата: `-file` `c:\myKeyCert.cer`

Таким образом, чтение сертификата ключа проверки ЭП с носителя и запись сертификата в файл осуществляется:

    keytool -export -alias myKey -provider ru.CryptoPro.JCP.JCP -storetype HDImageStore  -keystore c:\.keystore

        -storepass 123456 -file c:\myKeyCert.cer

## Чтение сертификата ключа проверки ЭП из файла и запись его на носитель в соответствии с хранящимся на носителе ключом ЭП

В данном примере осуществляется чтение сертификата ключа проверки ЭП из файла и запись его на носитель в соответствии с хранящимся на носителе ключом ЭП.

Чтение сертификата ключа проверки ЭП из файла и запись его на носитель осуществляется при помощи команды `-import`, которой в качестве параметров передаются:

- уникальное имя ключа ЭП на носителе, в соответствии с которым на носитель записывается сертификат: `-alias` `myKey`
- тип провайдера (КриптоПро JCP): `-provider` `ru.CryptoPro.JCP.JCP`
- пароль на ключ ЭП: `-keypass` `11111111`
- имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`
- путь к хранилищу доверенных сертификатов, проинициализированному именем носителя: `-keystore` `c:\.keystore`
- пароль на хранилище доверенных сертификатов: `-storepass` `123456`
- путь к файлу для чтения из него сертификата: `-file` `c:\myKeyCert.cer`

Таким образом, чтение сертификата ключа проверки ЭП из файла и запись его на носитель в соответствии с хранящимся на носителе ключом ЭП осуществляется:

        keytool -import -alias myKey -provider ru.CryptoPro.JCP.JCP -keypass 11111111 -storetype HDImageStore

            -keystore c:\.keystore -storepass 123456 -file c:\myKeyCert.cer

## Чтение доверенного сертификата из хранилища и запись его в файл

В данном примере осуществляется чтение доверенного сертификата из хранилища и запись сертификата в файл.

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

- уникальное имя читаемого из хранилища доверенного сертификата (предполагается, что на носителе нет ключа с тем же именем): `-alias` `myCert`
- тип провайдера (КриптоПро JCP): `-provider` `ru.CryptoPro.JCP.JCP`
- имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`
- путь к хранилищу доверенных сертификатов, проинициализированному именем носителя: `-keystore` `c:\.keystore`
- пароль на хранилище доверенных сертификатов: `-storepass` `123456`
- путь к файлу для записи в него сертификата: `-file` `c:\myCert.cer`

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

    keytool -export -alias myCert -provider ru.CryptoPro.JCP.JCP -storetype HDImageStore  -keystore c:\.keystore

        -storepass 123456 -file c:\myCert.cer

## Чтение доверенного сертификата из файла и запись его в хранилище

В данном примере осуществляется чтение доверенного сертификата из файла и запись его в хранилище.

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

- уникальное записываемого сертификата (предполагается, что на носителе нет ключа с тем же именем): `-alias` `myCert`
- тип провайдера (КриптоПро JCP): `-provider` `ru.CryptoPro.JCP.JCP`
- имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`
- путь к хранилищу доверенных сертификатов, проинициализированному именем носителя: `-keystore` `c:\.keystore`
- пароль на хранилище доверенных сертификатов: `-storepass` `123456`
- путь к файлу для чтения из него сертификата: `-file` `c:\myCert.cer`

Таким образом, чтение сертификата ключа проверки ЭП из файла и запись его на носитель в соответствии с хранящимся на носителе ключом ЭП осуществляется:

        keytool -import -alias myCert -provider ru.CryptoPro.JCP.JCP -storetype HDImageStore -keystore c:\.keystore

            -storepass 123456 -file c:\myCert.cer

## Удаление ключа и соответствующего ему самоподписанного сертификата с носителя

В данном примере осуществляется удаление ключа ЭП и соответствующего ему самоподписанного сертификата с носителя.

Удаление ключа и соответствующего ему самоподписанного сертификата с носителя осуществляется при помощи команды `-delete`, которой в качестве параметров передаются:

- уникальное имя удаляемого ключа: `-alias` `myKey`
- тип провайдера (КриптоПро JCP): `-provider` `ru.CryptoPro.JCP.JCP`
- имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`
- путь к хранилищу доверенных сертификатов, проинициализированному именем носителя: `-keystore` `c:\.keystore`
- пароль на хранилище доверенных сертификатов: `-storepass` `123456`

Таким образом, удаление ключа ЭП и соответствующего ему самоподписанного сертификата с носителя осуществляется:

        keytool -delete -alias myKey -provider ru.CryptoPro.JCP.JCP -storetype HDImageStore -keystore c:\.keystore

            -v -storepass 123456

При удалении ключа с носителя, требующего пароля доступа к ключу на носителе при удалении (например, смарт-карте Оскар) в качестве имени необходимо передать строку состоящую из имени, 4 символов двоеточия, и пароля доступа к ключу. Таким образом, удаление ключа ЭП и соответствующего ему самоподписанного сертификата со смарт-карты Оскар осуществляется:

        keytool -delete -alias myKey::::12345678 -provider ru.CryptoPro.JCP.JCP -storetype OCFStore -keystore c:\.keystore

            -v -storepass 123456

## Удаление доверенного сертификата из хранилища

В данном примере осуществляется удаление доверенного сертификата из хранилища.

Удаление доверенного сертификата из хранилища осуществляется при помощи команды `-delete`, которой в качестве параметров передаются:

- уникальное имя удаляемого сертификата (предполагается, что на носителе нет ключа с тем же именем): `-alias` `myCert`
- тип провайдера (КриптоПро JCP): `-provider` `ru.CryptoPro.JCP.JCP`
- имя ключевого носителя (жесткий диск): `-storetype` `HDImageStore`
- путь к хранилищу доверенных сертификатов, проинициализированному именем носителя: `-keystore` `c:\.keystore`
- пароль на хранилище доверенных сертификатов: `-storepass` `123456`

Таким образом, удаление доверенного сертификата из хранилища осуществляется:

        keytool -delete -alias myCert -provider ru.CryptoPro.JCP.JCP -storetype HDImageStore -keystore c:\.keystore

            -v -storepass 123456

# Использование утилиты ComLine

Также можно воспользоваться готовыми классами пакета ComLine из модуля Samples, входящего в состав КриптоПро JCP. Запустите ComLine с вызовом нужного класса либо сам класс, используя следующие параметры командной строки:

`java` `ComLine NameofClass args` или `java NameofClass args`

например:

    java ComLine KeyPairGen -alias name_of_key -dname CN=autor,OU=Security,O=CryptoPro,C=RU -reqCertpath C:/req.txt

или

    java KeyPairGen -alias name_of_key -dname CN=autor,OU=Security,O=CryptoPro,C=RU -reqCertpath C:/req.txt

## Проверка установки и настроек провайдеров.

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

    CheckConf (без параметров)

## Проверка работоспособности провайдеров.

Запуском:

    CheckConfFull [-servDir C:/*.*]

-servDir

рабочая директория

(по умолчанию текущая)

можно проверить работоспособность провайдеров.

Выполняются тесты на генерацию ключей, генерацию и проверку подписи, а также тесты на создание ssl-соединения (если установлен КриптоПро JTLS). (Запуск возможен при условии, что КриптоПро JCP был установлен успешно).

## Работа с ключами и сертификатами

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

Генерация ключевой пары осуществляется в соответствии с алгоритмами обмена Диффи-Хелмана и подписи ГОСТ Р 34.10-2001.

    KeyPairGen -alias name_of_key [-alg GOST3410] [-storetype HDImageStore] [-storepath null] [-storepass null]

        [-keypass password] [-isServer true] -dname CN=autor,OU=Security,O=CryptoPro,C=RU -reqCertpath C:/*.* -encoding der

-alias

уникальное имя записываемого ключа

-alg

алгоритм для генерации

(по умолчанию GOST3410)

-storetype

имя ключевого носителя HDImageStore (жесткий диск), FloppyStore (дискета), OCFStore или J6CFStore (карточки)

(по умолчанию HDImageStore)

-storepath

путь к хранилищу доверенных сертификатов

(по умолчанию null)

-storepass

пароль на хранилище доверенных сертификатов

(по умолчанию null)

-keypass

пароль на записываемый ключ

(по умолчанию null)

-isServer

если ключ серверный, то значение true

(по умолчанию false)

-dname

имя субъекта для генерации самоподписанного сертификата

-encoding

кодировка (DER/BASE64)

(по умолчанию DER)

-reqCertpath

путь для записи запроса

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

### Получение сертификата из запроса. Запись сертификата в хранилище и в файл.

    getCert -alias name_of_key [-storetype HDImageStore] [-storepath null]

        [-storepass null] -http http://www.cryptopro.ru/certsrv/ -certpath C:/*.cer -reqCertpath C:/*.*

-alias

уникальное имя ключа

-storetype

имя ключевого носителя HDImageStore (жесткий диск), FloppyStore (дискета), OCFStore или J6CFStore (карточки)

(по умолчанию HDImageStore)

-storepath

путь к хранилищу доверенных сертификатов

(по умолчанию null)

-storepass

пароль на хранилище доверенных сертификатов

(по умолчанию null)

-http

путь к центру сертификации

-reqCertpath

путь к файлу с запросом

-encoding

кодировка запроса (DER/BASE64)

(по умочанию DER)

-сertpath

путь к файлу для записи сертификата

### Построение цепочки сертификатов.

    Certs -alias name_of_key [-storetype HDImageStore] [-storepath null] [-storepass null]

        [-keypass password] -certs C:/my.cer,C:/*.cer,...,C:/root.cer

-alias

уникальное имя ключа

-keypass

пароль на ключ

(по умолчанию null)

-storetype

имя ключевого носителя HDImageStore (жесткий диск), FloppyStore (дискета), OCFStore или J6CFStore (карточки)

(по умолчанию HDImageStore)

-storepath

путь к хранилищу доверенных сертификатов

(по умолчанию null)

-storepass

пароль на хранилище доверенных сертификатов

(по умолчанию null)

-сerts

пути к сертификатам

### Формирование электронной подписи.

Формирование электронной подписи осуществляется в соответствии с алгоритмом ГОСТ Р 34.10-2001.

    Signature -alias name_of_key [-storetype HDImageStore] [-storepath null] [-storepass null]

        [-keypass password] -signpath C:/*.* -filepath C:/*.*

-alias

уникальное имя ключа

-keypass

пароль на записываемый ключ

(по умолчанию null)

-storetype

имя ключевого носителя HDImageStore (жесткий диск), FloppyStore (дискета), OCFStore или J6CFStore (карточки)

(по умолчанию HDImageStore)

-storepath

путь к хранилищу доверенных сертификатов

(по умолчанию null)

-storepass

пароль на хранилище доверенных сертификатов

(по умолчанию null)

-signpath

путь к файлу подписи

-filepath

путь к подписываемому файлу

### Проверка электронной подписи.

Проверка электронной подписи осуществляется в соответствии с алгоритмами ГОСТ Р ГОСТ Р 34.10-2001.

    SignatureVerif -alias name_of_key [-storetype HDImageStore] [-storepath null] [-storepass null]

        -signpath C:/*.* -filepath C:/*.*

-alias

уникальное имя ключа

-keypass

пароль на записываемый ключ

(по умолчанию null)

-storetype

имя ключевого носителя HDImageStore (жесткий диск), FloppyStore (дискета), OCFStore или J6CFStore (карточки)

(по умолчанию HDImageStore)

-storepath

путь к хранилищу доверенных сертификатов

(по умолчанию null)

-storepass

пароль на хранилище доверенных сертификатов

(по умолчанию null)

-signpath

путь к файлу подписи

-filepath

путь к проверяемому файлу

## Использование КриптоПро JTLS

### Запуск сервера из командной строки.

    Server [-port port] [-auth true] [-keyStoreType HDImageStore] [-trustStoreType HDImageStore] -trustStorePath C:/*.*

        -trustStorePassword trust_pass -keyStorePassword key_pass

-port

порт сервера

(по умолчанию 443)

-auth

нужна ли аутентификация клиента

(по умолчанию false)

-keyStoreType

тип ключевого носителя HDImageStore (жесткий диск), FloppyStore (дискета), OCFStore или J6CFStore (карточки)

(по умолчанию HDImageStore)

-trustStoreType

тип носителя для хранилища доверенных сертификатов HDImageStore (жесткий диск), FloppyStore (дискета)

(по умолчанию HDImageStore)

-trustStorePath

путь к хранилищу доверенных сертификатов

-trustStorePassword

пароль на хранилище доверенных сертификатов

-keyStorePassword

пароль на ключ

-servDir

рабочая директория сервера

(по умолчанию текущая)

При запросе ресурса `shutdown` сервер останавливается, предварительно послав клиенту ответ, который содержит сообщение об остановке сервера по окончании сессии.

### Запуск клиента из командной строки.

    Client [-port port] [-server serverName] [-keyStoreType HDImageStore] [-trustStoreType HDImageStore] -trustStorePath C:/*.*

        -trustStorePassword trust_pass -keyStorePassword key_pass [-fileget gettingFileName] [-fileout outputFilePath]

-port

порт сервера

(по умолчанию 443)

-server

имя сервера

(по умолчанию localhost)

-keyStoreType

тип ключевого носителя HDImageStore (жесткий диск), FloppyStore (дискета), OCFStore или J6CFStore (карточки)

(по умолчанию HDImageStore)

-trustStoreType

тип носителя для хранилища доверенных сертификатов HDImageStore (жесткий диск), FloppyStore (дискета)

(по умолчанию HDImageStore)

-trustStorePath

путь к хранилищу доверенных сертификатов

-trustStorePassword

пароль на хранилище доверенных сертификатов

-keyStorePassword

пароль на ключ

-fileget

имя ресурса

(по умолчанию index.html)

-fileout

путь к файлу вывода

(по умолчанию out.html)

### Запуск клиента нагрузочного примера из командной строки (samples.jar/JTLS_samples/HighLoadExample).

    JTLS_samples.HighLoadExample -client [-port hostPort] [-host hostName] [-get sourcePage]
    [-t T] [-n N] -source sourceDir
    -store tempDir -trustStorePath C:/*.* [-trustStoreType trust_type] -trustStorePassword trust_pass
    [-keyStoreType keystoreType] [-keyStorePassword key_pass]
    [-ct X] [-external] [-apache4] [-trace] [-help]

При выполнении команды, возможно, потребуется указать параметры -Dcom.sun.security.enableCRLDP=true -Dcom.ibm.security.enableCRLDP=true для осуществления проверки цепочки сертификатов online.

-port

порт сервера

(по умолчанию 443)

-host

имя сервера

(по умолчанию 127.0.0.1)

-get

имя загружаемого ресурса

(по умолчанию default.htm)

-t

количество потоков (подключений)

(по умолчанию 2)

-n

количество запросов на поток (подключение)

(по умолчанию 2)

-source

папка с ресурсами для передачи сервером клиенту (пока не используется)

-store

папка для сохранения загружаемого ресурса

-trustStorePath

путь к хранилищу доверенных сертификатов

-trustStoreType

тип носителя для хранилища доверенных сертификатов HDImageStore (жесткий диск), FloppyStore (дискета)

(по умолчанию HDImageStore)

-trustStorePassword

пароль на хранилище доверенных сертификатов

-keyStoreType

тип ключевого носителя HDImageStore (жесткий диск), FloppyStore (дискета), OCFStore или J6CFStore (карточки)

(по умолчанию HDImageStore)

-keyStorePassword

пароль на ключ

-ct

таймаут работы потока клиента (сек.)

(по умолчанию 5 мин.)

-external

означает подключение к "внешнему" (не созданному в этом же примере) серверу

-apache4

означает использование apache http client 4.x вместо внутреннего класса Client. Библиотеки apache должны быть в каталоге lib/ext

-trace

означает подробный вывод в консоль

-help

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

### Запуск клиента на основе apache http client 4.x из командной строки (samples.jar/JTLS_samples/ApacheHttpClient4XExample).

    JTLS_samples.ApacheHttpClient4XExample [-port hostPort] [-host hostName] [-get sourcePage]
    [-allow] [-auth] [-save path]
    -trustStorePath C:/*.* [-trustStoreType trust_type] -trustStorePassword trust_pass
    [-keyStoreType keystoreType] [-keyStorePassword key_pass]
    [-help]

При выполнении команды, возможно, потребуется указать параметры -Dcom.sun.security.enableCRLDP=true -Dcom.ibm.security.enableCRLDP=true для осуществления проверки цепочки сертификатов online.

-port

порт сервера

(по умолчанию 443)

-host

имя сервера

(по умолчанию 127.0.0.1)

-get

имя загружаемого ресурса

(по умолчанию default.htm)

-save

полный путь для сохранения загруженного ресурса

-allow

для отключения проверки соответствия адреса ресурса и CN серверного сертификата

-auth

указывает на необходимость клиентской аутентификации

-trustStorePath

путь к хранилищу доверенных сертификатов

-trustStoreType

тип носителя для хранилища доверенных сертификатов HDImageStore (жесткий диск), FloppyStore (дискета)

(по умолчанию HDImageStore)

-trustStorePassword

пароль на хранилище доверенных сертификатов

-keyStoreType

тип ключевого носителя HDImageStore (жесткий диск), FloppyStore (дискета), OCFStore или J6CFStore (карточки)

(по умолчанию HDImageStore)

-keyStorePassword

пароль на ключ

-help

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

# Криптопровайдер JCSP. Особенности

В дистрибутив JCP входит библиотека JCSP.jar. JCSP - провайдер, аналогичный JCP, но осуществляющий все криптографические операции путем обращения в КриптоПро CSP (далее просто CSP), основной класс провайдера ru.CryptoPro.JCSP.JCSP. Криптопровайдер КриптоПро JCSP реализует стандартный интерфейс Java Cryptography Architecture (JCA) в соответствии с российскими криптографическими алгоритмами и в соответствии с этим интерфейсом обеспечивает выполнение тех же операций, что и JCP.

Для указания имени провайдера вместо JCP.PROVIDER_NAME следует использовать JCSP.PROVIDER_NAME. Ниже представлены основные отличия в реализации и использовании КриптоПро JCSP.

## Генерация ключевой пары ЭП в соответствии с алгоритмом ГОСТ

### Создание объекта генерации ключевой пары ЭП (генератора)

Для создания генератора ключевой пары ЭП в соответствии с алгоритмом ГОСТ Р 34.10-2001 методу getInstance() необходимо в качестве параметра передать имя, идентифицирующее данный алгоритм ("GOST3410" или JCP.GOST_DEGREE_NAME). При таком вызове метода getInstance() совместно с определением требуемого алгоритма генерации ключевой пары необходимо передавать имя криптопровайдера, используемого для выполнения требуемой операции, т.е. JCSP.PROVIDER_NAME. Таким образом, создание генератора ключевой пары ЭП осуществляется одним из следующих способов:

    KeyPairGenerator kg = KeyPairGenerator.getInstance("GOST3410", "JCSP");

    KeyPairGenerator kg = KeyPairGenerator.getInstance(JCP.GOST_DEGREE_NAME, JCSP.PROVIDER_NAME);

Отличительной особенностю JCSP является использование биологического датчика КриптоПро CSP при генерации ключевой пары. Генерация ключевой пары может происходить по одному из двух сценариев.

- создание временного контейнера и копирование в рабочий;
- создание рабочего контейнера.

### Определение параметров генерации ключевой пары ЭП

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

- стандартный

      KeyPairGenerator kg = KeyPairGenerator.getInstance(JCP.GOST_DEGREE_NAME, JCSP.PROVIDER_NAME);

      KeyPair keyPair = kg.generateKeyPair();

  В этом случае происходит создание временного контейнера с неким произвольным паролем и именем (алиасом) и ввод в стандартное окно ДСЧ CSP.

- с заданием алиаса контейнера

      KeyPairGenerator kg = KeyPairGenerator.getInstance(JCP.GOST_DEGREE_NAME, JCSP.PROVIDER_NAME);

      String container = KeyStoreConfig.getHDImage().makeContainerName(containerName); // Создание контейнера типа HDIMAGE с именем containerName

      AlgIdSpec params = new NameAlgIdSpec(container); // Параметры инициализации генератора

      kg.initialize(params);

      KeyPair keyPair = kg.generateKeyPair();

  В этом случае создается рабочий контейнер с именем containerName с вводом в стандартное окно ДСЧ CSP, в окне ввода и подтверждения пароля для контейнера указывается пин-код. Параметр container может содержать значение в формате FQCN, например, \\.\HDIMAGE\test.

  Если происходит генерация на алгоритме GOST3410DH, то требуется формировать параметры так:

      AlgIdSpec params = new NameAlgIdSpec(AlgIdSpec.getDHDefault(), container); // Параметры инициализации генератора GOST3410DH

      kg.initialize(params);

## Работа с ключевыми носителями

Провайдер JCSP осуществляет работу с теми носителями, которые поддерживаются КриптоПро CSP.

#### Определение типа используемого ключевого носителя

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

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

- имя "HDIMAGE" определяет жесткий диск;
- имя "REGISTRY" определяет реестр (ОС Windows);
- другие типы носителей.

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

         KeyStore ks = KeyStore.getInstance("HDIMAGE", "JCSP");

         KeyStore ks = KeyStore.getInstance("REGISTRY", "JCSP");

#### Запись ключа ЭП на носитель

После того, как содержимое носителя (и, если это требуется, содержимое проинициализированного именем носителя хранилища сертификатов) было загружено, осуществляется собственно запись ключа ЭП на носитель. Данная операция реализуется при помощи вызова метода setKeyEntry() или метода setEntry() класса KeyStore:

        String alias;       // идентификатор (уникальное имя) ключа и

                            // соответствующего ему сертификата

                            // ключа проверки ЭП

        PrivateKey key;     // ключ ЭП

                            // от пароля на хранилище, используемого при загрузке)

        Certificate[] chain;// цепочка сертификатов, начиная с корневого и

                            // и заканчивая сертификатом ключа ЭП,

                            // соответствующего ключу ЭП

        ks.setKeyEntry(alias, key, null, chain);

либо

        KeyStore.ProtectionParameter params = new KeyStore.PasswordProtection(password);

        KeyStore.Entry entry = new JCSPPrivateKeyEntry(key, chain);

        ks.setEntry(alias, entry, params);

В функцию setKeyEntry вместо пароля передается null, т.к. далее ввод пин-кода потребуется произвести в окне КриптоПро CSP; т.е. указание пароля непосредственно при вызове setKeyEntry излишне. Использование функции setEntry позволяет, наоборот, избежать ввода пин-кода в окне КриптоПро CSP, т.е. передать его программно.

При вызове setKeyEntry после генерации пары на неинициализированном рабочим контейнером генераторе произойдет создание рабочего контейнера с именем alias и типом keyStoreType, копирование в него закрытого ключа и сертификата из временного контейнера и удаление последнего. При создании контейнера появится стандартное окно КриптоПро CSP для ввода и подтверждения пароля на контейнер. При вызове данной функции после генерации пары на инициализированном генераторе, если alias соответствует containerName в генераторе, произойдет только установка сертификата, т.к. контейнер уже создан; если alias не соответствует containerName в генераторе, то произойдет копирование ключа и установка сертификата в новый рабочий контейнер alias с соответствующим вводом пин-кода и его подтверждением для данного контейнера.

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

- создание рабочего контейнера с именем alias и типом контейнера, копирование в него закрытого ключа и сертификата из временного контейнера и удаление последнего. При создании контейнера будет использован пароль из параметра ProtectionParameter функции setEntry;
- если alias соответствует containerName, то произойдет смена текущего пароля на тот, что указан в ProtectionParameter, и установка сертификата; если alias не соответствует containerName, то произойдет создание нового контейнера alias с паролем из ProtectionParameter и копирование в него ключа и сертификатов.

## Работа с хранилищем доверенных сертификатов

Работа с хранилищами доверенных сертификатов не поддерживается. Тип CertStore реализован только для чтения из хранилищ доверенных сертификатов для системы Google Android, где работа с ним осуществляется аналогично JCP, но без указания пароля.

## Чтение ключей ЭП с алгоритмом ГОСТ Р 34.10-2001 с ключевых носителей

Работа с ключевыми контейнерами в JCSP идентична работе с ними в JCP за исключением имени провайдера. Получить закрытый ключ (и сертификат) можно двумя способами:

- с помощью метода getKey класса KeyStore

          String alias;   // Идентификатор (уникальное имя) получаемого ключа ЭП

          PrivateKey key = (PrivateKey)ks.getKey(alias, null);

- воспользовавшись методом getEntry класса KeyStore

          String alias;   // Идентификатор (уникальное имя) получаемого ключа ЭП

          KeyStore.ProtectionParameter params = new KeyStore.PasswordProtection(password);

          JCSPPrivateKeyEntry entry = ks.getEntry(alias, params);

В метод getKey вместо пароля передается null, т.к. ввод пин-кода потребуется только при непосредственной работе с ключом; осуществляться ввод пароля будет в стандартном окне КриптоПро CSP. В метод getEntry пароль передается в виде параметра ProtectionParameter, при этом вводить пин-код (если он был правильным) в окне CSP в дальнейшем не потребуется. Это означает, что операции вида getKey/setKeyEntry используют ввод пин-кода в окне CSP, а функции getEntry/setEntry - нет.

## Дополнительные возможности работы с сертификатами

### Запись сертификата ключа проверки электронной подписи на ключевой носитель в соответствии с хранящемся на нем ключом ЭП

В провайдере JCSP установка отдельного сертификата в контейнер не поддерживается, метод setCertificateEntry не реализован.

### Инициализация генератора запросов и сертификатов

При генерации запроса на сертификат с помощью класса GostCertificateRequest следует указывать провайдер в конструкторе:

        GostCertificateRequest request = new GostCertificateRequest(JCSP.PROVIDER_NAME);

## Использование утилиты ComLine

При выполнении команды CheckConfFull происходит проверка всех установленных модулей, в том числе и JCSP. Проверки JCSP включают: выполнение пробной подписи и проверки подписи, генерацию ключей и создание хранилища доверенных сертификатов, зашифрование и расшифрование текста, соединение по протоколу TLS 1.0 с использованием клиентской аутентификации и без (JCSP + cpSSL).

## Особенности использования с другими модулями

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

        CAdESConfig.setDefaultDigestSignatureProvider("JCSP"); // класс CAdESConfig входит в пакет ru.CryptoPro.CAdES

        либо

        System.setProperty("ru.CryptoPro.defaultProv", "JCSP");

Контексты ключей, хешей, контейнера освобождаются в методах finalize() объектов соответствующих классов.