Page tree

Versions Compared

Key

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

...

Warning

Устройства Рутокен, сертифицированные ФСБ, не поддерживают создание (импорт) ключей функцией C_CreateObject по алгоритмам ГОСТ 28147-89, ГОСТ Р 34.10-2001 и ГОСТ Р 34.10-2012 в долговременную память (с флагом CKA_TOKEN = TRUE).

...

Warning

Устройства Рутокен, сертифицированные ФСБ, не поддерживают создание (импорт) ключей функцией C_CreateObject по алгоритмам ГОСТ 28147-89, ГОСТ Р 34.10-2001 и ГОСТ Р 34.10-2012 в долговременную память (с флагом CKA_TOKEN = TRUE).

...

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

  • CKK_GOST28147 для ключей ГОСТ 28147-89,
  • CKK_MAGMA для использования в алгоритмах шифрования ГОСТ 34.12-2018 (ГОСТ Р 34.12-2015) с длиной блока 128 бит,
  • CKK_KUZNECHIK для использования в алгоритмах шифрования ГОСТ 34.12-2018 (ГОСТ Р 34.12-2015) с длиной блока 64 бит,
  • CKK_MAGMA_TWIN_KEY для использования в алгоритме экспорта и импорта ключей ГОСТ Р 1323565.1.017-2018, построенном на основании блочного шифра «Магма»,

  • CKK_KUZNECHIK_TWIN_KEY для использования в алгоритме экспорта и импорта ключей ГОСТ Р 1323565.1.017-2018, построенном на основании блочного шифра «Кузнечик»,

...

Code Block
languagecpp
titleПолучение MAC от данных по алгоритму ГОСТ Р 34.12-2015
/* Данные для хеширования в виде двоичной строки */
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 };

/*  Механизм выработки имитовставки ГОСТ 28147-89 */
CK_MECHANISM gost28147MacMech = {CKM_GOST28147_MAC, NULL_PTR, 0};
/*  Механизм выработки имитовставки ГОСТ Р 34.12-2015 */
CK_MECHANISM kuznechikMacMech = { CKM_KUZNECHIK_MAC, NULL_PTR, 0 };
CK_MECHANISM magmaMacMech = { CKM_MAGMA_MAC, NULL_PTR, 0 };
 
CK_BYTE_PTR pbtMac 	= NULL_PTR;            // Указатель на буфер для значения MAC
CK_ULONG 	ulMacSize 	= 0;               // Размер буфера в байтах
 
while(TRUE)
{
	...
 
	/* Инициализировать операцию взятия MAC*/
	printf("C_SignInit");
	rv = functionList->C_SignInit(hSession,					// Хэндл сессии
								  &kuznechikMacMech,	    // Механизм взятия MAC
								  hSecretKey);              // Хендл секретного ключа, на котором вычисляем MAC
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");

	/* Определить размер значения MAC */
	printf("C_Sign step 1");
	rv = pFunctionList->C_Sign(   hSession,				// Хэндл сессии
								  pbtData,				// Буфер с данными для хеширования
								  arraysize(pbtData),	// Размер данных для хеширования
								  pbtMac,				// Буфер для вычисленного значения хеша
								  &ulMacSize);			// Размер значения хеша
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");

	pbtMac = (CK_BYTE*)malloc(ulMacSize);
	if (pbtHash == NULL)
	{
		printf("Memory allocation for pbtMac failed! \n");
		break;
	}
	memset(pbtMac,
		   0,
		   (ulMacSize * sizeof(CK_BYTE)));
	/* Вычислить MAC от исходных данных */
	printf("C_Sign step 2");
	rv = pFunctionList->C_Sign(  hSession,				// Хэндл сессии
								 pbtData,				// Буфер с данными для хеширования
								 arraysize(pbtData),	// Размер данных для хеширования
								 pbtMac,				// Буфер для вычисленного значения хеша
								 &ulMacSize);			// Размер значения хеша
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
	break;
}
 

...

