Page tree

Versions Compared

Key

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

...

Code Block
languagecpp
titleМаскирование общего выработанного ключа
/* Размер симметричного ключа ГОСТ 28147-89 в байтах */
#define     GOST_28147_KEY_SIZE     0x20
 
/* Набор параметров КриптоПро A алгоритма ГОСТ 28147-89 */
CK_BYTE 	GOST28147params[]	= { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01 }; 
 
/* Параметры для механизма маскирования/демаскирования */
CK_GOSTR3410_KEY_WRAP_PARAMS  ckWrapParams = { GOST28147params;			// Указатель параметры (OID) алгоритма ГОСТ 2817828147-89 (используется только для C_WrapKey) 
																		// Если NULL_PTR, то используется CKA_GOSTR3411PARAMS. Для C_UnwrapKey должно быть NULL_PTR
 											   sizeof(GOST28147params);	// Длина объектного идентификатора
 											   cbUKM;					// Вектор инициализации (синхропосылки), если NULL_PTR -- используется случайное значение длиной 8 байт
 											   arraysize(cbUKM);		// Длина синхропосылки (в байтах, кратно 8)
 											   hKey;					// Хэндл ключа 
}
 
/* Механизм для маскирования/демаскирования ключа */
CK_MECHANISM    ckmWrapMech                 = {CKM_GOST28147_KEY_WRAP, NULL_PTR, 0};	
 
CK_OBJECT_CLASS ocSecKey 		= CKO_SECRET_KEY; 
CK_UTF8CHAR 	WrapKeyLabel[] 	= {"GOST Wrapped Key"}; 
CK_UTF8CHAR 	UnWrapKeyLabel[]= {"GOST Unwrapped Key"}; 
CK_KEY_TYPE 	KeyType 		= CKK_GOST28147; 
CK_BBOOL 		bTrue 			= CK_TRUE; 
CK_BBOOL 		bFalse 			= CK_FALSE; 

 
/* Шаблон маскируемого ключа */
CK_ATTRIBUTE attrGOST28147KeyToWrap[] =
{
	{ CKA_CLASS, &ocSeckey, sizeof(ocSeckey)},              // Объект секретного ключа ГОСТ 28147-89
	{ CKA_LABEL, &WrapKeyLabel, sizeof(WrapKeyLabel) - 1 },	// Метка ключа
	{ CKA_KEY_TYPE, &KeyType, sizeof(KeyType)},       		// Тип ключа
	{ CKA_TOKEN, &bFalse, sizeof(bFalse)},                  // Ключ является объектом сессии
	{ CKA_MODIFIABLE, &bTrue, sizeof(bTrue)},               // Ключ может быть изменен после создания
	{ CKA_PRIVATE, &bFalse, sizeof(bFalse)},                // Ключ доступен без авторизации
	{ CKA_VALUE, NULL_PTR, 0},                              // Значение ключа
	{ CKA_EXTRACTABLE, &bTrue, sizeof(bTrue)},              // Ключ может быть извлечен и зашифрован
	{ CKA_SENSITIVE, &bFalse, sizeof(bFalse)}               // Ключ не может быть извлечен в открытом виде
};

