Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

Руководство разработчика

Table of Contents
maxLevel3
outlinetrue
stylenone
excludeРуководство разработчика

Введение

Данный документ содержит описание Java-провайдера JRT11 и способов его использования.

Провайдер JRT11 предназначен для использования Рутокен ЭЦП в программных продуктах, разработанных на Java.

Провайдер JRT11 функционирует под управлением виртуальных машин Java 2 Runtime Environment версии 1.6 и выше, производства Oracle и Open JDK.

Провайдер JRT11 позволяет работать с российскими криптографическими алгоритмами ГОСТ 28147-89, ГОСТ Р 34.10-2001, ГОСТ Р 34.11-94 и стандартом RFC 4357 в стандартном интерфейсе Java Cryptography Architecture (JCA). В соответствии с этим интерфейсом обеспечивается выполнение следующих криптографических операций:

  • генерация ключей подписи, соответствующих алгоритму ГОСТ Р 34.10-2001;
  • генерация ключей шифрования, соответствующих алгоритму ГОСТ 28147-89;
  • выработка общего ключа парной связи по алгоритму Диффи-Хеллмана;
  • хранение ключей на отделяемом ключевом носителе;
  • шифрование данных в соответствии с ГОСТ 28147-89;
  • подпись / проверка данных в соответствии с ГОСТ Р 34.10-2001;
  • хеширование данных в соответствии с ГОСТ Р 34.11-94;
  • вычисление имитовставки в соответствии с ГОСТ 28147-89;
  • генерация последовательности случайных чисел требуемой длины;
  • поддержка алгоритма RSA, с ключами до 2048 бит.

Провайдер JRT11 выполнен в стандартном интерфейсе JCA и может использоваться непосредственно через него или же через свой собственный интерфейс.

Использование провайдера JRT11 через интерфейс JCA

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

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

Исторически сложилось так, что классы для работы с шифрованием содержатся в пакете javax.crypto, классы для работы с подписью находятся в пакете java.security.

Info

Подробное описание классов пакета java.security доступно в документации по API.

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

Подключение провайдера

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

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

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

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

<jre>\lib\ext\,

где <jre> – директория с установленным JRE или JDK.

Динамическая регистрация провайдера

Провайдер JRT11 реализован классом ru.rutoken.jrt11.JRT11Provider, который наследуется от стандартного класса Provider и может быть добавлен/удален в списке провайдеров по необходимости. Провайдер регистрируется под именем "JRT11".

Для управления списком провайдеров предназначены следующие методы класса Security:

Метод

Назначение

addProvider(Provider provider)­добавление провайдера в конец списка
insertProviderAt(Provider provider, int position)

добавление провайдера в нужную позици

removeProvider(String name)удаление провайдера из списка
Code Block
languagejava
titleЛистинг 1. Динамическая регистрация провайдера
Security.addProvider(new ru.rutoken.jrt11.JRT11Provider());

Статическая регистрация провайдера

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

<jre>\lib\security\java.security

строчки типа

security.provider.n = masterClassName,

где n – порядок приоритета провайдера при поиске требуемого алгоритма (1 – самый предпочтительный), masterClassName – полное имя родительского класса провайдера.

Code Block
languagejava
titleЛистинг 2.1. Статическая регистрация провайдера
security.provider.7=ru.rutoken.jrt11.JRT11Provider

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

Code Block
languagejava
titleЛистинг 2.2. Статическая регистрация провайдера c указанием конфигурационного файла в *nix
security.provider.7=ru.rutoken.jrt11.JRT11Provider /jrt11/jrt11.properties

При добавлении имени конфигурационного файла в Windows разделитель каталогов надо удваивать:

Code Block
languagejava
titleЛистинг 2.3. Статическая регистрация провайдера c указанием конфигурационного файла в Windows
security.provider.7=ru.rutoken.jrt11.JRT11Provider C:\\jrt11\\jrt11.properties

Подробнее о конфигурационном файле и его назначении см. раздел Сценарии задания конфигурации.

Общая схема работы с классами java.security

Создание объектов JCA