Code Block
languagecpp
titleПроверка MAC от данных по алгоритму ГОСТ Р 34.12-2015
/* Данные для хеширования в виде двоичной строки */
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 };

/*  Механизм выработки MAC ГОСТ Р 34.12-2015 */
CK_MECHANISM kuznechikMacMech = { CKM_KUZNECHIK_MAC, NULL_PTR, 0 };
CK_MECHANISM magmaMacMech = { CKM_MAGMA_MAC, NULL_PTR, 0 };
 
while(TRUE)
{
	...
 
	/* Инициализировать операцию проверки MAC*/
	printf("C_VerifyInit");
	rv = functionList->C_VerifyInit(hSession,				  // Хэндл сессии
								    &kuznechikMacMech,	      // Механизм взятия MAC
								    hSecretKey); 		      // Хендл секретного ключа, на котором вычисляем MAC
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");

	/* Проверка MAC */
	printf("C_Verify");
	rv = pFunctionList->C_Verify( hSession,				// Хэндл сессии
								  pbtData,				// Буфер с данными для хеширования
								  arraysize(pbtData),	// Размер данных для хеширования
								  pbtMac,				// Буфер для вычисленного значения хеша
								  &ulMacSize);			// Размер значения хеша
	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_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.
  • CKM_MD5_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA224_RSA_PKCS, CKM_SHA256_RSA_PKCS, CKM_SHA384_RSA_PKCS, CKM_SHA512_RSA_PKCS для алгоритма взятия хеша с последующим взятием подписи по алгоритму RSA
  • CKM_ECDSA для подписи алгоритмом ECDSA.

...

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

...

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

...

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

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

...

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

...

Code Block
languagecpp
titleПроверка подписи
while(TRUE)
{
	...
	/* Инициализировать операцию проверки подписи */
	printf(" C_VerifyInit");
	rv = pFunctionList->C_VerifyInit(hSession,    	// Хэндл сессии
									 &SigVerMech,	// Механизм подписи
									 hPublicKey);	// Хэндл открытого ключа
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
	
	/* Проверить подпись для исходных данных */
	printf(" C_Verify");
	rv = pFunctionList->C_Verify(hSession,   		// Хэндл сессии
								 pbHash,			// Буфер с значением хеша исходногосообщения
								 ulHashSize,		// Длина буфера
								 pbtSignature,		// Буфер с подписью
								 ulSignatureSize);	// Длина подписи
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
	break;
}
...
if (pbtSignature)
{
	free(pbtSignature);
	pbtSignature = NULL_PTR;
}
 
if (pbHash)
{
	free(pbHash);
	pbHash= NULL_PTR;
}

...

Поточная подпись и

...

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

При работе с большим количеством данных бывает удобно отправлять данные токену частями. При таком режиме работе с токеном необходимо использовать функции C_SignInit/C_VerifyInitC_SignUpdate/C_VerifyUpdate и C_SignFinal/C_VerifyFinal

Code Block
languagecpp
titleПример подписи данных в несколько итераций
	/* Инициализировать операцию подписи данных */
	printf("C_SignInit");
	rv = pFunctionList->C_SignInit( hSession,		// Хэндл сессии
									&SigVerMech256,	// Механизм подписи (SigVerMech256 или SigVerMech512)
									hPrivateKey ); 	// Хэндл закрытого ключа
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
 	
	for (size_t i=0; i < dataLen; i+=blockLen)
	{
	  size_t len = (dataLen-i) < blockLen? (dataLen-i) : blockLen;
	  // подпись отдельных блоков данных
	  rv = pFunctionList->C_SignUpdate( hSession,			// Хэндл сессии
	  									pData + i,			// Буфер с данными для подписи
	  									len);				// Длина подписываемых данных
											
	  if (rv != CKR_OK)
	  	break;
    }
	
	if (rv != CKR_OK)
	{
	  printf(" -> Failed\n");
	  break;
	}
	printf(" -> OK\n");

	/* Определить размер подписи*/
	printf("C_SignFinal step 1");
	rv = pFunctionList->C_SignFinal(hSession,			// Хэндл сессии
									pbtSignature,		// Буфер с подписью
									&ulSignatureSize);	// Длина подписи
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");

	pbtSignature = (CK_BYTE*)malloc(ulSignatureSize);
	if (pbtSignature  == NULL)
	{
		printf("Memory allocation for pbtSignature failed! \n");
		break;
	}
	memset( pbtSignature,
			0,
			ulSignatureSize * sizeof(CK_BYTE));

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


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

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

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

  • CKM_GOST28147_ECB для шифрования алгоритмом ГОСТ 28147-89 в режиме простой замены,
  • CKM_GOST28147 для шифрования алгоритмом ГОСТ 28147-89 в режиме гаммирования с обратной связью (программное и аппаратное),
  • CKM_KUZNECHIK_ECB для шифрования алгоритмом Кузнечик в режиме простой замены (ГОСТ 34.13-2018),
  • CKM_KUZNECHIK_CTR_ACPKM для шифрования алгоритмом Кузнечик в режиме гаммирования CTR с мешингом ACPKM (Р 1323565.1.017-2018),
  • CKM_MAGMA_ECB для шифрования алгоритмом Магма в режиме простой замены (ГОСТ 34.13-2018),
  • CKM_MAGMA_CTR_ACPKM для шифрования алгоритмом Магма в режиме гаммирования CTR с мешингом ACPKM (Р 1323565.1.017-2018),
  • CKM_RSA_PKCS для шифрования алгоритмом RSA.
Warning
titleВнимание!

Так как в режиме простой замены (механизм CKM_GOST28147_ECB)

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

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

  • CKM_GOST28147_ECB для шифрования алгоритмом ГОСТ 28147-89 в режиме простой замены,
  • CKM_GOST28147 для шифрования алгоритмом ГОСТ 28147-89 в режиме гаммирования с обратной связью (программное и аппаратное),
  • CKM_KUZNECHIK_ECB для шифрования алгоритмом Кузнечик в режиме простой замены (ГОСТ 34.13-2018),
  • CKM_KUZNECHIK_CTR_ACPKM для шифрования алгоритмом Кузнечик в режиме гаммирования CTR с мешингом ACPKM (ГОСТ 34.13-2018),
  • CKM_MAGMA_ECB для шифрования алгоритмом Магма в режиме простой замены (ГОСТ 34.13-2018),
  • CKM_MAGMA_CTR_ACPKM для шифрования алгоритмом Магма в режиме гаммирования CTR с мешингом ACPKM (ГОСТ 34.13-2018),
  • CKM_RSA_PKCS для шифрования алгоритмом RSA.
Warning
titleВнимание!

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

...

Сначала операцию шифрования нужно инициализировать вызовом функции C_EncryptInit(), передав в нее идентификатор сессии, механизма и секретного ключа. В параметрах механизмов для ГОСТ 28147-89 и ГОСТ Р 34.12-2015 можно задать вектор инициализации и его длину.

...

Code Block
languagecpp
titleШифрование данных по алгоритмам ГОСТ 28147-89 в режиме гаммирования с обратной связью и ГОСТ 34.12-2015 в режиме гаммирования CTR с мешингом ACPKM
/* Данные для шифрования */
CK_BYTE 	pbtData[] 	= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	                 	 	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
	                 		0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
	                  		0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00 };
 
