Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Предназначение устройств Рутокен

Рутокен S

Рутокен

...

Рутокен ЭЦП

Рутокен PINPad

S – устройство для авторизации в компьютерных системах и защиты персональных данных российским стандартом шифрования "на борту".

Рутокен S реализует следующие возможности стандарта PKCS#11:

  • генерация и импорт ключей шифрования ГОСТ 28147-89, 
  • шифрование данных по алгоритму ГОСТ 28147-89 в режимах простой замены, гаммирования и гаммирования с обратной связью, 
  • вычисление (и проверка?) имитовставки по алгоритму ГОСТ 28147-89 длиной 32 бит, 
  • генерация последовательности случайных чисел длиной 256 бит.

Рутокен Lite

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

Рутокен ЭЦП

Рутокен ЭЦП – электронный идентификатор с аппаратной реализацией российских и зарубежных стандартов электронной подписи, шифрования и хеширования.

Рутокен PINPad представляет собой решение класса TrustScreen, которое позволяет визуализировать подписываемый документ на экране доверенного устройства перед наложением электронной подписи. Устройство позволяет реализовать следующие незаменимые в PKI-инфраструктуре возможности: 

  • Формировать запросы на сертификат в формате PKCS#10 для неизвлекаемых ключей электронной подписи ГОСТ Р 34.10-2001 с возможностью визуализации и подтверждения на устройстве;
  • Подписывать и шифровать данные в формате CMS с использованием алгоритмов ГОСТ Р 34.10-2001, ГОСТ Р 34.11-94 и ГОСТ 28147-89, схемы VKO;
  • Хранить и использовать сертификаты открытого ключа ГОСТ Р 34.10-2001 в формате X.509.

Кроме того, Рутокен PINPad поддерживает национальные стандарты в полном объеме:

  • алгоритмы  ГОСТ Р 34.10-2012 и ГОСТ Р 34.10-2001: генерация ключевых пар с проверкой качества, импорт ключевых пар, формирование и проверка электронной подписи, срок действия закрытых ключей до 3-х лет.
  • алгоритмы  ГОСТ Р 34.11-2012 и ГОСТ Р 34.11-94: вычисление значения хеш-функции данных, в том числе с возможностью последующего формирования электронной подписи.
  • алгоритм ГОСТ 28147-89: генерация и импорт ключей шифрования, шифрование данных в режимах простой замены, гаммирования и гаммирования с обратной связью, вычисление и проверка криптографической контрольной суммы данных (имитовставки ГОСТ).
  • выработка сессионных ключей (ключей парной связи): по схеме VKO GOST R 34.10-2001 (RFC 4357), расшифрование по схеме EC El-Gamal.
  • алгоритм RSA: поддержка ключей размером до 2048 бит, генерация ключевых пар с настраиваемой проверкой качества, импорт ключевых пар, формирование электронной подписи.
  • генерация последовательности случайных чисел требуемой длины.

Начало работы

Подключение библиотеки

Для работы с устройствами Рутокен по стандарту PKCS#11 приложение предварительно должно динамически загрузить библиотеку, реализующую интерфейс стандарта. Рутокен SDK предоставляет две библиотеки rtPKCS11.dll и rtPKCS11ECP.dll, подробнее об особенностях выбора и использования которых можно ознакомиться в разделе Использование библиотек rtPKCS11 и rtPKCS11ECP. Основная разница заключается в том, что российские алгоритмы доступны в библиотеке rtPKCS11ECP.dll, а зарубежные - в rtPKCS11.dll.

После загрузки библиотеки нужно получить адрес экспортируемой библиотекой функции C_GetFunctionList и вызвать ее для получения списка функций PKCS#11. Теперь все готово для работы с библиотекой.

Для работы с функциями расширения необходимо получить адрес функции CK_C_EX_GetFunctionListExtended и вызвать ее для получения списка функций расширения PKCS#11.

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

Рутокен PINPad