Для осуществления любой криптографической операции, как шифрование/подпись данных или генерация ключевой пары, первым шагом создается объект, реализующий алгоритм, с помощью метода getInstance(). Этот метод является статическим и возвращает ссылку на класс, который обеспечивает выполнение требуемой операции. В качестве аргумента методу getInstance() необходимо передать имя алгоритма. Вторым необязательным аргументом может быть передано либо имя провайдера либо сам объект провайдера. Настоятельно рекомендуется использовать форму getInstance(String algorithm, String provider) или getInstance(String algorithm, Provider provider) с указанием провайдера. Явное указание имени провайдера позволит обеспечить использование алгоритма из нужного провайдера и избавит от возможных конфликтов между различными провайдерами.

Code Block
languagejava
titleЛистинг 3.1 Пример создания объекта хеширования
MessageDigest digest = MessageDigest.getInstance("rtGOST3411", "JRT11");

Использование параметров через интерфейс AlgorithmParameterSpec

После создания объекта его можно инициализировать. В некоторых случаях при инициализации класса предусмотрена возможность передачи параметров, реализующих интерфейс AlgorithmParameterSpec (например, KeyPairGenerator.initialize(java.security.spec.AlgorithmParameterSpec) или Signature.setParameter(java.security.spec.AlgorithmParameterSpec)). Полный список методов, использующих AlgorithmParameterSpec,  доступен по следующей ссылке.

В качестве параметров могут выступать:

  • Config - конфигурация PKCS#11;
  • Context - созданный контекст PKCS#11;
  • Token - Рутокен;
  • Session - открытая сессия;
  • ParamPin - PIN-код Рутокен;
  • ParamSet - набор параметров.

Эти параметры предназначены для взаимодействия с PKCS#11 токеном и описаны в разделе Сценарии задания конфигурации.

Такая инициализация не является обязательной, например, алгоритмы хеширования (MessageDigest) и генерации случайных чисел (SecureRandom) будут работать и без нее, но для создания ключа подписи на Рутокен необходимо знание PIN-кода, значение которого и передается с помощью параметра. После инициализации объект можно использовать по назначению.

Задать параметры можно непосредственно в имени алгоритма. При создании алгоритма после его имени через разделитель "/" следует указать строковое представление OID.

Code Block
languagejava
titleЛистинг 3.2 Пример использования расширенных имен алгоритмов
KeyPairGenerator generator = KeyPairGenerator.getInstance("rtGOST3410/1.2.643.2.2.35.1", "JRT11");

Генерация ключей

Генерация ключей шифрования

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

Для генерации ключей шифрования для алгоритма ГОСТ 28147-89 при создании объекта типа KeyGenerator методом getInstance() в качестве имени алгоритма надо указать значение "rt11GOST28147".

Затем генерация ключа осуществляется вызовом метода generateKey().

(info) Подробное описание использования классаKeyGenerator доступно в разделе JCA (вместе с подробным примером).

Code Block
languagejava
titleЛистинг 4. Пример генерации ключа для шифрования по алгоритму ГОСТ 28147-89
KeyGenerator generator = KeyGenerator.getInstance("rt11GOST28147", "JRT11");
SecretKey secret = generator.generateKey();

Генерация ключей подписи

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

Для генерации ключевых пар для алгоритма ГОСТ Р 34.10-2001 при создании объекта типа KeyPairGenerator методом getInstance() в качестве имени алгоритма надо указать значение "rtGOST3410". 

Затем генерация ключа осуществляется вызовом метода generateKeyPair().

(info) Подробное описание использования класса KeyPairGenerator доступно в разделе JCA (вместе с подробным примером).

Code Block
languagejava
titleЛистинг 5.1. Пример генерации ключевой пары для подписи данных по алгоритму ГОСТ Р 34-10.2001
KeyGenerator generator = KeyGenerator.getInstance("rt11GOST28147", "JRT11");
SecretKey secret = generator.generateKey();

(warning) Так как провайдер JRT11 методом KeyPairGenerator() генерирует ключевую пару сразу на Рутокен, то при ее создание следует сразу указать имя ключевой пары. Это можно сделать путем передачи методу initialize() классом ParamAlias значения имени "alias".

