Page tree

Versions Compared

Key

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

...

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

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

...

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

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

Для завершения работы с библиотекой ее нужно деинициализировать вызовом функции C_Finalize().

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_GetSlotInfo(), в которую передается идентификатор слота. Ее вызов запускает обновление информации обо всех слотах. Если токен извлечь из разъема и затем снова вставить в тот же самый разъем, то он может подключиться к любому свободному слоту, а не обязательно к тому же самому.

Мониторинг событий в слоте

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

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

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

Code Block
languagecpp
titleМониторинг событий в слотах
 

...

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;                        tokenInfoEx; // Структура данных типа CK_TOKEN_INFO_EXTENDED с информацией о токене
  
 while(TRUE)
 {
	 ...
  
	 printf("Determining token type");
  
	 /* Получить адрес функции запроса структуры с указателями на функции расширения */
	 pfGetFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(hModule,
				                                                          "C_EX_GetFunctionListExtended");
	if (pfGetFunctionListEx == NULL_PTR)
	{
		 "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");
	}

	 } break;
 }

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

// Про колбэк

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;

Получение и сброс прав доступа

В PKCS#11 доступны две роли: CKU_USER -- пользователь Рутокен, CKU_SO -- администратор Рутокен.

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");

Генерация ключевой пары

Атрибуты ключевых объектов

Все поддерживаемые устройствами Рутокен атрибуты объектов представлены в разделе Объекты PKCS #11.

Атрибуты ключевых объектов Рутокен объектов Рутокен PINPad 

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

...

Если ключ был создан с флагом повышенной защиты CKA_VENDOR_KEY_PIN_ENTER, то для подписи таким ключом таким ключом перед операцией потребуется ввести PIN-код на тачскрине устройства

Поддерживаемые типы ключей

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

  • CKK_GOSTR3410 для ключей ГОСТ  для ключей ГОСТ Р 34.10-2001,

  • CKK_GOSTR3410_512 для ключей ГОСТ Р 34.10-2012,
  • CKK_RSA для ключей RSA.

Примеры шаблонов ключей

Ниже представлены примеры шаблонов закрытого и открытого ключа ГОСТ Р 34.10-2001 с пояснениями.

...

Все поддерживаемые устройствами Рутокен атрибуты объектов представлены в разделе Объекты секретных ключей. 

Атрибуты ключевых объектов Рутокен объектов Рутокен PINPad 

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

...

Если ключ был создан с флагом повышенной защиты CKA_VENDOR_KEY_PIN_ENTER, то для шифрования таким ключом перед операцией потребуется ввести PIN-код на тачскрине устройства. 

Поддерживаемые типы ключей

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

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

  • CKK_GOST28147 для 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; 
  
 /* Набор параметров КриптоПро A алгоритма ГОСТ 28147-89 */
 CK_BYTE 	GOST28147params[]	 = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01 }; 
  
 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)} // Параметры алгоритма 
};

Поддерживаемые Поддерживаемые механизмы генерации ключей

...

  • CKM_GOST28147_KEY_GEN для генерации секретного ключа ГОСТ 28147-89 (библиотекой rtPKCS11ECP),
  • CKM_GOST_KEY_GEN для генерации секретного ключа ГОСТ 28147-89 (библиотекой rtPKCS11).

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

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

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

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

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

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

Поддерживаемые механизмы

Устройства Рутокен поддерживают следующие механизмы хеширования:

  • CKM_MD2 для хеширования алгоритмом MD2,
  • CKM_MD5 для хеширования алгоритмом MD5,
  • CKM_SHA_1 для хеширования алгоритмом SHA-1,
  • CKM_GOSTR3411 для хеширования алгоритмом ГОСТ Р 34.11.94,
  • CKM_GOSTR3411_12_256 для хеширования алгоритмом ГОСТ Р 34.11.2012 с длиной значения 256 бит,
  • CKM_GOSTR3411_12_512 для хеширования алгоритмом ГОСТ Р 34.11.2012 с длиной закрытого ключа 512 бит.

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

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

секретного ключа if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n");


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

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

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

Поддерживаемые механизмы

Устройства Рутокен поддерживают следующие механизмы хеширования:

  • CKM_MD2 для хеширования алгоритмом MD2,
  • CKM_MD5 для хеширования алгоритмом MD5,
  • CKM_SHA_1 для хеширования алгоритмом SHA-1,
  • CKM_GOSTR3411 для хеширования алгоритмом ГОСТ Р 34.11.94,
  • CKM_GOSTR3411_12_256 для хеширования алгоритмом ГОСТ Р 34.11.2012 с длиной значения 256 бит,
  • CKM_GOSTR3411_12_512 для хеширования алгоритмом ГОСТ Р 34.11.2012 с длиной закрытого ключа 512 бит.

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

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