Рутокен PINPad представляет собой решение класса TrustScreen, которое позволяет визуализировать подписываемый документ на экране доверенного устройства перед наложением электронной подписи. Устройство позволяет реализовать следующие незаменимые в PKI-инфраструктуре возможности: 

  • Формировать запросы на сертификат в формате PKCS#10 для неизвлекаемых ключей электронной подписи ГОСТ Р 34.10-2001 с возможностью визуализации и подтверждения на устройстве;
  • Подписывать и шифровать данные в формате CMS с использованием алгоритмов ГОСТ Р 34.10-2001, ГОСТ Р 34.11-94 и ГОСТ 28147-89, схемы VKO;
  • Хранить и использовать сертификаты открытого ключа ГОСТ Р 34.10-2001 в формате X.509.

Кроме того, Рутокен PINPad поддерживает национальные стандарты в полном объеме:

  • алгоритмы  ГОСТ Р 34.10-2012 и ГОСТ Р 34.10-2001: генерация ключевых пар с проверкой качества, импорт ключевых пар, формирование и проверка электронной подписи, срок действия закрытых ключей до 3-х лет.
  • алгоритмы  ГОСТ Р 34.11-2012 и ГОСТ Р 34.11-94: вычисление значения хеш-функции данных, в том числе с возможностью последующего формирования электронной подписи.
  • алгоритм ГОСТ 28147-89: генерация и импорт ключей шифрования, шифрование данных в режимах простой замены, гаммирования и гаммирования с обратной связью, вычисление и проверка криптографической контрольной суммы данных (имитовставки ГОСТ).
  • выработка сессионных ключей (ключей парной связи): по схеме VKO GOST R 34.10-2001 (RFC 4357), расшифрование по схеме EC El-Gamal.
  • генерация последовательности случайных чисел требуемой длины.

Начало работы

Подключение библиотеки

Для работы с устройствами Рутокен по стандарту PKCS#11 приложение предварительно должно динамически загрузить библиотеку, реализующую интерфейс стандарта. Рутокен SDK предоставляет две библиотеки rtPKCS11.dll и rtPKCS11ECP.dll, подробнее об особенностях выбора и использования которых можно ознакомиться в разделе Использование библиотек rtPKCS11 и rtPKCS11ECP. Основная разница заключается в том, что российские алгоритмы доступны в библиотеке rtPKCS11ECP.dll, а зарубежные - в rtPKCS11.dll.

После загрузки библиотеки нужно получить адрес экспортируемой библиотекой функции C_GetFunctionList() и вызвать ее для получения списка функций PKCS#11. Теперь все готово для работы с библиотекой.

Для работы с функциями расширения необходимо получить адрес функции CK_C_EX_GetFunctionListExtended() и вызвать ее для получения списка функций расширения PKCS#11.

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

Code Block
languagecpp
titleЗагрузка библиотеки и списка функций PKCS#11
/* Имя библиотеки PKCS#11 */
#ifdef _WIN32
/* Библиотека для Рутокен S, Рутокен Lite и Рутокен ЭЦП, поддерживает только алгоритмы
Code Block
languagecpp
titleЗагрузка библиотеки и списка функций PKCS#11
/* Имя библиотеки PKCS#11 */
#ifdef _WIN32
/* Библиотека для Рутокен S, Рутокен Lite и Рутокен ЭЦП, поддерживает только алгоритмы RSA */
	#define PKCS11_LIBRARY_NAME         "rtPKCS11.dll" 
/* Библиотека для Рутокен Lite, Рутокен ЭЦП, Рутокен PINPad, поддерживает алгоритмы ГОСТ и RSA */
	#define PKCS11ECP_LIBRARY_NAME      "rtPKCS11ECP.dll"
#endif 
#ifdef __unix__
/* Библиотека для Рутокен Lite, Рутокен ЭЦП, Рутокен PINPad, поддерживает алгоритмы ГОСТ и RSA */
	#define PKCS11_LIBRARY_NAME         "librtpkcs11ecp.so"
	#define PKCS11ECP_LIBRARY_NAME      "librtpkcs11ecp.so"
