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

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

КриптоПро JCP
Версия 1.0


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

ЖТЯИ.00031-01 33 01


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

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

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

blank

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

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

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





Содержание

  1. Введение
  2. Использование основной функциональности криптопровайдера КриптоПро JCP через стандартный интерфейс JCA
  3. Работа с параметрами в криптопровайдере КриптоПро JCP
  4. Дополнительные возможности работы с сертификатами
  5. Работа с электронной цифровой подписью для XML-документов
  6. КриптоПро JCP и Cryptographic Message Syntax(CMS)
  7. Использование утилиты keytool
  8. Использование утилиты ComLine

Введение

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

Криптопровайдер КриптоПро JCP является средством криптографической защиты информации (СКЗИ КриптоПро JCP 1.0), реализующим российские криптографические алгоритмы и функционирующим под управлением виртуальной машины 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) в соответствии с российскими криптографическими алгоритмами и в соответствии с этим интерфейсом обеспечивает выполнение следующих операций:

Помимо перечисленных операций, осуществляемых в соответствии со стандартным интерфейсом 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-94 и ГОСТ Р 34.10-2001. Запись и чтение сертификатов открытых ключей допустимы для обоих алгоритмов и удовлетворяет следующим правилам:

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

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

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

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

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

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

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

При таком вызове метода 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():

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

     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():

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

Согласно стандартному интерфейсу класса 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-94 и ГОСТ Р 34.10-2001 с ключевых носителей

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

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

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

    String alias;   // идентификатор (уникальное имя) получаемого закрытого ключа,
                    // установленный при записи ключа на носитель

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

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

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

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

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

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

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

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

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

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

    ks.setCertificateEntry(alias, cert);

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

Чтение сертификата открытого ключа с ключевого носителя

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

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

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

    Certificate cert = ks.getCertificate(alias);

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

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

Удаление секретного ключа с ключевого носителя осуществляется вызовом функции 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, являющегося уникальным именем записываемого сертификата.

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

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

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

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

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

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

    String alias;   // идентификатор (уникальное имя) сертификата,
                    // установленный при записи сертификата в хранилище

    Certificate cert = ks.getCertificate(alias);

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

Пример чтения сертификата из хранилища доверенных сертификатов см. 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 необходимо доинициализировать. При генерировании ключа пользователю по умолчанию предлагается использовать оконный интерфейс. Для доинициализации будет использовано время между пользовательскими событиями: нажатиями клавиш, кнопок мыши, движениями мыши.

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

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

Пример использования генератора случайных чисел с использованием класса 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 производится в два этапа: обработка данных и последующее завершение операции хеширования.

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

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

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

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

После того, как все данные были обработаны, следует завершить операцию хеширования. Завершение осуществляется при помощи метода 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 запрещается.

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

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

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

При таком вызове метода 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, в соответствии с которыми будет осуществляться операция формирования ЭЦП. Определение параметров ЭЦП осуществляется во время инициализации операции создания подписи методом initSign() класса Signature. в соответствии с параметрами закрытого ключа подписи, передаваемыми данному методу. Этот ключ не только определяет параметры формирования ЭЦП, но и используется в процессе ее формирования.

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

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

    PrivateKey privateKey; // обязательно ключ с алгоритмом "GOST3410"
                           // (соответствующий алгоритму ГОСТ Р 34.10-2001)
    sig.initSign(privateKey);

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

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

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

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

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

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

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

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

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

  1. Последовательная обработка каждого байта данных (при этом количество вызовов метода update(byte b) равно длине массива данных):
        byte[] data;
        for(int i = 0; i < data.length; i++)
        sig.update(data[i]);
        
  2. Блочная обработка данных (данные обрабатываются блоками определенной длины):
        byte[] data;
        int BLOC_LEN = 1024;
    
        // если длина исходных данных меньше длины блока
        if(data.length/BLOC_LEN == 0)
            sig.update[data];
        else {
            // цикл по блокам
            for (int i = 0; i < data.length/BLOC_LEN; i++) {
                byte[] bloc = new byte[BLOC_LEN];
                for(int j = 0; j < BLOC_LEN; j++) bloc[j] = data[j + i * BLOC_LEN];
                sig.update(bloc);
            }
        
            // обработка остатка
            byte[] endBloc = new byte[data.length % BLOC_LEN];
            for(int j = 0; j < data.length % BLOC_LEN; j++)
                bloc[j] = data[j + data.length - data.length % BLOC_LEN - 1];
            sig.update(bloc);
        }
        
  3. Обработка данных целиком:
        byte[] data;
        sig.update(data);
        

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    sig.initVerify(publicKey);

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

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

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

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

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

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

Проверка ЭЦП

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

Примеры создания и проверки подписи см. 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"

    //для построения цепочки
    CertPathBuilder builder = CertPathBuilder.getInstance("CPPKIX");
    и
    //для проверки цепочки
    CertPathValidator validator = CertPathValidator.getInstance("CPPKIX");

Пример построения и проверки цепочки сертификатов см. 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, в зависимости от способа его создания, определяет

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

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

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

Изменение такого набора параметров осуществляется при помощи интерфейса 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("GOST3410DH", 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/security/dist/java-library/, выбирая последнюю версию продукта.

Основные операции осуществляются при помощи функций следующих классов: 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 операции

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

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

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

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

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

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

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

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

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

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

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

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

    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

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

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

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

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

    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, которой в качестве параметров передаются:

Таким образом, генерирование самоподписанного сертификата открытого ключа в соответствии с хранящимся на носителе закрытым ключом и запись сертификата на носитель осуществляется:
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, которой в качестве параметров передаются:

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


keytool -export -alias myKey -provider ru.CryptoPro.JCP.JCP -storetype HDImageStore  -keystore c:\.keystore
    -storepass 123456 -file c:\myKeyCert.cer

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

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

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

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

    keytool -import -alias myKey -provider ru.CryptoPro.JCP.JCP -keypass 11111111 -storetype HDImageStore
        -keystore c:\.keystore -storepass 123456 -file c:\myKeyCert.cer

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

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

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

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

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

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

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

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

Таким образом, чтение сертификата открытого ключа из файла и запись его на носитель в соответствии с хранящимся на носителе закрытым ключом осуществляется:
    keytool -import -alias myCert -provider ru.CryptoPro.JCP.JCP -storetype HDImageStore -keystore c:\.keystore
        -storepass 123456 -file c:\myCert.cer

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

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

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

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

    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, которой в качестве параметров передаются:

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

    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

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

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

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

Запуском:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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