CK_BYTE	 	IV[]  	 	= {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,};		// Значение вектора инициализации для алгоритма ГОСТ 28147-89 

// Механизмы CKM_KUZNECHIK_CTR_ACPKM и CKM_MAGMA_CTR_ACPKM используют два параметра: 
// период смены ключа и синхропосылку, длина которой равна половине длины блока.
// Параметры задаются в виде последовательно записанного периода смены ключа 32-битного целого, 
// представленного в BigEndian формате и синхропосылки в виде байтового массива.
// Если период смены ключа установлен в нуль, ключ по алгоритму ACPKM не меняется и механизм совпадает с режимом CTR, описанном в ГОСТ Р 34.13-2018.
CK_BYTE	 	kuznechikEncMechParams[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };	// Параметры алгоритма Кузнечик ГОСТ Р 34.12-2015
CK_BYTE     magmaEncMechParams[]     = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };	                        // Параметры алгоритма Магма ГОСТ Р 34.12-2015


/* Механизм шифрования/расшифрования  */
CK_MECHANISM	EncDecStreamMech   	= 
	{CKM_GOST28147, IV, sizeof(IV)}; // по алгоритму ГОСТ 28147-89 в режиме гаммирования с обратной связью
//    { CKM_KUZNECHIK_CTR_ACPKM, &kuznechikEncMechParams, sizeof(kuznechikEncMechParams) };  // по алгоритму Кузнечик ГОСТ Р 34.12-2015 в режиме гаммирования CTR с мешингом ACPKM
//    { CKM_MAGMA_CTR_ACPKM, &magmaEncMechParams, sizeof(magmaEncMechParams) };              // по алгоритму Магма ГОСТ Р 34.12-2015 в режиме гаммирования CTR с мешингом ACPKM