#endif 	
#ifdef __APPLE__
/* Библиотека для Рутокен Lite, Рутокен ЭЦП, Рутокен PINPad, поддерживает алгоритмы ГОСТ и RSA */
	#define PKCS11_LIBRARY_NAME         "librtpkcs11ecprtPKCS11.dylib"dll" 
/* Библиотека для Рутокен Lite, Рутокен ЭЦП, Рутокен PINPad, поддерживает алгоритмы ГОСТ и RSA */
	#define PKCS11ECP_LIBRARY_NAME      "librtpkcs11ecprtPKCS11ECP.dylibdll"
#endif 	

HMODULE hModule = NULL_PTR;           #ifdef __unix__
/* Библиотека для Рутокен Lite, Рутокен ЭЦП, Рутокен PINPad, поддерживает алгоритмы ГОСТ и RSA */
	#define PKCS11_LIBRARY_NAME         "librtpkcs11ecp.so"
	#define PKCS11ECP_LIBRARY_NAME      "librtpkcs11ecp.so"
#endif 	
#ifdef __APPLE__
/* Библиотека для Рутокен Lite, Рутокен ЭЦП, Рутокен PINPad, поддерживает //алгоритмы ХэндлГОСТ загруженнойи библиотекиRSA PKCS#11
CK_FUNCTION_LIST_PTR pFunctionList = NULL_PTR;        */
	#define PKCS11_LIBRARY_NAME         "librtpkcs11ecp.dylib"
	#define PKCS11ECP_LIBRARY_NAME      "librtpkcs11ecp.dylib"
#endif 	

HMODULE hModule = NULL_PTR;          //  Указатель на список функций PKCS#11, хранящийся в структуре CK_FUNCTION_LIST
CK_C_GetFunctionList pfGetFunctionList = NULL_PTR;              // УказательХэндл назагруженной функциюбиблиотеки C_GetFunctionListPKCS#11
CK_RV rvFUNCTION_LIST_PTR pFunctionList = CKRNULL_OKPTR;                  // Указатель на список функций PKCS#11, хранящийся в структуре CK_FUNCTION_LIST
CK_C_GetFunctionList pfGetFunctionList = NULL_PTR;              // Указатель //на Вспомогательная переменная для хранения кода возврата
 