Code Block
languagejava
titleЛистинг 5.2. Пример генерации ключевой пары для подписи данных по алгоритму ГОСТ Р 34-10.2001 с заданным именем
KeyPairGenerator generator = KeyPairGenerator.getInstance("rtGOST3410", "JRT11");
generator.initialize(new ru.rutoken.security.spec.ParamAlias("alias"));
KeyPair pair = generator.generateKeyPair();

По этому имени станет возможным извлечение ключа из хранилища.

Для генерации ключевой пары по алгоритму RSA в качестве имени алгоритма надо задать "rtRSA". Размер ключа задается методом KeyPairGenerator.initialize(int).

Выработка общего сессионного ключа парной связи

Провайдер JRT11 позволяет осуществлять выработку общего ключа парной связи по алгоритму Диффи-Хеллмана через стандартный интерфейс JCA при помощи класса KeyAgreement.

Для выработки ключа шифрования для алгоритма ГОСТ 28147-89 при создании объекта типа KeyAgreement методом getInstance() в качестве имени алгоритма надо указать значение"rtGOST3410".

Созданный объект необходимо инициализировать собственным закрытым ключом и параметрами. В качестве параметров, участвующих в выработке общего ключа, передается объект класса IvParameterSpec, представляющий собой стартовый вектор для выработки общего ключа. После инициализации необходимо передать открытый ключ методом doPhase(), параметры которого должны совпадать с соответствующими параметрами закрытого ключа. При генерации общего ключа парной связи в качестве имени алгоритма надо передать методу generateSecret()  значение "rt11GOST28147".

(info) Подробное описание использования классаKeyAgreement доступно в разделе JCA (вместе с подробным примером).

Code Block
languagejava
titleЛистинг 6. Пример выработки общего ключа парной связи по алгоритму Диффи-Хеллмана
KeyAgreement agreement = KeyAgreement.getInstance("rtGOST3410", "JRT11");
agreement.init(privateKey, new IvParameterSpec(ivBytes));
agreement.doPhase(publicKey, true);
SecretKey secret = agreement.generateSecret("rt11GOST28147");

Шифрование и расшифрование

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

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

Для шифрования по алгоритму ГОСТ 28147-89 при создании объекта типа Cipher методом getInstance() в качестве имени алгоритма необходимо указать значение "rt11GOST28147".

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

(info) Подробное описание использования класса Cipher доступно в разделе JCA (вместе с подробным примером).

Code Block
languagejava
titleЛистинг 7.1. Пример шифрования данных по алгоритму ГОСТ 28147-89
cipher = Cipher.getInstance("rt11GOST28147", "JRT11");
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] result = cipher.doFinal(data);
Code Block
languagejava
titleЛистинг 7.2. Пример расшифрования данных по алгоритму ГОСТ 28147-89
cipher = Cipher.getInstance("rt11GOST28147", "JRT11");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] result = cipher.doFinal(data);

Шифрование и расшифрование ключей

Для шифрования по алгоритму ГОСТ 28147-89 при создании объекта типа Cipher методом getInstance() в качестве имени алгоритма необходимо указать значение "rt11GOST28147".

Для шифрования ключа созданный объект необходимо инициализировать ключом шифрования с помощью метода init(). Затем зашифрованный ключ становится доступен вызовом метода wrap(), а расшифрованный - методом unwrap().

(info) Подробное описание использования класса Cipher доступно в разделе JCA (вместе с подробным примером).

Code Block
languagejava
titleЛистинг 8.1. Пример шифрования ключа по алгоритму ГОСТ 28147-89
cipher = Cipher.getInstance("rt11GOST28147", "JRT11");
cipher.init(Cipher.WRAP_MODE, secret);
byte[] result = cipher.wrap(wrappedKey);
Code Block
languagejava
titleЛистинг 8.2. Пример расшифрования ключа по алгоритму ГОСТ 28147-89
cipher = Cipher.getInstance("rt11GOST28147", "JRT11");
cipher.init(Cipher.UNWRAP_MODE, secret);
byte[] result = cipher.unwrap(unwrappedKey);

Хеширование данных

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