Code Block
languagecpp
titleХеширование данных по алгоритму ГОСТ Р 34.11-94
/* Данные для хеширования в виде двоичной строки */ CK_BYTE pbtData[] = { 0x3C, 0x21, 0x50, 0x49, 0x4E, 0x50, 0x41, 0x44, 0x46, 0x49, 0x4C, 0x45, 0x20, 0x52, 0x55, 0x3E, 0x3C, 0x21, 0x3E, 0xED, 0xE5, 0xE2, 0xE8, 0xE4, 0xE8, 0xEC, 0xFB, 0xE9, 0x20, 0xF2, 0xE5, 0xEA }; /* Механизм хеширования ГОСТ Р 34.11-94 */ CK_MECHANISM HashMech = {CKM_GOSTR3411, NULL_PTR, 0};   CK_BYTE_PTR pbtHash = NULL_PTR; // Указатель на буфер для хешированных данных CK_ULONG ulHashSize = 0; // Размер буфера в байтах   while(TRUE) { ...   /* Инициализировать операцию хеширования */ printf("C_DigestInit"); rv = pFunctionList->C_DigestInit(hSession, &HashMech); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Определить размер хешированных данных */ printf("C_Digest step 1"); rv = pFunctionList->C_Digest( hSession, pbtData, arraysize(pbtData), pbtHash, &ulHashSize); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtHash = (CK_BYTE*)malloc(ulHashSize); memset(pbtHash, 0, (ulHashSize * sizeof(CK_BYTE))); /* Сформировать хеш от исходных данных */ printf("C_Digest step 2"); rv = pFunctionList->C_Digest(hSession, pbtData, arraysize(pbtData), pbtHash, &ulHashSize); 
Code Block
languagecpp
titleХеширование данных по алгоритму ГОСТ Р 34.11-94
/* Данные для хеширования в виде двоичной строки */
CK_BYTE pbtData[] = { 0x3C, 0x21, 0x50, 0x49, 0x4E, 0x50, 0x41, 0x44, 0x46, 0x49, 0x4C, 0x45, 0x20, 0x52, 0x55, 0x3E, 
					  0x3C, 0x21, 0x3E, 0xED, 0xE5, 0xE2, 0xE8, 0xE4, 0xE8, 0xEC, 0xFB, 0xE9, 0x20, 0xF2, 0xE5, 0xEA };

/*  Механизм хеширования ГОСТ Р 34.11-94 */
CK_MECHANISM HashMech = {CKM_GOSTR3411, NULL_PTR, 0}; 

 
CK_BYTE_PTR pbtHash = NULL_PTR;            // Указатель на буфер для хешированных данных
CK_ULONG ulHashSize = 0;                   // Размер буфера в байтах
 
while(TRUE)
{
	...
 
	/* Инициализировать операцию хеширования  */
	printf("C_DigestInit");
	rv = pFunctionList->C_DigestInit(hSession,
								 	 &HashMech);
	if (rv != CKR_OK)
	{
		 { printf(" -> Failed\n");
		 break;
	 }
	 printf(" -> OK\n");


	/* Определить размер хешированных данных */
	printf("C_Digest step 1");
	rv = pFunctionList->C_Digest( hSession,
								  pbtData,
								  arraysize(pbtData),
								  pbtHash,
								  &ulHashSize);
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");

	pbtHash = (CK_BYTE*)malloc(ulHashSize);
	memset(pbtHash,
		   0,
		   (ulHashSize * sizeof(CK_BYTE)));

	/* Сформировать хеш от исходных данных */
	printf("C_Digest step 2");
	rv = pFunctionList->C_Digest(hSession,
								 pbtData,
								 arraysize(pbtData),
								 pbtHash,
								 &ulHashSize);
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
	break;
}
 

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

Поддерживаемые механизмы

Устройства Рутокен поддерживают следующие механизмы подписи:

  • 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.

Формат данных для подписи, отображаемый Рутокен PINPad

Если у закрытого ключа, которым подписываются данные, выставлен флаг визуализации, перед подписью Рутокен PINPad выведет на экран подписываемые данные для проверки и будет ожидать подтверждения или отмены операции. Чтобы Рутокен PINPad мог отобразить подписываемые данные, они должны иметь определенный формат:

Code Block
languagecpp
titleФормат данных Рутокен PINPad
<!PINPADFILE RU> 	// обязательный признак строки, которая будет распознаваться Rutoken PINPad
<!>some text 		// текст, нераспознаваемый Rutoken PINPad
<N>some text 		// наименование поля
<V>some text 		// значение поля

Подпись данных 

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

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

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

...

 break; }  

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

Поддерживаемые механизмы

Устройства Рутокен поддерживают следующие механизмы подписи:

  • 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.

Формат данных для подписи, отображаемый Рутокен PINPad

Если у закрытого ключа, которым подписываются данные, выставлен флаг визуализации, перед подписью Рутокен PINPad выведет на экран подписываемые данные для проверки и будет ожидать подтверждения или отмены операции. Чтобы Рутокен PINPad мог отобразить подписываемые данные, они должны иметь определенный формат:

Code Block
languagecpp
titleФормат данных Рутокен PINPad
<!PINPADFILE RU> // обязательный признак строки, которая будет распознаваться Rutoken PINPad <!>some text // текст, нераспознаваемый Rutoken PINPad <N>some text // наименование поля <V>some text // значение поля

