Page tree

Versions Compared

Key

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

...

  • флаг формата возвращаемого ключа (CKD_NULL или CKD_CPDIVERSIFY_KD),
  • значение открытого ключа второй стороны и его размер,
  • вектор синхронизации и его длину.

 

Пример выработки общего ключа парной связи по алгоритму VKO GOST R 34.10-2001 и VKO GOST R 34.10-2012

Code Block
languagebash
titleВыработка общего ключа парной связи по схеме ключевого обмена VKO GOST 34.10-2001 на стороне отправителя
/* Значение синхропосылки */
CK_BYTE cbUKM[] = {A9 3C 16 46 18 F0 31 F3};
 
/* Параметры механизма выработки общего ключа VKO GOST R 34.10-2001 */
CK_GOSTR3410_DERIVE_PARAMS ckDeriveParams	 = { CKD_CPDIVERSIFY_KDF,// Формат выходных данных: CKD_CPDIVERSIFY_KD - диверсифицированный KEK (для VKO GOST R 34.10-2001), 
																	// CKD_NULL - не диверсифицированный KEK
												NULL_PTR, 			// Значение открытого ключа
												0, 	 				// Длина открытого ключа в байтах	
												cbUKM,				// Вектор инициализации (синхропосылки)
												arraysize(cbUKM)};	// Длина синхропосылки в байтах (от 8 байт)

/* Механизм выработки общего ключа */
CK_MECHANISM    ckmDerivationMech2001         = {CKM_GOSTR3410_DERIVE, NULL_PTR, 0}; 
CK_MECHANISM    ckmDerivationMech2012         = {CKM_GOSTR3410_12_DERIVE, NULL_PTR, 0}; 
 
/* Значение открытого ключа получателя */
CK_BYTE cbPubRecipientKey[] = { FF 8D AB 7F 1C 0B 74 A5 AD 7F 0B 5F 8D 5B 3C 44 
							    58 37 98 C9 25 86 40 7E EC 6E AF 00 CB 44 65 A5 
							    22 9A 53 56 32 97 35 80 99 CA 1E 17 21 3A 96 0E 
						        21 FB C6 0F 25 5B 5D 99 4E C4 5C 42 08 7D 06 04 };
 
CK_OBJECT_CLASS ocSecKey 			= CKO_SECRET_KEY; 
CK_UTF8CHAR 	DerivedKeyLabel[] 	= {"Derived Key"}; 
CK_BYTE 		SecKeyID[] 			= {"GOST Secret Key"}; 
CK_KEY_TYPE 	KeyType 			= CKK_GOST28147; 
CK_BBOOL 		bTrue 				= CK_TRUE; 
CK_BBOOL 		bFalse 				= CK_FALSE; 

/* Шаблон для создания общего ключа */
CK_ATTRIBUTE attrGOST28147DerivedKey[] =
{
	{ CKA_CLASS, &ocSeckey, sizeof(ocSeckey)},                      // Объект секретного ключа ГОСТ 28147-89
	{ CKA_LABEL, &DerivedKeyLabel, sizeof(DerivedKeyLabel) - 1},    // Метка ключа
	{ CKA_KEY_TYPE, &KeyType, sizeof(KeyType)},               		// Тип ключа
	{ CKA_TOKEN, &bFalse, sizeof(bFalse)},                          // Ключ является объектом сессии
	{ CKA_MODIFIABLE, &bTrue, sizeof(bTrue)},                       // Ключ может быть изменен после создания
	{ CKA_PRIVATE, &bFalse, sizeof(bFalse)},                        // Ключ доступен без авторизации
	{ CKA_EXTRACTABLE, &bTrue, sizeof(bTrue)},                      // Ключ может быть извлечен и зашифрован
	{ CKA_SENSITIVE, &bFalse, sizeof(bFalse)}                       // Ключ не может быть извлечен в открытом виде
};
 