Для создания объекта хеширования по алгоритму ГОСТ Р 34.11-94 методу getInstance() необходимо в качестве параметра передать имя, идентифицирующее данный алгоритм –"rtGOST3411". Следующим шагом необходимо предоставить данные для хеширования методом update(). Вычисление хеш-суммы осуществляется методом digest().

(info) Подробное описание использования класса MessageDigest доступно в разделе JCA (вместе с подробным примером).

Code Block
languagejava
titleЛистинг 9. Пример вычисления хеш-суммы ГОСТ Р 34.11-94
MessageDigest messageDigest = MessageDigest.getInstance("rtGOST3411", "JRT11");
messageDigest.update("rtGOST3411".getBytes());
byte[] digestValue = messageDigest.digest();

Подпись и проверка подписи данных

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

Для создания объекта подписи/проверки подписи по алгоритму ГОСТ Р 34.10-94 методу getInstance() необходимо в качестве параметра передать имя, идентифицирующее данный алгоритм –"rtGOST3411withrtGOST3410". Следующим шагом необходимо предоставить закрытый ключ для подписи данных методом initSign() или открытый ключ/сертификат для проверки подписи методом initVerify(). Сами данные для подписи/проверки подписи передаются методом update(). Подпись данных осуществляется методом sign(), проверка подписи – методом verify().

(info) Подробное описание использования класса Signature доступно в разделе JCA (вместе с подробными примерами).

Code Block
languagejava
titleЛистинг 10.1. Пример подписи данных по алгоритму ГОСТ Р 34.10-2001
Signature signature = Signature.getInstance("rtGOST3411withrtGOST3410", "JRT11");
signature.initSign(privateKey);
signature.update(TEXT);
byte[] signatureValue = signature.sign();
Code Block
languagejava
titleЛистинг 10.2. Пример проверки подписи данных по алгоритму ГОСТ Р 34.10-2001
Signature signature = Signature.getInstance("rtGOST3411withrtGOST3410", "JRT11");
signature.initVerify(publicKey);
signature.update(TEXT);
boolean result = signature.verify(signatureValue));

Для подписи ключом RSA в качестве имени алгоритма надо использовать "MD5withRSA".

Имитозащита данных

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

Для имитозащиты данных по алгоритму ГОСТ 28147-89 при создании объекта типа Mac методу getInstance() в качестве имени алгоритма надо передать значение "rt11GOST28147".

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

(info) Подробное описание использования класса Mac доступно в разделе JCA (вместе с подробным примером).

Code Block
languagejava
titleЛистинг 11. Пример вычисления имитовставки по алгоритму ГОСТ 28147-89
Mac mac = Mac.getInstance("rt11GOST28147", "JRT11");
mac.init(secret);
mac.update(dataBytes);
byte[] macValue = mac.doFinal();

Генерация последовательности случайных чисел

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

При создании объекта типа SecureRandom методу getInstance() в качестве имени алгоритма надо передать значение "rtRandom". Для генерации случайной последовательности чисел вызывается метод nextBytes(), в качестве аргумента передается массив произвольного размера для заполнения случайными байтами.

(info) Подробное описание использования класса SecureRandom доступно в разделе JCA.

Code Block
languagejava
titleЛистинг 12. Пример генерации последовательности псевдослучайных чисел
byte[] bytes = new byte[8];
SecureRandom random = SecureRandom.getInstance("rtRandom", "JRT11");
random.nextBytes(bytes);

Хранение ключей

Провайдер JRT11 позволяет осуществлять извлечение ключа из хранилища через стандартный интерфейс JCA при помощи класса KeyStore. Операция извлечения используется для ключей, создаваемых с помощью класса KeyPairGenerator и записываемых сразу на Рутокен.

При создании объекта типа KeyStore методу getInstance() в качестве имени алгоритма надо передать значение "rtStore". Для извлечения ключа необходимо передать методом KeyStore.load(InputStream, char[]) PIN-код Рутокен вторым значением, а значение InputStream оставить пустым.

(info) Подробное описание использования класса KeyStore доступно в разделе JCA.

Code Block
languagejava
titleЛистинг 13.1. Пример извлечения ключа из хранилища
KeyStore keyStore = KeyStore.getInstance("rtStore", "JRT11");
keyStore.load(null, "12345678".toCharArray());
PrivateKey privateKey = (PrivateKey)keyStore.getKey("alias", null);