Подпись данных 

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

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

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

В качестве данных на подпись может быть передан запрос на сертификат, представленный в байт-коде.

Подпись на Рутокен PINPad совместным механизмом хеширования и подписи

При использовании совместного механизма хеширования и подписи в функцию C_Sign с совместным механизмом (например, CKM_GOSTR3410_WITH_GOSTR3411передается текст в специальным формате для отображения его на экране Рутокен PINPad.

При вызове функции C_Sign на экране Рутокен PINPad появится текст сообщения, а функция будет ожидать нажатия пользователем кнопки подтверждения или отказа от операции на экране Рутокен PINPad.

Если пользователь подтверждает выполнение операции, то сообщение сначала хешируется внутри Рутокен PINPad, а затем подписывается. Функция C_Sign возвращает управление и 64-байтовый блок сформированной цифровой подписи . 

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

Подпись на Рутокен PINPad отдельными механизмами хеширования и подписи

При использовании отдельных механизмов хеширования и подписи сначала в функцию C_Digest с механизмом хеширования (например, CKM_GOSTR3411передается текст в специальном формате для отображения его на экране Рутокен PINPad.

При вызове функция C_Digest вычисляет хеш и возвращает управление вместе с значением хеша. Исходное сообщение и значение хеша запоминаются внутри Рутокен PINPad.

Затем вызывается функция C_Sign с механизмом подписи (например, CKM_GOSTR3410и произвольным значением хеша. Рутокен PINPad подставляет сохраненное значение хеша вместо переданного функцией C_Sign значения и отображает на экране текст исходного сообщения. Функция C_Sign ожидает нажатия пользователем кнопки подтверждения или отказа от операции на экране Рутокен PINPad.

Если пользователь подтверждает выполнение операции, то сохраненное значение хеша в Рутокен PINPad подписывается, и функция C_Sign возвращает управление и 64-байтовый блок сформированной цифровой подписи. 

Если пользователь отклоняет операцию подписи, функция C_Sign немедленно возвращает управление и код ошибки. Вычисления цифровой подписи не производится.

 

Пример подписи данных по алгоритму ГОСТ Р 34.10-2001

Code Block
languagecpp
titleПодпись данных по алгоритму ГОСТ Р 34.10-2001
/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 */
 CK_MECHANISM    SigVerMech = {CKM_GOSTR3410, NULL_PTR, 0};
  
 /* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-1994 */
 CK_BYTE     GOST3411params[]  = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01 };
  
 /*  Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 с хешированием по алгоритму ГОСТ Р 34.11-94*/
 CK_MECHANISM    HashSigVerMech = {CKM_GOSTR3410_WITH_GOSTR3411, GOST3411params, sizeof(GOST3411params)};

 CK_BYTE_PTR pbtSignature = NULL_PTR;                 // Указатель на буфер, содержащий подпись для исходных данных
 CK_ULONG ulSignatureSize = 0;                        // Размер буфера, содержащего подпись для исходных данных, в байтах
  
 while(TRUE)
 {
	 ...
  
	 /* Инициализировать операцию подписи данных */
	 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,			 // Хэндл сессии
								 pbtHash,			 // Буфер с данными для подписи
								ulHashSize,			подписи 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,			подписи ulHashSize, // Длина подписываемых данных
								 pbtSignature,		 // Буфер с подписанными данными
								 &ulSignatureSize);	 // Длина подписанных данных
	 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 (PKCS#7)

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

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

 

Code Block
languagecpp
titleПодпись данных в формате CMS (PKCS#7)
CK_OBJECT_HANDLE hCert;			 // Хэндл сертификата
  
 ...
  
 /* Подпись данных */
 printf("PKCS7 Sign");
 rv = pFunctionListEx->C_EX_PKCS7Sign( hSession, 				// Хэндл сессии
									  pbtData, 					// Буфер с данными для подписи
									  arraysize(pbtData),		 // Размер данных для подписи
									  hCert,					 // Хэндл сертификата
									  &pbtSignature, 			// Буфер для подписанных данных 
									  &ulSignatureSize, 		// Размер подписанных данных  
									  hPrvKey, 					// Хэндл закрытого ключа, соответствующего сертификату 
									  NULL, 					 // Указатель на массив сертификатов
									  0, 						 // Размер массива
									  0);						 // Формат подписи: 0 0 - неотделяемая подпись (подпись вместе с исходными данными); 
																 // PKCS7_DETACHED_SIGNATURE - отделяемая подпись (подпись без исходных данных)
 if (rv != CKR_OK)
	 printf(" -> Failed\n");
 else
	 printf(" -> OK\n");

 ...
  
 /* Освобождение памяти*/
 printf("C_EX_FreeBuffer");
 rv = pFunctionListEx->C_EX_FreeBuffer(pbtSignature);
 if (rv != CKR_OK)
	 printf(" -> Failed\n");
 else
	 printf(" -> OK\n");


Проверка подписи

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

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

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

Поддерживаемые механизмы

Устройства Рутокен поддерживают следующие механизмы шифрования:

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

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

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

...