CK_BYTE_PTR 	pbtEncryptedData 	= NULL_PTR;         // Указатель на буфер, содержащий зашифрованные данные
CK_ULONG 		ulEncryptedDataSize = 0;                // Размер буфера с зашифрованными данными, в байтах 
CK_ULONG 		ulBlockSize 		= 32;				// Размер блока данных, в байтах
CK_ULONG 		ulCurrentPosition 	= 0;				// Текущее начало блока
CK_ULONG 		ulRestLen			= 0;				// Размер оставшегося буфера, в байтах
 
while(TRUE)
{
	...
	/* Инициализировать операцию шифрования */
	printf("C_EncryptInit");
	rv = pFunctionList->C_EncryptInit(hSession,				// Хэндл сессии
			                          &EncDecStreamMech,	// Механизм шифрования
			                          hSecKey);				// Хэндл секретного ключа
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");

	/* Зашифровать открытый текст */
	ulEncryptedDataSize = arraysize(pbtData);
	ulRestLen = arraysize(pbtData);
	pbtEncryptedData = (CK_BYTE*)malloc(ulEncryptedDataSize);
	if (pbtEncryptedData == NULL)
	{
		printf("Memory allocation for pbtEncryptedData failed! \n");
		break;
	}
	memset( pbtEncryptedData,
			0,
			(ulEncryptedDataSize * sizeof(CK_BYTE)));

	while (ulRestLen)
	{
		if (ulBlockSize > ulRestLen)
			ulBlockSize = ulRestLen;
		printf("Block size: %u B (Total: %u of %u) ", ulBlockSize, ulCurrentPosition + ulBlockSize, ulEncryptedDataSize);
		rv = pFunctionList->C_EncryptUpdate(hSession,								// Хэндл сессии
											pbtData + ulCurrentPosition,			// Буфер с блоком данных для шифрования
											ulBlockSize,							// Размер блока, в байтах
											pbtEncryptedData + ulCurrentPosition,	// Буфер с блоком зашифрованных данных
											&ulBlockSize);							// Размер блока, в байтах
		if (rv != CKR_OK)
		{
			printf(" -> Failed\n");
			break;
		}
		printf(" -> OK\n");

		ulCurrentPosition += ulBlockSize;
		ulRestLen -= ulBlockSize;
	}		
	if (rv != CKR_OK)
		break;

	printf("Finalizing encryption");
	rv = pFunctionList->C_EncryptFinal( hSession, 					// Хэндл сессии
										NULL_PTR,					// Буфер с последним блоком данных 
										&ulEncryptedDataSize);		// Длина буфера
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
	/* Распечатать буфер, содержащий зашифрованные данные*/
	printf("Encrypted buffer is:\n");
	for (i = 0;
		 i < ulEncryptedDataSize;
	     i++)
	{
		printf("%02X ", pbtEncryptedData[i]);
		if ((i + 1) % 8 == 0)
			printf("\n");
	}

	break;
}

...