Так как для извлечения открытого ключа в KeyStore нет специальных возможностей, а хранилище "rtStore" хранит ключи в контейнерах, предлагается использовать следующий механизм: сначала извлечь KeyStore.Entry методом KeyStore.getEntry(String, ProtectionParameter), а затем из полученного контейнера извлечь открытый ключ.

Code Block
languagejava
titleЛистинг 13.2. Пример извлечения открытого ключа из хранилища
KeyStore.Entry entry = keyStore.getEntry("alias", null);
PublicKey publicKey = ((ru.rutoken.security.KeyContainer)entry).getPublicKey();

Использование провайдера JRT11 без интерфейса JCA

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

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

Провайдер JRT11 имеет собственный интерфейс, аналогичный JCA и лишенный описанных недостатков.

Краткое описание собственного интерфейса провайдера JRT11

Аналогично интерфейсу JCA, где классы SecureRandom, MessageDigest, KeyPairGenerator, Signature располагаются в пакете java.security, аналогичные классы собственного интерфейса провайдера JRT11 SecureRandom, MessageDigest, KeyPairGenerator, Signature располагаются в пакете в пакете ru.rutoken.security. В этих классах полностью сохранен интерфейс JCA как в плане создания объекта, так и в плане использования: аналогичны используемые методы, параметры, исключения.

Например, код

Code Block
languagejava
titleЛистинг 14. Пример использования собственного интерфейса провайдера JRT11
MessageDigest digest = MessageDigest.getInstance(algorithm);
digest.update(data);
byte[] result = digest.digest();

будет одинаково работать как в случае использования стандартного класса java.security.MessageDigest, так и в случае использования класса ru.rutoken.security.MessageDigest.

Переход от одного интерфейса к другому легко реализуется заменой оператора import. Подробное описание интерфейса классов ru.rutoken.security предоставлено в JavaDoc. 

Классы для работы с шифрованием средствами JCA/JCE находятсяв пакете javax.crypto. По аналогии, классы для работы с шифрованием средствами JRT11 находятся в пакете ru.rutoken.crypto.

Очистка объектов

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

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

Для очистки конфиденциальной информации в провайдере JRT11 предназначен класс ru.rutoken.security.Cleaner. Все объекты, которые содержат конфиденциальную информацию, должны быть по окончании использования очищены с помощью статического метода Cleaner.clean(Object), вызванного в finally секции для гарантированной очистки в случае любых ошибок.

Code Block
languagejava
titleЛистинг 15. Пример очистки объекта
public byte[] sign(byte[] data, PrivateKey key) throws Exception 
{
	Signature signature = null;
    try 
	{
    	signature = Signature.getInstance(JRT11Provider.GOST_SIGNATURE_ALGORITHM, JRT11Provider.PROVIDER_NAME);
        signature.initSign(key);
        signature.update(data);
        return signature.sign();
     } 
	finally 
	{
        Cleaner.clean(signature);
    }
}

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

  • подписываемые данные,
  • закрытый ключ, с помощью которого производится подпись,
  • объект хранилища, из которого прочитан ключ,
  • PIN-код Пользователя и Администратора Рутокен,
  • и все остальные объекты, которые могут содержать конфиденциальную информацию или способствовать ее получению.

Использование параметров алгоритмов

Провайдер JRT11 позволяет работать с параметрами российских алгоритмов, описанными в стандарте RFC 4357 и обеспечивающими необходимую стойкость. Они обеспечивают совместимость с продуктами других производителей и не рекомендуются к использованию без необходимости. Использование других параметров, стойкость которых неизвестна, не допускается. Использование тестовых параметров допустимо только для целей тестирования.

Для работы параметрами алгоритмов предназначен класс ru.rutoken.security.spec.gost (подробное описание класса предоставлено в JavaDoc).

Используется четыре типа параметров: шифрования (Crypt), хеширования (Digest), подписи (Elliptic) и обмена (Exchange).

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

Параметры подписи (Elliptic) предназначены для ключей подписи и использовать такие ключи для выработки ключа парной связи по алгоритму Диффи-Хеллмана нельзя.