CK_ATTRIBUTE 		attrDerivedKeyValue = {CKA_VALUE, NULL_PTR, 0}; // Структура данных типа CK_ATTRIBUTE для хранения значения атрибута CKA_VALUE
CK_OBJECT_HANDLE 	hDerivedKey_1 = NULL_PTR;           			// Хэндл выработанного на стороне отправителя общего ключа
CK_OBJECT_HANDLE 	hObject,               							// Хэндл объекта
while(TRUE)
{
	...
		
	/* Выделить необходимое количество памяти для значения атрибута */
	ckDeriveParams.pPublicData = (CK_BYTE*)malloc(ckDeriveParams.ulPublicDataLen);
	if (ckDeriveParams.pPublicData == NULL)
	{
		printf("Memory allocation for aSlots failed! \n");
		break;
	}
	memset(ckDeriveParams.pPublicData,
	       0,
	       (ckDeriveParams.ulPublicDataLen * sizeof(CK_BYTE)))

	/* Поместить в структуру типа CK_GOSTR3410_DERIVE_PARAMS открытый ключ получателя */
	ckDeriveParams.pPublicData = &cbPubRecipientKey;
	ckDeriveParams.ulPublicDataLen = arraysize(cbPubRecipientKey);

 
	/* Поместить в структуру типа CK_MECHANISM параметры, необходимые для выработки общего ключа */
	ckmDerivationMech.pParameter = &ckDeriveParams;
	ckmDerivationMech.ulParameterLen = sizeof(ckDeriveParams);
 
	/* Выработать общий ключ ГОСТ 28147-89 на основании закрытого ключа отправителя и открытого ключа получателя */
	printf("C_DeriveKey");
	rv = pFunctionList->C_DeriveKey(hSession,							// Хэндл открытой с правами Пользователя сессии 
	                                &ckmDerivationMech2001,				// Механизм ключевого обмена
	                                hPrivateKey,						// Хэндл закрытого ключа отправителя
	                                attrGOST28147DerivedKey,			// Шаблон создания общего ключа
	                                arraysize(attrGOST28147DerivedKey), // Размер шаблона
	                                &hDerivedKey_1);					// Хэндл общего выработанного ключа
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
	
	/* Получить размер буфера для хранения значения атрибута CKA_VALUE*/
	printf("Getting object value size");
	rv = pFunctionList->C_GetAttributeValue(hSession,				// Хэндл открытой с правами Пользователя сессии 
	                                        hDerivedKey_1,			// Хэндл общего ключа
	                                        &attrDerivedKeyValue,	// Шаблон получения значения атрибута
	                                        1);						// Количество атрибутов в шаблоне
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");

 
	/* Выделить необходимое количество памяти для значения атрибута */
	attrDerivedKeyValue.pValue = (CK_BYTE*)malloc(attrDerivedKeyValue.ulValueLen);
	if (attrDerivedKeyValue.pValue == NULL)
	{
		printf("Memory allocation for attrDerivedKeyValue failed! \n");
		break;
	}
	memset(attrDerivedKeyValue.pValue,
	       0,
	       (attrDerivedKeyValue.ulValueLen * sizeof(CK_BYTE)));

 
	/* Получить значение общего ключа ГОСТ 28147-89 */
	printf("Getting object value");
	rv = pFunctionList->C_GetAttributeValue(hSession,				// Хэндл открытой с правами Пользователя сессии 
	                                        hDerivedKey_1,			// Хэндл общего ключа
	                                        &attrDerivedKeyValue,	// Шаблон получения значения атрибута
	                                        1);						// Количество атрибутов в шаблоне
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");

	/* Распечатать буфер со значением общего ключа ГОСТ 28147-89 */
	printf("Derived key data is:\n");
	for (i = 0;
	     i < attrDerivedKeyValue.ulValueLen;
	     i++)
	{
		printf("%02X ",  attrDerivedKeyValue.pValue[i]);
		if ((i + 1) % 8 == 0)
			printf("\n");
	}
	break;
}

if (ckDeriveParams.pPublicData)
{
	free(ckDeriveParams.pPublicData);
	ckDeriveParams.pPublicData = NULL_PTR;
	ckDeriveParams.ulPublicDataLen = 0;
}

if (attrDerivedKeyValue.pValue)
{
	free(attrDerivedKeyValue.pValue);
	attrDerivedKeyValue.pValue = NULL_PTR;
	attrDerivedKeyValue.ulValueLen= 0;
}