while (TRUE)
{
	/* Загрузить библиотеку */
	printf("Loading library %s", PKCS11ECP_LIBRARY_NAME);
	hModule = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
	if (hModule == NULL_PTR)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");

	/* Получить адрес функции запроса структуры с указателями на функции */	
	printf("Getting GetFunctionList function");
	pfGetFunctionList = (CK_C_GetFunctionList)GetProcAddress(hModule, "C_GetFunctionList"функцию C_GetFunctionList
CK_RV rv = CKR_OK;                                              // Вспомогательная переменная для хранения кода возврата
 
while (TRUE)
{
	/* Загрузить библиотеку */
	printf("Loading library %s", PKCS11ECP_LIBRARY_NAME);
	hModule = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
	if (pfGetFunctionListhModule == NULL_PTR)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
 
	/* Получить структуруадрес сфункции указателями запроса структуры с указателями на функции */	
	printf("Getting GetFunctionList function list");
	rvpfGetFunctionList = pfGetFunctionList(&pFunctionList(CK_C_GetFunctionList)GetProcAddress(hModule, "C_GetFunctionList");
	if (rvpfGetFunctionList !== CKRNULL_OKPTR)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
	... 
	break;
}
 
/* Получить структуру Выгрузитьс библиотекууказателями изна памятифункции */
if (hModule)
{
	printf("UnloadingGetting function librarylist");
	rv = pfGetFunctionList(&pFunctionList);
	if (FreeLibrary(hModule)rv != TRUE)CKR_OK)
	{
		printf(" -> Failed\n");
	else	break;
	}
	printf(" -> OK\n");
	...
	break;
}
 
/* Выгрузить библиотеку из памяти */
if (hModule)
{
	printf("Unloading library");
	if (FreeLibrary(hModule) != NULL_PTR;
}TRUE)
		printf(" -> Failed\n");
	else
		printf(" -> OK\n");
	hModule = NULL_PTR;
}

Инициализация и Инициализация и деинициализация библиотеки

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

...

Code Block
languagecpp
titleИнициализация библиотеки
...
 
/* Инициализировать библиотеку */
printf("Initializing library");
rv = pFunctionList->C_Initialize(NULL_PTR);
if (rv != CKR_OK)
	printf(" -> Failed\n");
else
	printf(" -> OK\n");

...
 
/* Деинициализировать библиотеку */
if (pFunctionList)
{
	printf("Finalizing library");
	rvTemp = pFunctionList->C_Finalize(NULL_PTR);
	if (rvTemp != CKR_OK)
		printf(" -> Failed\n");
	else
		printf(" -> OK\n");
	pFunctionList = NULL_PTR;
}

...

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

...

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

...

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

При вызове C_WaitForSlotEvent() с флагом CKF_DONT_BLOCK функция возвращает код CKR_NO_EVENT при отсутствии событий или код CKR_OK при его наличии (вместе с идентификатором соответствующего событию слота).

При вызове C_WaitForSlotEvent() с флагом 0 выполнение функции блокируется до возникновения события и функция возвращает код CKR_OK и номер соответствующего слота.

...

Определение типа устройств

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

Code Block
languagecpp
titleОпределение класса токена
CK_C_EX_GetFunctionListExtended pfGetFunctionListEx = NULL_
Code Block
languagecpp
titleОпределение класса токена
CK_C_EX_GetFunctionListExtended pfGetFunctionListEx = NULL_PTR; 	// Указатель на функцию C_EX_GetFunctionListExtended
CK_FUNCTION_LIST_EXTENDED_PTR 	pFunctionListEx = NULL_PTR;       	// Указатель на список функций расширения PKCS#11, хранящийся в структуре CK_FUNCTION_LIST_EXTENDED
CK_TOKEN_INFO_EXTENDED			tokenInfoEx;                        // Структура данных типа CK_TOKEN_INFO_EXTENDED с информацией о токене
 
...
 
printf(" Determining token type");
 
/* Получить адрес функции запроса структуры с указателями на функции расширения */
pfGetFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(hModule,
			                                                          "C_EX_GetFunctionListExtended");
if (pfGetFunctionListEx == NULL_PTR)
{
	printf(" -> Failed\n");
	break;
}
 
/* Получить структуру с указателями на функции расширения */
rv = pfGetFunctionListEx(&pFunctionListEx);

if (rv != CKR_OK)
{
	printf(" -> Failed\n");
	break;
}
memset(&tokenInfoEx,
	   0,
	   sizeof(CK_TOKEN_INFO_EXTENDED));
tokenInfoEx.ulSizeofThisStructure = sizeof(CK_TOKEN_INFO_EXTENDED);
 
/* Получить расширенную информацию о подключенном токене */
rv = pFunctionListEx->C_EX_GetTokenInfoExtended(aSlots[0],		// Идентификатор слота, к которому подключен токен
			                                    &tokenInfoEx);	// Буфер для помещения информации о токене
if (rv != CKR_OK)
{
	printf(" -> Failed\n");
	break;
}
/* Определить класс токена */
if (tokenInfoEx.ulTokenClass == TOKEN_CLASS_S)
{
	bIsRutokenPINPad = FALSE;
	printf(": Rutoken / Rutoken S\n");
}
else if (tokenInfoEx.ulTokenClass == TOKEN_CLASS_ECP)
{
	bIsRutokenPINPad = FALSE;
	printf(": Rutoken ECP\n");
}
else if (tokenInfoEx.ulTokenClass == TOKEN_CLASS_LITE)
{
	bIsRutokenPINPad = FALSE;
	printf(": Rutoken Lite\n");
}
else if (tokenInfoEx.ulTokenClass == TOKEN_CLASS_WEB)
{
	bIsRutokenPINPad = FALSE;
	printf(": Rutoken WEB\n");
}
else if (tokenInfoEx.ulTokenClass == TOKEN_TYPE_RUTOKEN_PINPAD_FAMILY)
{
	bIsRutokenPINPad = TRUE;
	printf(": Rutoken PINPad\n");
}
else
{
	bIsRutokenPINPad = FALSE;
	printf(": undefined\n");
}

Открытие и закрытие сессии

// Про колбэк

Code Block
languagecpp
titleМониторинг событий в слотах
CK_SESSION_HANDLE hSession = NULL_PTR;       // Хэндл открытой сессии

...
 
/* Открыть RW сессию в первом доступном слоте */
printf("Opening Session");
rv = pFunctionList->C_OpenSession(aSlots[0], 								// Идентификатор слота
								  CKF_SERIAL_SESSION | CKF_RW_SESSION,		// Флаги сессии
								  NULL_PTR,
								  NULL_PTR,
								  &hSession);								// Хэндл сессии
if (rv != CKR_OK)
	printf(" -> Failed\n");
else
	printf(" -> OK\n");
 
...
 
/* Закрыть все открытые сессии в слоте */
printf("C_CloseAllSession");
rv = pFunctionList->C_CloseAllSessions(aSlots[0]);
if (rvTemp != CKR_OK)
	printf(" -> Failed\n");
else
	printf(" -> OK\n");
hSession = NULL_PTR;

...

Code Block
languagecpp
titleМониторинг событий в слотах
/* DEMO PIN-код Пользователя Рутокен */
CK_UTF8CHAR      USER_PIN[]      = {'1', '2', '3', '4', '5', '6', '7', '8'};
 
...
 
/* Выполнить аутентификацию Пользователя */
printf("Logging in");
rv = pFunctionList->C_Login(hSession,				// Хэндл сессии
							CKU_USER,				// Тип пользователя
							USER_PIN,				// PIN-код пользователя
							sizeof(USER_PIN));		// Длина PIN-кода
if (rv != CKR_OK)
	printf(" -> Failed\n");
else
	printf(" -> OK\n");
 
...
 
/*Сбросить права доступа */
printf("Logging out");
rv = pFunctionList->C_Logout(hSession);
if ((rv == CKR_OK) || (rv == CKR_USER_NOT_LOGGED_IN))
	printf(" -> OK\n");
else
	printf(" -> Failed\n");

...

Пример генерации ключевой пары

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

Code Block
languagecpp
titleГенерация ключевой пары ГОСТ Р 34.10-2001
/* Вычисление размера массива */
#define 		 arraysize(a)   (sizeof(a)/sizeof(a[0]))
 
CK_MECHANISM     KeyGenMech	 = {CKM_GOSTR3410_KEY_PAIR_GEN, NULL_PTR, 0}; // Генерация ключа ГОСТ Р 34.10-2001
 
CK_OBJECT_HANDLE hPublicKey	 = NULL_PTR;    // Хэндл открытого ключа
CK_OBJECT_HANDLE hPrivateKey = NULL_PTR;    // Хэндл закрытого ключа

... 
printf("\n Generating key pair");
rv = pFunctionList->C_GenerateKeyPair(hSession,                             // Хэндл открытой сессии
			                          &KeyGenMech,                          // Используемый механизм генерации ключевой пары 
			                          GOST34_10_2001PublicKey,              // Шаблон открытого ключа 
			                          arraysize(GOST34_10_2001PublicKey),   // Размер шаблона открытого ключа
			                          GOST34_10_2001PrivateKey,             // Шаблон закрытого ключа 
			                          arraysize(GOST34_10_2001PrivateKey),  // Размер шаблона закрытого ключа
			                          &hPublicKey,                      	// Хэндл открытого ключа
			                          &hPrivateKey);                    	// Хэндл закрытого ключа
if (rv != CKR_OK)
	printf(" -> Failed\n");
else
	printf(" -> OK\n");

...

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

...

Устройства Рутокен поддерживают следующие типы секретных ключей (CK_KEY_TYPE

  • CKK_GENERIC_SECRET для SECRET для абстрактных ключей произвольной длины,

  • CKK_GOST28147 для ключей ГОСТ 28147-89.

...

Code Block
languagecpp
titleШаблон секретного ключа ГОСТ 28147-89
CK_OBJECT_CLASS ocPubKey 		= CKO_SECRET_KEY; 
CK_UTF8CHAR 	SecKeyLabel[] 	= {"GOST Secret Key"}; 
CK_BYTE 		SecKeyID[] 		= {"GOST Secret Key"}; 
CK_KEY_TYPE 	KeyType 		= CKK_GOST28147; 
CK_BBOOL 		bTrue 			= CK_TRUE; 
CK_BBOOL 		bFalse 			= CK_FALSE; 
CK_BYTE 	GOST28147params[]	= { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01 }; // Параметры алгоритма ГОСТ 28147-89
 
   
CK_ATTRIBUTE attrGOST28147_89SecKey[] =
{
	{ CKA_CLASS, &ocSeckey, sizeof(ocSeckey)},              // Объект секретного ключа ГОСТ 28147-89
	{ CKA_LABEL, &SecKeyLabel, sizeof(SecKeyLabel) - 1},    // Метка ключа
	{ CKA_ID, &SecKeyID, sizeof(SecKeyID) - 1},             // Идентификатор ключа
	{ CKA_KEY_TYPE, &KeyType, sizeof(KeyType)},       		// Тип ключа
	{ CKA_ENCRYPT, &bTrue, sizeof(bTrue)},                  // Ключ предназначен для зашифрования
	{ CKA_DECRYPT, &bTrue, sizeof(bTrue)},                  // Ключ предназначен для расшифрования
	{ CKA_TOKEN, &bTrue, sizeof(bTrue)},                    // Ключ является объектом токена
	{ CKA_PRIVATE, &bFalse, sizeof(bFalse)},                // Ключ доступен без авторизации на токене
	{ CKA_VENDOR_KEY_CONFIRM_OP, &bTrue, sizeof(bTrue) }, 	// Операция шифрования/расшифрования требует подтверждения на PINPad (только для Рутокен PINPad)
	{ CKA_VENDOR_KEY_PIN_ENTER, &bTrue, sizeof(bTrue) }, 	// Операция шифрования/расшифрования требует ввода PIN-кода на PINPad (только для Рутокен PINPad)
	{ CKA_GOST28147_PARAMS, GOST28147params, sizeof(GOST28147params)} // Параметры алгоритма 
};

...

Пример генерации секретного ключа

Для генерации секретного ключа предназначена функция C_GenerateKey(), в которую передается механизм генерации и шаблон ключа.

Code Block
languagecpp
titleГенерация симметричного ключа ГОСТ 28147-89
/* Вычисление размера массива */
#define 		 arraysize(a)   (sizeof(a)/sizeof(a[0]))
 
CK_MECHANISM     KeyGenMech	 = {CKM_GOST28147_KEY_GEN, NULL_PTR, 0}; // Генерация ключа ГОСТ 28147-89
 
CK_OBJECT_HANDLE hSecKey	 = NULL_PTR;    						// Хэндл cекретного ключа
 
...
printf("\n Generating key");
rv = pFunctionList->C_GenerateKey(hSession,                             // Хэндл открытой сессии
			                      &KeyGenMech,              			// Используемый механизм генерации ключа
			                      attrGOST28147_89SecKey,               // Шаблон для создания секретного ключа
			                      arraysize(attrGOST28147_89SecKey),    // Размер шаблона секретного ключа
			                      &hSecKey);                   			// Хэндл секретного ключа
if (rv != CKR_OK)
	printf(" -> Failed\n");
else
	printf(" -> OK\n");


Импорт // TO DO Импорт ключа

Удаление // TO DO Удаление объектов

Вычисление значения хеш-функции

...

  • CKM_GOSTR3410 подписи алгоритмом ГОСТ Р 34.10.2001,
  • CKM_GOSTR3410_WITH_GOSTR3411 для совместного хеширования алгоритмом CKM_GOSTR3411 и подписи алгоритмом CKM_GOSTR3410,
  • CKM_GOSTR3410_512 для подписи алгоритмом ГОСТ Р 34.10.2012 с длиной закрытого ключа 512 бит,
  • CKM_GOSTR3410_WITH_GOSTR3411_12_256 для совместного хеширования алгоритмом CKM_GOSTR3411_12_256 и подписи на ключе длиной 256 бит,

  • CKM_GOSTR3410_WITH_GOSTR3411_12_512 для совместного хеширования алгоритмом  CKM_GOSTR3411_12_512 и подписи на ключе длиной 512 бит,

  • CKM_RSA_PKCS для подписи алгоритмом RSA.

Сырая подпись

  • 256 и подписи на ключе длиной 256 бит,

  • CKM_GOSTR3410_WITH_GOSTR3411_12_512 для совместного хеширования алгоритмом  CKM_GOSTR3411_12_512 и подписи на ключе длиной 512 бит,

  • CKM_RSA_PKCS для подписи алгоритмом RSA.

Сырая подпись

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

При использовании совместных алгоритмов хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411) в C_Sign() передается открытый текст для подписи, при использовании только алгоритма подписи (например, CKM_GOSTR3410)  -- уже прохешированные данные.

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

Code Block
languagecpp
titleПодпись данных по алгоритму ГОСТ Р 34.10-2001
/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 */
CK_MECHANISM    SigVerMech = {CKM_GOSTR3410, NULL_PTR, 0};
 
...
 
/* Инициализировать операцию подписи данных */
printf("C_SignInit");
rv = pFunctionList->C_SignInit( hSession,		// Хэндл сессии
								&SigVerMech,	// Механизм подписи
								hPrivateKey ); 	// Хэндл закрытого ключа
if (rv != CKR_OK)
{
	printf(" -> Failed\n");
	break;
}
printf(" -> OK\n");
 
/* Определить размер подписанных данных */
printf("C_Sign step 1");
rv = pFunctionList->C_Sign( hSession,			// Хэндл сессии
							pbHash,				// Буфер с данными для подписи
							ulHashSize,			// Длина подписываемых данных
							pbtSignature,		// Буфер с подписанными данными
							&ulSignatureSize);	// Длина подписанных данных
if (rv != CKR_OK)
{
	printf(" -> Failed\n");
	break;
}
printf(" -> OK\n");

pbtSignature = (CK_BYTE*)malloc(ulSignatureSize);
memset( pbtSignature,
		0,
		ulSignatureSize * sizeof(CK_BYTE));


/* Подписать исходные данные */
printf("C_Sign step 2");
rv = pFunctionList->C_Sign( hSession,			// Хэндл сессии
							pbHash,				// Буфер с данными для подписи
							ulHashSize,			// Длина подписываемых данных
							pbtSignature,		// Буфер с подписанными данными
							&ulSignatureSize);	// Длина подписанных данных
if (rv != CKR_OK)
if (rv != CKR_OK)
{
	printf(" -> Failed\n");
	break;
}
printf(" -> OK\n");


/* Распечатать буфер, содержащий подпись */
printf("Signature buffer is: \n");
for (i = 0;
	 i < ulSignatureSize;
	 i++)
{
	printf("%02X ", pbtSignature[i]);
	if ((i + 1) % 8 == 0)
		printf("\n");
}

 

Подпись в формате CMS

Формат входных данных

...

  • CKM_GOST28147_ECB для шифрования алгоритмом ГОСТ 28147-89 в режиме простой замены,
  • CKM_GOST28147 для шифрования алгоритмом ГОСТ 28147-89 в режиме сцепления блоковрежимах гаммирования и гаммирования с обратной связью,
  • CKM_RSA_PKCS для шифрования алгоритмом RSA.

Режим гаммирования

Режим гаммирования с обратной связью

Генерация запроса PKCS#10

...