Реализация каждого параметра состоит из трех классов: интерфейс, реализация и фабрика.

Интерфейс определяет, соответствует ли OID присвоенному ему параметру в стандарте  RFC 4357. Каждый OID может быть закодирован в соответствии с ITU-T Rec. X.690 (07/2002), поэтому в интерфейсе есть метод public byte[] getEncodedOID().

Фабрика определяет возможности перечисления всех возможных параметров и получения параметров:

  • по умолчанию;
  • по номеру;
  • по OID;
  • по строковому представленияю OID;
  • по ASN.1 кодированному представлению.

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

Получениепараметров из фабрики

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

Code Block
languagejava
titleЛистинг 16.1. Пример установки параметров из фабрики
KeyPairGenerator generator = KeyPairGenerator.getInstance("rtGOST3410", "JRT11");
generator.initialize(EllipticParamFactory.getInstance());
KeyPair pair = generator.generateKeyPair();
Code Block
languagejava
titleЛистинг 16.2. Пример установки параметров из фабрики
Mac mac = Mac.getInstance("rt11GOST28147", "JRT11");
mac.init(key, CryptParamFactory.getInstance("1.2.643.2.2.31.1"));

В целях обеспечения совместимости c java-классами все используемые параметры реализуют стандартный интерфейс java.security.spec.AlgorithmParameterSpec. Методы, позволяющие устанавливать в алгоритм параметры, реализующие интерфейс AlgorithmParameterSpec, есть в большинстве алгоритмов (см. следующую ссылку) .

Использование расширенных имен алгоритмов

Задать параметры можно непосредственно в имени алгоритма. При создании алгоритма после его имени через разделитель "/" следует указать строковое представление OID.

Code Block
languagejava
titleЛистинг 16.3. Пример использования расширенных имен алгоритмов
KeyPairGenerator generator = KeyPairGenerator.getInstance("rtGOST3410/1.2.643.2.2.35.1", "JRT11");

 Этот способ будет работать как при создании алгоритма стандартными средствами JCA из пакета java.security , так и при создании алгоритмов средствами пакета ru.rutoken.security.

Конфигурация PKCS#11

В состав конфигурации PKCS#11 входит 3 параметра:

  • библиотека PKCS#11 (параметр Library),
  • серийный номер Рутокен (параметр Serial) и
  • PIN-код Рутокен (параметр Pin).

Параметр Library указывает полный путь к библиотеке, реализующей стандарт PKCS#11, и зависит от операционной системы. Если путь не задан явно в конфигурации, провайдер JRT11 будет пытаться найти библиотеку по умолчанию. Например, для ОС Windows JRT11 будет проверять путь C:\Windows\System32\rtPKCS11ECP.dll.

Параметр Serial содержит уникальный серийный номер Рутокен, с которым должен работать провайдер JRT11. Его можно узнать через Панель управления Рутокен (по нажатию кнопки Информация будет выдан ID в hex). В конфигурации серийный номер также задается в шестнадцатеричном виде. Если серийный номер не задан, то провайдер JRT11 будет пытаться использовать первый присутствующий Рутокен.

Параметр Pin определяет PIN-код Рутокен и значения по умолчанию не имеет.

Конфигурация PKCS#11 может быть сохранена в файл.

Code Block
languagejava
titleЛистинг 17. Пример конфигурационного файла
Library=C:\Windows\System32\rtPKCS11ECP.dll
Serial=2b356eb7
Pin=12345678

Для работы с конфигурацией предназначен класс ru.rutoken.jrt11.Config (подробное описание класса предоставлено в JavaDoc). 

Класс Config реализует интерфейс AlgorithmParameterSpec, поэтому его можно передавать в качестве параметра в некоторые алгоритмы, например, KeyPairGenerator.initialize(int).

Использование класса SessionFactory

Предназначение класса ru.rutoken.jrt11.SessionFactory заключается не только в определении конфигурации PKCS#11, но и выполнении предварительных действий для работы по стандарту PKCS#11: инициализации библиотеки, поиска подключенного Рутокен, открытии сессии и пр. и выдаче параметра для инициализации JCA алгоритма. Подробное описание класса доступно в JavaDoc.