/* Шаблон демаскированного ключа */
CK_ATTRIBUTE attrGOST28147UnwrappedKey[] =
{
	{ CKA_CLASS, &ocSeckey, sizeof(ocSeckey)},                    // Объект секретного ключа ГОСТ 28147-89
	{ CKA_LABEL, &UnWrapLabelGOST, sizeof(UnWrapLabelGOST) - 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 для хранения значения атрибута CKA_VALUE */
CK_ATTRIBUTE attrValue = {CKA_VALUE, NULL_PTR, 0};  
        
CK_OBJECT_HANDLE hDerivedKey_2;           			 // Хэндл выработанного на стороне получателя общего ключа
CK_BYTE_PTR pbtSessionKey = NULL_PTR;                // Указатель на буфер, содержащий сессионный ключ
CK_BYTE_PTR pbtWrappedKey = NULL_PTR;                // Указатель на буфер, содержащий маскированный на стороне отправителя сессионный ключ
CK_ULONG ulWrappedKeySize = 0;                       // Размер буфера со значением маскированного на стороне отправителя сессионного ключа, в байтах
CK_BYTE_PTR pbtUnwrappedKey = NULL_PTR;              // Указатель на буфер, содержащий демаскированный на стороне получателя сессионный ключ
CK_ULONG ulUnwrappedKeySize = 0;                     // Размер буфера со значением демаскированного на стороне получателя сессионного ключа, в байтах
CK_OBJECT_HANDLE hTempKey = NULL_PTR;                // Хэндл ключа, который будет маскироваться/демаскироваться


while(TRUE)
{
	...
	/*Установить параметры в структуре типа CK_MECHANISM для маскирования ключа*/
	ckmWrapMech.ulParameterLen = 8;
	GenerateRandomData(ckmWrapMech.ulParameterLen, (PBYTE *)&ckmWrapMech.pParameter);
		
	/* Заполнить шаблон сессионного ключа случайными данными */
	GenerateRandomData(GOST_28147_KEY_SIZE, &pbtSessionKey);
	for (i = 0;
		 i < arraysize(attrGOST28147KeyToWrap);
		 i++)
		if (attrGOST28147KeyToWrap[i].type == CKA_VALUE)
		{
			attrGOST28147KeyToWrap[i].pValue = pbtSessionKey;
			attrGOST28147KeyToWrap[i].ulValueLen = GOST_28147_KEY_SIZE;
			break;
		}
	while(TRUE)
	{
		/* Создать ключ, который будет маскирован */
		printf("Creating the GOST 28147-89 key to wrap");
		rv = pFunctionList->C_CreateObject(hSession,							// Хэндл сессии, открытой с правами Пользователя
				                           attrGOST28147KeyToWrap,				// Шаблон создаваемого ключа
				                           arraysize(attrGOST28147KeyToWrap),	// Размер шаблона
				                           &hTempKey);							// Хэндл созданного ключа
		if (rv != CKR_OK)
		{
			printf(" -> Failed\n");
			break;
		}
		printf(" -> OK\n");
 
		/* Получить размер буфера, содержащего значение маскированного ключа */
		printf("Defining wrapping key size");
		rv = pFunctionList->C_WrapKey(hSession,					// Хэндл сессии, открытой с правами Пользователя		
				                      &ckmWrapMech,				// Механизм маскирования
				                      hDerivedKey_1,			// Хэндл ключа, которым будет маскироваться ключ
				                      hTempKey,					// Хэндл ключа, который будет маскирован
				                      NULL_PTR,					// Указатель на буфер с маскированным ключом
				                      &ulWrappedKeySize);		// Размер маскированного ключа
		if (rv != CKR_OK)
		{
			printf(" -> Failed\n");
			break;
		}
		printf(" -> OK\n");
 
		pbtWrappedKey = (CK_BYTE*)malloc(ulWrappedKeySize);
		if (pbtWrappedKey == NULL)
		{
			printf("Memory allocation for pbtWrappedKey failed! \n");
			break;
		}		
		memset(pbtWrappedKey,
		 	  0,
		   	  ulWrappedKeySize * sizeof(CK_BYTE));
	
		/* Получить маскированный ключ на стороне отправителя */
		printf("Wrapping key");
		rv = pFunctionList->C_WrapKey(hSession,					// Хэндл сессии, открытой с правами Пользователя		
				                 	  &ckmWrapMech,				// Механизм маскирования
				                      hDerivedKey_1,			// Хэндл ключа, которым будет маскироваться ключ
				                      hTempKey,					// Хэндл ключа, который будет маскирован
				                      pbtWrappedKey,			// Указатель на буфер с маскированным ключом
				                      &ulWrappedKeySize);		// Размер маскированного ключа
		if (rv != CKR_OK)
		{
			printf(" -> Failed\n");
			break;
		}
		printf(" -> OK\n");
 
		/* Распечатать буфер, содержащий маскированный ключ */
		printf("Wrapped key data is:\n");
		for (i = 0;
			 i < ulWrappedKeySize;
	   		 i++)
		{
			printf("%02X ", pbtWrappedKey[i]);
			if ((i + 1) % 9 == 0)
				printf("\n");
		}
		break;
	}
 
	if (hTempKey)
	{
		pFunctionList->C_DestroyObject(hSession,
			                           hTempKey);
		hTempKey = NULL_PTR;
	}
		
	if (rv == CKR_OK)
		printf("\nWrapping has been completed successfully.\n");
	else
	{
		printf("\nWrapping failed!\n");
		break;
	}
 
	while (TRUE)
	{
		/* Демаскировать ключ на стороне получателя*/
		printf("Unwrapping key");
		rv = pFunctionList->C_UnwrapKey(hSession,								// Хэндл сессии, открытой с правами Пользователя	
			                            &ckmWrapMech,							// Механизм маскирования
			                            hDerivedKey_2,							// Хэндл ключа, которым был маскирован ключ
			                            pbtWrappedKey,							// Указатель на буфер с маскированным ключом
			                            ulWrappedKeySize,						// Размер буфера с маскированным ключом
			                            attrGOST28147UnwrappedKey,				// Указатель на шаблон для демаскированного ключа
			                            arraysize(attrGOST28147UnwrappedKey),	// Размер шаблона для демаскированного ключа
			                            &hTempKey);								// Указатель на буфер с маскированным ключом
		if (rv != CKR_OK)
		{
			printf(" -> Failed\n");
			break;
		}
		printf(" -> OK\n");
			
		/* Получить буфер со значением демаскированного ключа */
		printf("Getting unwrapped key value...\n");
		
		/* Получить размер буфера для хранения значения атрибута CKA_VALUE */
		printf("Getting object value size");
		rv = pFunctionList->C_GetAttributeValue(hSession,   // Хэндл сессии, открытой с правами Пользователя
		                                        hTempKey,	// Хэндл объекта, значение атрибутов которых требуется получить 
		                                        &attrValue, // Указатель на шаблон с атрибутами, значение которых требуется получить
		                                        1);			// Количество строк в шаблоне
		if (rv != CKR_OK)
		{
			printf(" -> Failed\n");
			break;
		}
		printf(" -> OK\n");

		/* Выделить необходимое количество памяти для значения атрибута */
		attrValue.pValue = (CK_BYTE*)malloc(attrValue.ulValueLen);
		if (attrValue.pValue== NULL)
		{
			printf("Memory allocation for attrValue failed! \n");
			break;
		}		
		memset(attrValue.pValue,
		       0,
		       (attrValue.ulValueLen * sizeof(CK_BYTE)));
		
		/* Получить значение атрибута CKA_VALUE */
		printf("Getting object value");
		rv = pFunctionList->C_GetAttributeValue(hSession,   // Хэндл сессии, открытой с правами Пользователя
		                                        hTempKey,	// Хэндл объекта, значение атрибутов которых требуется получить 
		                                        &attrValue, // Указатель на шаблон с атрибутами, значение которых требуется получить
		                                        1);			// Количество строк в шаблоне
		if (rv != CKR_OK)
		{
			printf(" -> Failed\n");
			break;
		}
		printf(" -> OK\n");

		/* Распечатать буфер со значением демаскированного ключа  */
		printf("Unwrapped key data:\n");
		for (i = 0;
		     i < attrValue.ulValueLen;
		     i++)
		{
			printf("%02X ", attrValue.pValue[i]);
			if ((i + 1) % 8 == 0)
				printf("\n");
		}
		break;
	}
	if (hTempKey)
	{
		pFunctionList->C_DestroyObject(hSession,
			                           hTempKey);
		hTempKey = NULL_PTR;
	}
	if (rv == CKR_OK)
		printf("Unwrapping has been completed successfully.\n\n");
	else
	{
		printf("\nUnwrapping failed!\n\n");
		break;
	}
 
	/* Сравнить первоначальное значение сессионного ключа со значением демаскированного ключа */
	if ((ulUnwrappedKeySize != GOST_28147_KEY_SIZE)
		|| (memcmp(pbtSessionKey,
		           attrValue.pValue,
		           GOST_28147_KEY_SIZE) != 0))
		printf("\nThe unwrapped key is not equal to the session key!\n");
	else
		printf("The unwrapped key is equal to the session key.\n");
	break;
}

...

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 HashMech 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,					// Хэндл сессии
								 	 &HashMechgostR3411_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;
}
 

...

  • CKM_GOSTR3410 подписи алгоритмом ГОСТ Р 34.10.2001 и ГОСТ Р 34.10.2012 с длиной закрытого ключа 256 бит,
  • CKM_GOSTR3410_WITH_GOSTR3411 для совместного хеширования алгоритмом CKM_GOSTR3411 и подписи алгоритмом CKMподписи алгоритмом 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 

...

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

...

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

...

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

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

...

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

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

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

...