if (rv != CKR_OK)
{
	pFunctionList->C_DestroyObject(hSession,
	                               hDerivedKey_1);
	hDerivedKey_1 = NULL_PTR;
}
if (rv != CKR_OK)
	printf("\nDeriving failed!\n\n");
else
	printf("Deriving has been completed successfully.\n\n");
		

...

Предварительно должна быть открыта сессия чтения/записи. 

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

Code Block
languagecpp
titleХеширование данных по алгоритму ГОСТ Р 34.11-94 / ГОСТ Р 34.11-2012
/* Данные для хеширования в виде двоичной строки */
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 gostR3411_946HashMech = {CKM_GOSTR3411, NULL_PTR, 0}; 
/*  Механизм хеширования ГОСТ Р 34.11-2012(256) */
CK_MECHANISM gostR3411_12_256HashMech = {CKM_GOSTR3411_12_256, NULL_PTR, 0}; 
/*  Механизм хеширования ГОСТ Р 34.11-2012(512) */
CK_MECHANISM gostR3411_12_512HashMech = {CKM_GOSTR3411_12_512, NULL_PTR, 0 };
 
CK_BYTE_PTR pbtHash 	= NULL_PTR;            // Указатель на буфер для значения хеша данных
CK_ULONG 	ulHashSize 	= 0;                   // Размер буфера в байтах
 
while(TRUE)
{
	...
 
	/* Инициализировать операцию хеширования */
	printf("C_DigestInit");
	rv = pFunctionList->C_DigestInit(hSession,					// Хэндл сессии
								 	 &gostR3411_946HashMech );	// Механизм хеширования: необходимо выбрать соответствующий из
																// gostR3411_946HashMech, gostR3411_12_256HashMech или gostR3411_12_512HashMech 
	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);
	if (pbtHash == NULL)
	{
		printf("Memory allocation for pbtHash failed! \n");
		break;
	}
	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;
}
 

...

Особенности подписи данных на Рутокен PINPad 

...

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

...

При использовании отдельных механизмов хеширования и подписи сообщение сначала хешируется функциями C_DigestInit() и C_Digest(), а затем значение хеша подписывается функциями C_SignInit()/C_EX_SignInvisibleInit() и C_Sign()/C_EX_SignInvisible().

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

Затем вызывается функция инициализации подписи C_SignInit()/C_EX_SignInvisibleInit(), в которую передается механизм подписи (например, CKM_GOSTR3410), и сама функция подписи C_Sign()/C_EX_SignInvisible() с переданным в нее значением хеша.

Если подпись выполняется ключевой парой с атрибутом CKA_VENDOR_KEY_CONFIRM_OP равным true, то при вызове функции C_EX_SignInvisible() подпись выполняется в автоматическом режиме. Рутокен PINPad сверяет сохраненное значение хеша с переданным функцией C_EX_SignInvisible() и в случае совпадения выполняет подпись хеша и возвращает блок сформированной подписи размером 64 байта для механизма CKM_GOSTR3410 и 128 байт для механизма CKM_GOSTR3410_512.  Если значения хешей не совпадают, функция C_EX_SignInvisible() возвращает ошибку.

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

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

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

...

Пример подписи данных по алгоритму ГОСТ Р 34.10-2001 отдельными механизмами хеширования и подписи для всех устройств Рутокен

...

Пример подписи данных по алгоритму ГОСТ Р 34.10-2012 отдельными механизмами хеширования и подписи для всех устройств Рутокен

...

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

Пример подписи данных по алгоритму ГОСТ Р 34.10-2001 совместным механизмом хеширования и подписи (кроме Рутокен PINPad)

...

Пример подписи данных по алгоритму ГОСТ Р 34.10-2012 совместным механизмом хеширования и подписи (кроме Рутокен PINPad)

...

При использовании совместного механизма и хеширование, и подпись выполняются функцией C_EX_SignInvisible(). Сначала в функцию C_EX_SignInvisibleInit() передается совместный механизм (например, CKM_GOSTR3410_WITH_GOSTR3411), а затем в функцию C_EX_SignInvisible() – сообщение.

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

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

...

Пример подписи данных по алгоритму ГОСТ Р 34.10-2012 совместным механизмом хеширования и подписи для Рутокен PINPad

...