Схема использования класса:

  1. создание объекта SessionFactory;
  2. инициализация объекта SessionFactory методом setParameter();
  3. получение параметра.
Code Block
languagejava
titleЛистинг 18. Пример использования класса SessionFactory
SessionFactory factory = new SessionFactory();
factory.setParameter(new ParamPin(tokenPin));
AlgorithmParameterSpec token = factory.getToken();

Для инициализации объекта SessionFactory может быть использован класс Config или ParamPin.

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

Также можно с помощью функции getSession() получить дескриптор открытой сессии и работать с ним.

Сценарии задания конфигурации PKCS#11

Ниже перечислены различные сценарии задания конфигурации PKCS#11.

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

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

Code Block
languagejava
titleЛистинг 19.1. Пример задания конфигурации PKCS#11
System.setProperty("ru.rutoken.jrt11.ConfigLibrary", "C:\\Windows\\System32\\rtPKCS11ECP.dll");
System.setProperty("ru.rutoken.jrt11.ConfigSerial", "2b356eb7");
System.setProperty("ru.rutoken.jrt11.ConfigPin", "12345678");

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

3. Задать конфигурацию можно при установке провайдера.

Code Block
languagejava
titleЛистинг 19.2. Пример задания конфигурации PKCS#11
Config config = new Config("C:\\Windows\\System32\\rtPKCS11ECP.dll", "2b356eb7", "12345678");
Security.addProvider(new JRT11Provider(config));

Этот способ эквивалентен предыдущему. Задание конфигурации в провайдере приводит к установке системных свойств.

4. При установке провайдера можно задать имя конфигурационного файла.

Code Block
languagejava
titleЛистинг 19.3. Пример задания конфигурации PKCS#11
String configFileName = "C:\\jrt11\\jrt11.properties";
Security.addProvider(new JRT11Provider(configFileName));

5. Для случая статической регистрации провайдера имя конфигурационного файла можно указать в файле <jre>\lib\security\java.security:

security.provider.7=ru.rutoken.jrt11.JRT11Provider C:\\jrt11\\jrt11.properties

6. Создать конфигурацию можно прямо в коде, и передать параметром в алгоритм

Code Block
languagejava
titleЛистинг 19.4. Пример задания конфигурации PKCS#11
Config config = new Config("C:\\Windows\\System32\\rtPKCS11ECP.dll", "2b356eb7", "12345678");
generator.initialize(config);

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

Code Block
languagejava
titleЛистинг 19.5. Пример задания конфигурации PKCS#11
Config config = new Config(null, null, "12345678");
generator.initialize(config);

7. PIN-код Рутокен можно устанавливать в алгоритм напрямую, без конфигурации.

Code Block
languagejava
titleЛистинг 19.6. Пример задания PIN-кода Рутокен
generator.initialize(new ru.rutoken.security.spec.ParamPin("12345678"));

8. Можно устанавливать в алгоритм PKCS#11 токен.

Code Block
languagejava
titleЛистинг 19.6. Пример задания конфигурации PKCS#11
Config config = new Config("C:\\Windows\\System32\\rtPKCS11ECP.dll", "2b356eb7", "12345678");
sessionFactory.setParameter(config);
generator.initialize(sessionFactory.getToken());

Это способ является рекомендуемым.

9. Можно устанавливать в алгоритм PKCS#11 контекст.

Code Block
languagejava
titleЛистинг 19.6. Пример задания конфигурации PKCS#11
generator.initialize(sessionFactory.getContext());

10. Можно устанавливать в алгоритм PKCS#11 сессию.

Code Block
languagejava
titleЛистинг 19.6. Пример задания конфигурации PKCS#11
generator.initialize(sessionFactory.getSession());

       

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

Related links

  1. Руководство по применению JCA: http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html
  2. Спецификация Java SE 6 API http://docs.oracle.com/javase/6/docs/api/index.html
  3. Загрузка JDK/JDE http://www.oracle.com/technetwork/java/javase/downloads/index.html
  4. Русскоязычное руководство по maven http://www.apache-maven.ru/index.html

Вложения

  1. JavaDoc для разработчиков jrt11-0.5-javadoc.zip