Info | ||
---|---|---|
| ||
Расширенный набор примеров для встраивания содержится в Комплекте разработчика Рутокен |
Table of Contents maxLevel 4 outline true style none
...
Warning |
---|
Устройства Рутокен, сертифицированные ФСБ, не поддерживают создание (импорт) ключей функцией |
...
Warning |
---|
Устройства Рутокен, сертифицированные ФСБ, не поддерживают создание (импорт) ключей функцией |
...
CKK_GENERIC_SECRET
для абстрактных ключей произвольной длины,CKK_GOST28147
для ключей ГОСТ 28147-89,CKK_MAGMA
для использования в алгоритмах шифрования ГОСТ 34.12-2018 (ГОСТ Р 34.12-2015) с длиной блока 128 64 бит,CKK_KUZNECHIK
для использования в алгоритмах шифрования ГОСТ 34.12-2018 (ГОСТ Р 34.12-2015) с длиной блока 64 128 бит,CKK_MAGMA_TWIN_KEY
для использования в алгоритме экспорта и импорта ключей ГОСТ Р 1323565.1.017-2018, построенном на основании блочного шифра «Магма»,CKK_KUZNECHIK_TWIN_KEY
для использования в алгоритме экспорта и импорта ключей ГОСТ Р 1323565.1.017-2018, построенном на основании блочного шифра «Кузнечик»,
...
- kdf – идентификатор механизма диверсификации. Может быть использован один из двух механизмов:
- CKD_NULL - нет диверсификации
- CKD_CPDIVERSIFY_KDF
- pPublicData – открытый ключ получателя
- pUKM – имитовставкасинхропосылка
VKO GOST R 34.10-2012 (256 бит и 512 бит)
...
- 4 байта (little-endian, т.е. младшие байты сначала) представляют собой значение KDF. Значение определяет механизм диверсификации:
- CKD_NULL - нет диверсификации
- CKM_KDF_4357
- CKD_CPDIVERSIFY_KDF
- CKM_KDF_GOSTR3411_2012_256
- 4 байта (little-endian) задают длину открытого ключа в байтах. (для 256 бит – это 64. Для 512 бит – 128)
- открытый ключ (n-байтовый вектор в little-endian), длина которого определена предыдущим полем
- 4 байта (little-endian) задают длину UKM (от 8 байт)
- UKM (n-байтовый вектор в little-endian) , длина определена выше.
...
- pLabel, pSeed – строки задающие параметры label и seed.
- ulR – количество байт в счетчике итераций, с возможными значениями 1, 2, 3, 4.
- ulL – необходимая байтовая длина вырабатываемого ключевого материала.
- ulOffset – байтовое смещение, в последовательности ключевого материала, начиная с которого полученные байты используются для получения диверсифицированного ключа.
CKM
...
_GOST_KEG
Механизм CKM_VENDOR_GOST_KEG позволяет вырабатывать двойственный ключ из закрытого ключа отправителя и открытого ключа получателя.
...
Для задания параметров механизма используется структура CK_VENDORECDH1_GOST_KEGDERIVE_PARAMS:
Code Block | ||||
---|---|---|---|---|
| ||||
typedef struct CK_VENDORECDH1_GOST_KEGDERIVE_PARAMS { CK_EC_BYTEKDF_PTRTYPE pPublicDatakdf; CK_ULONG ulPublicDataLenulSharedDataLen; CK_BYTE_PTR pUKMpSharedData; CK_ULONG ulUKMLenulPublicDataLen; } CK_VENDOR_GOST_KEG_PARAMSBYTE_PTR pPublicData; }; |
- pPublicData – открытый ключ получателя
- pUKM – имитовставкасинхропосылка.
Пример выработки общего ключа парной связи по алгоритму VKO GOST R 34.10-2012
Code Block | ||||
---|---|---|---|---|
| ||||
/* Размер синхропосылки в байтах */ #define UKM_LENGTH 8 #define DERIVE_PARAMS_256_LENGTH 84 /************************************************************************* * Параметры для выработки ключа обмена по схеме VKO GOST R 34.10-2012-256* * Содержат в себе данные по диверсификации ключа, открытый ключ и UKM * *************************************************************************/ CK_BYTE deriveParameters2012_256[DERIVE_PARAMS_256_LENGTH] = { 0x00, }; const CK_ULONG keyLengthOffset = 4; // Смещение длины ключа в массиве const CK_ULONG publicKeyValueOffset = 8; // Смещение значения ключа в массиве const CK_ULONG ukmLengthOffset = 72; // Смещение длины UKM в массиве const CK_ULONG ukmDataOffset = 76; // Смещение UKM в массиве /************************************************************************* * Функция записи четырёхбайтного значения длины в буфер * *************************************************************************/ void ulongToBuffer(CK_BYTE_PTR buffer, CK_ULONG value) { buffer[0] = value & 0xFF; buffer[1] = (value >> 8) & 0xFF; buffer[2] = (value >> 16) & 0xFF; buffer[3] = (value >> 24) & 0xFF; } /* Механизм выработки ключа обмена по алгоритму VKO GOST R 34.10-2012 */ CK_MECHANISM gostR3410_12DerivationMech = { CKM_GOSTR3410_12_DERIVE, NULL_PTR, 0 }; /* Значение открытого ключа получателя */ CK_BYTE cbPubRecipientKey[] = { 0xFF, 0x8D, 0xAB, 0x7F, 0x1C, 0x0B, 0x74, 0xA5, 0xAD, 0x7F, 0x0B, 0x5F, 0x8D, 0x5B, 0x3C, 0x44, 0x58, 0x37, 0x98, 0xC9, 0x25, 0x86, 0x40, 0x7E, 0xEC, 0x6E, 0xAF, 0x00, 0xCB, 0x44, 0x65, 0xA5, 0x22, 0x9A, 0x53, 0x56, 0x32, 0x97, 0x35, 0x80, 0x99, 0xCA, 0x1E, 0x17, 0x21, 0x3A, 0x96, 0x0E, 0x21, 0xFB, 0xC6, 0x0F, 0x25, 0x5B, 0x5D, 0x99, 0x4E, 0xC4, 0x5C, 0x42, 0x08, 0x7D, 0x06, 0x04 }; 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_BYTE ukm[UKM_LENGTH]; // Буфер, содержащий UKM CK_OBJECT_HANDLE hDerivedKey = NULL_PTR; // Хэндл выработанного общего ключа CK_OBJECT_HANDLE hObject; // Хэндл объекта ... /************************************************************************* * Установить параметры в структуре типа CK_GOSTR3410_DERIVE_PARAMS * * для выработки ключа обмена * *************************************************************************/ rv = pFunctionList->C_GenerateRandom(hSession, ukm, sizeof(ukm)); if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } /************************************************************************* * Поместить в структуру типа CK_MECHANISM параметры, необходимые * * для выработки ключа обмена * *************************************************************************/ ulongToBuffer(deriveParameters2012_256, CKM_KDF_GOSTR3411_2012_256); ulongToBuffer(deriveParameters2012_256 + keyLengthOffset, sizeof(cbPubRecipientKey)); memcpy(deriveParameters2012_256 + publicKeyValueOffset, cbPubRecipientKey, sizeof(cbPubRecipientKey)); ulongToBuffer(deriveParameters2012_256 + ukmLengthOffset, sizeof(ukm)); memcpy(deriveParameters2012_256 + ukmDataOffset, ukm, sizeof(ukm)); gostR3410_12DerivationMech.pParameter = deriveParameters2012_256; gostR3410_12DerivationMech.ulParameterLen = sizeof(deriveParameters2012_256); /* Выработать общий ключ ГОСТ 28147-89 на основании закрытого ключа отправителя и открытого ключа получателя */ printf("C_DeriveKey"); rv = pFunctionList->C_DeriveKey(hSession, // Хэндл открытой с правами Пользователя сессии &gostR3410_12DerivationMech, // Механизм ключевого обмена hPrivateKey, // Хэндл закрытого ключа отправителя attrGOST28147DerivedKey, // Шаблон создания общего ключа arraysize(attrGOST28147DerivedKey), // Размер шаблона &hDerivedKey); // Хэндл общего выработанного ключа if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } printf(" -> OK\n"); /* Получить размер буфера для хранения значения атрибута CKA_VALUE*/ printf("Getting object value size"); rv = pFunctionList->C_GetAttributeValue(hSession, // Хэндл открытой с правами Пользователя сессии hDerivedKey, // Хэндл общего ключа &attrDerivedKeyValue, // Шаблон получения значения атрибута 1); // Количество атрибутов в шаблоне if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } printf(" -> OK\n"); /* Выделить необходимое количество памяти для значения атрибута */ attrDerivedKeyValue.pValue = (CK_BYTE*)malloc(attrDerivedKeyValue.ulValueLen); if (attrDerivedKeyValue.pValue == NULL) { printf("Memory allocation for attrDerivedKeyValue failed! \n"); goto exit; } memset(attrDerivedKeyValue.pValue, 0, (attrDerivedKeyValue.ulValueLen * sizeof(CK_BYTE))); /* Получить значение общего ключа ГОСТ 28147-89 */ printf("Getting object value"); rv = pFunctionList->C_GetAttributeValue(hSession, // Хэндл открытой с правами Пользователя сессии hDerivedKey, // Хэндл общего ключа &attrDerivedKeyValue, // Шаблон получения значения атрибута 1); // Количество атрибутов в шаблоне if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } printf(" -> OK\n"); /* Распечатать буфер со значением общего ключа ГОСТ 28147-89 */ printf("Derived key data is:\n"); for (size_t i = 0; i < attrDerivedKeyValue.ulValueLen; i++) { printf("%02X ", ((CK_BYTE_PTR) attrDerivedKeyValue.pValue)[i]); if ((i + 1) % 8 == 0) printf("\n"); } exit: if (attrDerivedKeyValue.pValue) { free(attrDerivedKeyValue.pValue); attrDerivedKeyValue.pValue = NULL_PTR; attrDerivedKeyValue.ulValueLen = 0; } if (rv != CKR_OK) { pFunctionList->C_DestroyObject(hSession, hDerivedKey); hDerivedKey = NULL_PTR; } if (rv != CKR_OK) printf("\nDeriving failed!\n\n"); else printf("Deriving has been completed successfully.\n\n"); |
Пример выработки двойственного ключа по алгоритму
...
KEG
Code Block | ||||
---|---|---|---|---|
| ||||
/* Размер синхропосылки в байтах */ #define UKM_KEG_LENGTH 24 // Значение для ключа ГОСТ 2012-256 //#define UKM_KEG_LENGTH 16 // Значение для ключа ГОСТ 2012-512 CK_UTF8CHAR derivedKuznechikTwinKeyLabel[] = { "Derived Kuznechik twin key" }; CK_UTF8CHAR derivedMagmaTwinKeyLabel[] = { "Derived Magma twin key" }; CK_OBJECT_CLASS secretKeyObject = CKO_SECRET_KEY; CK_KEY_TYPE keyTypeKuznechikTwin = CKK_KUZNECHIK_TWIN_KEY; CK_KEY_TYPE keyTypeMagmaTwin = CKK_MAGMA_TWIN_KEY; CK_BBOOL attributeTrue = CK_TRUE; CK_BBOOL attributeFalse = CK_FALSE; /* Значение открытого ключа получателя для ГОСТ 2012-256*/ CK_BYTE cbPubRecipientKey[] = { 0xFF, 0x8D, 0xAB, 0x7F, 0x1C, 0x0B, 0x74, 0xA5, 0xAD, 0x7F, 0x0B, 0x5F, 0x8D, 0x5B, 0x3C, 0x44, 0x58, 0x37, 0x98, 0xC9, 0x25, 0x86, 0x40, 0x7E, 0xEC, 0x6E, 0xAF, 0x00, 0xCB, 0x44, 0x65, 0xA5, 0x22, 0x9A, 0x53, 0x56, 0x32, 0x97, 0x35, 0x80, 0x99, 0xCA, 0x1E, 0x17, 0x21, 0x3A, 0x96, 0x0E, 0x21, 0xFB, 0xC6, 0x0F, 0x25, 0x5B, 0x5D, 0x99, 0x4E, 0xC4, 0x5C, 0x42, 0x08, 0x7D, 0x06, 0x04 }; /************************************************************************* * Шаблон для создания двойственного ключа экспорта типа Кузнечик * *************************************************************************/ CK_ATTRIBUTE derivedTwinKeyTemplate[] = { { CKA_LABEL, &derivedKuznechikTwinKeyLabel, sizeof(derivedKuznechikTwinKeyLabel) - 1}, // Метка ключа { CKA_CLASS, &secretKeyObject, sizeof(secretKeyObject) }, Значение открытого ключа получателя для ГОСТ 2012-512*/ /*CK_BYTE cbPubRecipientKey[] = { 0xFC, 0xD5, 0xD3, 0x91, 0xEF, 0x58, 0x66, 0x50, 0x26, 0x59, 0x6C, 0x71, 0xE5, 0x89, 0x35, 0xC7, // Класс - секретный ключ { CKA_KEY_TYPE, &keyTypeKuznechikTwin, sizeof(keyTypeKuznechikTwin)}, // Тип ключа - двойственный Кузнечик { CKA_TOKEN, &attributeFalse, sizeof(attributeFalse)},0x35, 0x71, 0x28, 0xA4, 0xAD, 0x3C, 0xD5, 0x0A, 0xA3, 0xF8, 0xB1, 0xD9, 0xC1, 0x77, 0xB3, 0x17, // Ключ является объектом сессии { CKA_MODIFIABLE, &attributeTrue, sizeof(attributeTrue)},0x65, 0x0C, 0x7E, 0x6E, 0x11, 0x12, 0xC2, 0x62, 0xB3, 0xDF, 0x43, 0x32, 0x54, 0xB4, 0x7C, 0x7D, // Ключ может быть изменен после создания { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue)},0xF3, 0x3C, 0x1F, 0xD7, 0xEA, 0x02, 0xE7, 0x70, 0x15, 0xCC, 0xFC, 0x28, 0xC6, 0xAE, 0x91, 0x29, // Ключ доступен только после аутентификации на токене { CKA_EXTRACTABLE, &attributeTrue, sizeof(attributeTrue)},0x58, 0xFB, 0x75, 0x14, 0x7B, 0x0E, 0x99, 0x59, 0xF9, 0x4B, 0xE9, 0x80, 0xA5, 0xBB, 0x18, 0x8E, // Ключ может быть извлечен в зашифрованном виде { CKA_SENSITIVE, &attributeFalse, sizeof(attributeFalse)}0xED, 0x43, 0xCC, 0x8D, 0x9E, 0x39, 0x14, 0x6A, 0xBA, 0xC7, 0x5F, 0xFF, 0x02, 0x4C, 0x1C, 0x9E, // Ключ может быть извлечен в открытом виде }; /***0xFE, 0x71, 0xF2, 0xC3, 0xFD, 0xD6, 0x1C, 0x76, 0xBE, 0xCF, 0x77, 0xB6, 0xD7, 0x5D, 0xFF, 0x35, 0x3C, 0x35, 0x70, 0x78, 0x03, 0xED, 0x6E, 0x0A, 0x03, 0x65, 0xDC, 0xA4, 0xAA, 0x59, 0x8B, 0xDB };*/ /************************************************************************* * Шаблон для создания двойственного ключа экспорта типа Магма Кузнечик * *************************************************************************/ //CK_ATTRIBUTE derivedTwinKeyTemplate[] = //{ // { CKA_LABEL, &derivedMagmaTwinKeyLabelderivedKuznechikTwinKeyLabel, sizeof(derivedMagmaTwinKeyLabelderivedKuznechikTwinKeyLabel) - 1}, // Метка ключа // { CKA_CLASS, &secretKeyObject, sizeof(secretKeyObject) }, // Класс - секретный ключ // { CKA_KEY_TYPE, &keyTypeMagmaTwinkeyTypeKuznechikTwin, sizeof(keyTypeMagmaTwinkeyTypeKuznechikTwin)}, // Тип ключа - двойственный МагмаКузнечик // { CKA_TOKEN, &attributeFalse, sizeof(attributeFalse)}, // Ключ является объектом сессии // { CKA_MODIFIABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть изменен после создания // { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue)}, // Ключ доступен только после аутентификации на токене // { CKA_EXTRACTABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть извлечен в зашифрованном виде // { CKA_SENSITIVE, &attributeFalse, sizeof(attributeFalse)} // Ключ может быть извлечен в открытом виде //}; CK_MECHANISM gostKegDerifivationMech = { CKM_VENDOR_GOST_KEG, NULL_PTR, 0 }; CK_VENDOR_GOST_KEG_PARAMS keg256DeriveParams; CK_ATTRIBUTE attrDerivedKeyValue = { CKA_VALUE, NULL_PTR, 0 }; // Структура данных типа CK_ATTRIBUTE для хранения значения атрибута CKA_VALUE CK_BYTE ukm[UKM_KEG_LENGTH]; // Буфер, содержащий UKM CK_OBJECT_HANDLE hDerivedKey = NULL_PTR; // Хэндл выработанного общего ключа CK_OBJECT_HANDLE hObject; // Хэндл объекта ... //************************************************************************* * Шаблон для создания двойственного ключа экспорта типа Магма * ************************************************************************* * Установить параметры в структуре типа CK_VENDOR_GOST_KEG_PARAMS * * для выработки двлйственного ключа/ //CK_ATTRIBUTE derivedTwinKeyTemplate[] = //{ // { CKA_LABEL, &derivedMagmaTwinKeyLabel, sizeof(derivedMagmaTwinKeyLabel) - 1}, // Метка ключа // { CKA_CLASS, &secretKeyObject, sizeof(secretKeyObject) }, // Класс - секретный ключ // { CKA_KEY_TYPE, &keyTypeMagmaTwin, sizeof(keyTypeMagmaTwin)}, // Тип ключа - двойственный Магма // { CKA_TOKEN, &attributeFalse, sizeof(attributeFalse)}, // Ключ является объектом сессии // { CKA_MODIFIABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть изменен после * *************************************************************************/ rv = pFunctionList->C_GenerateRandom(hSession, ukm, sizeof(ukm)); if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } /************************************************************************* * Поместить в структуру типа CK_MECHANISM параметры, необходимые * * для выработки ключа обмена создания // { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue)}, // Ключ доступен только после аутентификации на токене // { CKA_EXTRACTABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть извлечен в зашифрованном виде // { CKA_SENSITIVE, &attributeFalse, sizeof(attributeFalse)} // Ключ может быть извлечен в открытом виде //}; CK_ECDH1_DERIVE_PARAMS keg256DeriveParams; CK_MECHANISM gostKegDerifivationMech = { CKM_GOST_KEG, &keg256DeriveParams, sizeof(keg256DeriveParams)}; CK_ATTRIBUTE attrDerivedKeyValue = { CKA_VALUE, NULL_PTR, 0 }; // Структура данных типа CK_ATTRIBUTE для хранения значения атрибута CKA_VALUE CK_BYTE ukm[UKM_KEG_LENGTH]; // Буфер, содержащий UKM CK_OBJECT_HANDLE hDerivedKey = NULL_PTR; // Хэндл выработанного общего ключа CK_OBJECT_HANDLE hObject; // * Хэндл объекта ... /*************************************************************************/ keg256DeriveParams.pPublicData = cbPubRecipientKey; keg256DeriveParams.ulPublicDataLen = sizeof(cbPubRecipientKey); keg256DeriveParams.pUKM = ukm; keg256DeriveParams.ulUKMLen = sizeof(ukm); gostR3410_12DerivationMech.pParameter = keg256DeriveParams; gostR3410_12DerivationMech.ulParameterLen = sizeof(keg256DeriveParams); /* Выработать общий ключ ГОСТ 28147-89 на основании закрытого ключа отправителя и открытого ключа получателя */ printf("C_DeriveKey"); rv = pFunctionList->C_DeriveKey(hSession, // Хэндл открытой с правами Пользователя сессии &gostR3410_12DerivationMech, // Механизм ключевого обмена hPrivateKey, // Хэндл закрытого ключа отправителя derivedTwinKeyTemplate, // Шаблон создания общего ключа arraysize(derivedTwinKeyTemplate), // Размер шаблона &hDerivedKey); // Хэндл общего выработанного ключа * Установить параметры в структуре типа CK_VENDOR_GOST_KEG_PARAMS * * для выработки двойственного ключа * *************************************************************************/ rv = pFunctionList->C_GenerateRandom(hSession, ukm, sizeof(ukm)); if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } printf(" -> OK\n"); /************************ Получить размер буфера для хранения значения атрибута CKA_VALUE*/ printf("Getting object value size"); rv = pFunctionList->C_GetAttributeValue(hSession, // Хэндл открытой с правами Пользователя сессии hDerivedKey, // Хэндл общего ключа &attrDerivedKeyValue, // Шаблон получения значения атрибута 1); // Количество атрибутов в шаблоне if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } printf(" -> OK\n"); /* Выделить необходимое количество памяти для значения атрибута */ attrDerivedKeyValue.pValue = (CK_BYTE*)malloc(attrDerivedKeyValue.ulValueLen); if (attrDerivedKeyValue.pValue == NULL) { printf("Memory allocation for attrDerivedKeyValue failed! \n"); goto exit; } memset(attrDerivedKeyValue.pValue, 0, (attrDerivedKeyValue.ulValueLen * sizeof(CK_BYTE))); /* Получить значение общего ключа ГОСТ 28147-89 */ printf("Getting object value************************************************* * Поместить в структуру типа CK_MECHANISM параметры, необходимые * * для выработки ключа обмена * *************************************************************************/ keg256DeriveParams.kdf = CKD_NULL; keg256DeriveParams.pPublicData = cbPubRecipientKey; keg256DeriveParams.ulPublicDataLen = sizeof(cbPubRecipientKey); keg256DeriveParams.pUKM = ukm; keg256DeriveParams.ulUKMLen = sizeof(ukm); gostKegDerifivationMech .pParameter = &keg256DeriveParams; gostKegDerifivationMech .ulParameterLen = sizeof(keg256DeriveParams); /* Выработать общий двойственный ключ на основании закрытого ключа отправителя и открытого ключа получателя */ printf("C_DeriveKey"); rv = pFunctionList->C_GetAttributeValueDeriveKey(hSession, // Хэндл открытой с правами Пользователя сессии hDerivedKey&gostKegDerifivationMech, // Механизм ключевого обмена hPrivateKey, // Хэндл общегозакрытого ключа отправителя &attrDerivedKeyValuederivedTwinKeyTemplate, // Шаблон получениясоздания значенияобщего атрибутаключа 1); arraysize(derivedTwinKeyTemplate), // Размер шаблона &hDerivedKey); // КоличествоХэндл атрибутовобщего ввыработанного шаблонеключа if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } printf(" -> OK\n"); /* РаспечататьПолучить буферразмер собуфера значениемдля общегохранения ключазначения ГОСТ 28147-89 атрибута CKA_VALUE*/ printf("DerivedGetting keyobject data is:\nvalue size"); for (size_t i = 0; i < attrDerivedKeyValue.ulValueLen; i++) { printf("%02X ", ((CK_BYTE_PTR)attrDerivedKeyValue.pValue)[i]); if ((i + 1) % 8 == 0) printf("rv = pFunctionList->C_GetAttributeValue(hSession, // Хэндл открытой с правами Пользователя сессии hDerivedKey, // Хэндл общего ключа &attrDerivedKeyValue, // Шаблон получения значения атрибута 1); // Количество атрибутов в шаблоне if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } exit: if (attrDerivedKeyValue.pValue) { free(attrDerivedKeyValue.pValue); printf(" -> OK\n"); /* Выделить необходимое количество памяти для значения атрибута */ attrDerivedKeyValue.pValue = (CK_BYTE*)malloc(attrDerivedKeyValue.ulValueLen); if (attrDerivedKeyValue.pValue == NULL_PTR;) { attrDerivedKeyValue.ulValueLen = 0; } if (rv != CKR_OK) { pFunctionList->C_DestroyObject(hSession, hDerivedKey); hDerivedKey = NULL_PTR; }printf("Memory allocation for attrDerivedKeyValue failed! \n"); goto exit; } memset(attrDerivedKeyValue.pValue, 0, (attrDerivedKeyValue.ulValueLen * sizeof(CK_BYTE))); /* Получить значение общего двойственного ключа */ printf("Getting object value"); rv = pFunctionList->C_GetAttributeValue(hSession, // Хэндл открытой с правами Пользователя сессии hDerivedKey, // Хэндл общего ключа &attrDerivedKeyValue, // Шаблон получения значения атрибута 1); // Количество атрибутов в шаблоне if (rv != CKR_OK) { printf("\nDeriving failed!\n -> Failed\n"); goto exit; } printf(" -> OK\n"); else/* Распечатать буфер со значением общего двойственного ключа */ printf("DerivingDerived haskey been completed successfully.\ndata is:\n"); for (size_t i = 0; i < attrDerivedKeyValue.ulValueLen; i++) { printf("%02X ", ((CK_BYTE_PTR)attrDerivedKeyValue.pValue)[i]); if ((i + 1) % 8 == 0) printf("\n"); } exit: if (attrDerivedKeyValue.pValue) { free(attrDerivedKeyValue.pValue); attrDerivedKeyValue.pValue = NULL_PTR; attrDerivedKeyValue.ulValueLen = 0; } if (rv != CKR_OK) { pFunctionList->C_DestroyObject(hSession, hDerivedKey); hDerivedKey = NULL_PTR; } if (rv != CKR_OK) printf("\nDeriving failed!\n\n"); else printf("Deriving has been completed successfully.\n\n"); |
Маскирование секретного ключа
Для получения сеансового ключ (CEK), зашифрованного на KEK с имитовставкой синхропосылкой CEK, необходимо после получения ключа функцией C_DeriveKey() использовать функцию маскирования C_WrapKey().
Для выработки сеансового ключ (CEK) в оперативной памяти токена, зашифрованного на KEK с имитовставкой CEKсинхропосылкой CEK, необходимо использовать функцию расширения C_EX_WrapKey().
...
Code Block | ||||
---|---|---|---|---|
| ||||
/* ИмитовставкаСинхропосылка для механизма импорта и экспорта ключа алгоритма KExp15 на двойственном ключе Кузнечик */ CK_BYTE gostKuznechikKExp15Ukm[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* ИмитовставкаСинхропосылка для механизма импорта и экспорта ключа алгоритма KExp15 на двойственном ключе Магма */ CK_BYTE gostMagmaKExp15Ukm[] = { 0x00, 0x00, 0x00, 0x00 }; /* Механизм импорта и экспорта ключа по алгоритму KExp15 на двойственном ключе Кузнечик */ CK_MECHANISM gostKuznechikKExp15Mech = { CKM_KUZNECHIK_KEXP_15_WRAP, &gostKuznechikKExp15Ukm, sizeof(gostKuznechikKExp15Ukm) }; /* Механизм импорта и экспорта ключа по алгоритму KExp15 на двойственном ключе Кузнечик */ CK_MECHANISM gostMagmaKExp15Mech = { CKM_MAGMA_KEXP_15_WRAP, &gostMagmaKExp15Ukm, sizeof(gostMagmaKExp15Ukm) }; CK_MECHANISM_PTR gostKExp15Mech = &gostKuznechikKExp15Mech; //CK_MECHANISM gostKExp15Mech = gostMagmaKExp15Mech; /* DEMO-метка для сессионного ключа */ CK_UTF8CHAR sessionKeyLabel[] = { "GOST 28147-89 key to wrap" }; CK_UTF8CHAR sessionKuznechikKeyLabel[] = { "Kuznechik key to wrap" }; CK_UTF8CHAR sessionMagmaKeyLabel[] = { "Magma key to wrap" }; CK_OBJECT_CLASS secretKeyObject = CKO_SECRET_KEY; CK_KEY_TYPE keyTypeGost28147 = CKK_GOST28147; CK_KEY_TYPE keyTypeKuznechik = CKK_KUZNECHIK; CK_KEY_TYPE keyTypeMagma = CKK_MAGMA; CK_BBOOL attributeTrue = CK_TRUE; CK_BBOOL attributeFalse = CK_FALSE; /************************************************************************* * Шаблон сессионного ключа типа Кузнечик * *************************************************************************/ CK_ATTRIBUTE sessionKeyTemplate[] = { { CKA_LABEL, &sessionKuznechikKeyLabel, sizeof(sessionKuznechikKeyLabel) - 1 }, // Метка ключа { CKA_CLASS, &secretKeyObject, sizeof(secretKeyObject) }, // Класс - секретный ключ { CKA_KEY_TYPE, &keyTypeKuznechik, sizeof(keyTypeKuznechik)}, // Тип ключа - Кузнечик { CKA_TOKEN, &attributeFalse, sizeof(attributeFalse)}, // Ключ является объектом сессии { CKA_MODIFIABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть изменен после создания { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue)}, // Ключ доступен только после аутентификации на токене { CKA_VALUE, NULL_PTR, 0}, // Значение ключа { CKA_EXTRACTABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть извлечен в зашифрованном виде { CKA_SENSITIVE, &attributeFalse, sizeof(attributeFalse)} // Ключ может быть извлечен в открытом виде }; /************************************************************************* * Шаблон сессионного ключа типа Магма * *************************************************************************/ //CK_ATTRIBUTE sessionKeyTemplate[] = //{ // { CKA_LABEL, &sessionMagmaKeyLabel, sizeof(sessionMagmaKeyLabel) - 1 },// Метка ключа // { CKA_CLASS, &secretKeyObject, sizeof(secretKeyObject) }, // Класс - секретный ключ // { CKA_KEY_TYPE, &keyTypeMagma, sizeof(keyTypeMagma)}, // Тип ключа - Магма // { CKA_TOKEN, &attributeFalse, sizeof(attributeFalse)}, // Ключ является объектом сессии // { CKA_MODIFIABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть изменен после создания // { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue)}, // Ключ доступен только после аутентификации на токене // { CKA_VALUE, NULL_PTR, 0}, // Значение ключа // { CKA_EXTRACTABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть извлечен в зашифрованном виде // { CKA_SENSITIVE, &attributeFalse, sizeof(attributeFalse)} // Ключ может быть извлечен в открытом виде //}; /************************************************************************* * Шаблон сессионного ключа типа ГОСТ 28147-89 * *************************************************************************/ //CK_ATTRIBUTE sessionKeyTemplate[] = //{ // { CKA_LABEL, &sessionKeyLabel, sizeof(sessionKeyLabel) - 1 }, // Метка ключа // { CKA_CLASS, &secretKeyObject, sizeof(secretKeyObject) }, // Класс - секретный ключ // { CKA_KEY_TYPE, &keyTypeGost28147, sizeof(keyTypeGost28147)}, // Тип ключа - ГОСТ 28147-89 // { CKA_TOKEN, &attributeFalse, sizeof(attributeFalse)}, // Ключ является объектом сессии // { CKA_MODIFIABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть изменен после создания // { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue)}, // Ключ доступен только после аутентификации на токене // { CKA_VALUE, NULL_PTR, 0}, // Значение ключа // { CKA_EXTRACTABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть извлечен в зашифрованном виде // { CKA_SENSITIVE, &attributeFalse, sizeof(attributeFalse)} // Ключ может быть извлечен в открытом виде //}; /************************************************************************* * Шаблон демаскированного сессионного ключа типа Кузнечик * *************************************************************************/ CK_ATTRIBUTE unwrapSessionKeyTemplate[] = { { CKA_LABEL, &sessionKuznechikKeyLabel, sizeof(sessionKuznechikKeyLabel) - 1 }, // Метка ключа { CKA_CLASS, &secretKeyObject, sizeof(secretKeyObject) }, // Класс - секретный ключ { CKA_KEY_TYPE, &keyTypeKuznechik, sizeof(keyTypeKuznechik)}, // Тип ключа - Кузнечик { CKA_TOKEN, &attributeFalse, sizeof(attributeFalse)}, // Ключ является объектом сессии { CKA_MODIFIABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть изменен после создания { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue)}, // Ключ доступен только после аутентификации на токене { CKA_EXTRACTABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть извлечен в зашифрованном виде { CKA_SENSITIVE, &attributeFalse, sizeof(attributeFalse)} // Ключ может быть извлечен в открытом виде }; /************************************************************************* * Шаблон демаскированного сессионного ключа типа Магма * *************************************************************************/ //CK_ATTRIBUTE sessionKeyTemplate[] = //{ // { CKA_LABEL, &sessionMagmaKeyLabel, sizeof(sessionMagmaKeyLabel) - 1 },// Метка ключа // { CKA_CLASS, &secretKeyObject, sizeof(secretKeyObject) }, // Класс - секретный ключ // { CKA_KEY_TYPE, &keyTypeMagma, sizeof(keyTypeMagma)}, // Тип ключа - Магма // { CKA_TOKEN, &attributeFalse, sizeof(attributeFalse)}, // Ключ является объектом сессии // { CKA_MODIFIABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть изменен после создания // { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue)}, // Ключ доступен только после аутентификации на токене // { CKA_EXTRACTABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть извлечен в зашифрованном виде // { CKA_SENSITIVE, &attributeFalse, sizeof(attributeFalse)} // Ключ может быть извлечен в открытом виде //}; /************************************************************************* * Шаблон демаскированного сессионного ключа типа ГОСТ 28147-89 * *************************************************************************/ //CK_ATTRIBUTE sessionKeyTemplate[] = //{ // { CKA_LABEL, &sessionKeyLabel, sizeof(sessionKeyLabel) - 1 }, // Метка ключа // { CKA_CLASS, &secretKeyObject, sizeof(secretKeyObject) }, // Класс - секретный ключ // { CKA_KEY_TYPE, &keyTypeGost28147, sizeof(keyTypeGost28147)}, // Тип ключа - ГОСТ 28147-89 // { CKA_TOKEN, &attributeFalse, sizeof(attributeFalse)}, // Ключ является объектом сессии // { CKA_MODIFIABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть изменен после создания // { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue)}, // Ключ доступен только после аутентификации на токене // { CKA_EXTRACTABLE, &attributeTrue, sizeof(attributeTrue)}, // Ключ может быть извлечен в зашифрованном виде // { CKA_SENSITIVE, &attributeFalse, sizeof(attributeFalse)} // Ключ может быть извлечен в открытом виде //}; /* Структура данных типа CK_ATTRIBUTE для хранения значения атрибута CKA_VALUE */ CK_ATTRIBUTE attrValue = { CKA_VALUE, NULL_PTR, 0 }; CK_OBJECT_HANDLE hDerivedTwinKey; // Хэндл выработанного двйоственного ключа 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; // Хэндл ключа, который будет маскироваться/демаскироваться ... /* Заполнить шаблон сессионного ключа случайными данными */ GenerateRandomData(GOST_28147_KEY_SIZE, &pbtSessionKey); for (int i = 0; i < arraysize(sessionKeyTemplate); i++) if (sessionKeyTemplate[i].type == CKA_VALUE) { sessionKeyTemplate[i].pValue = pbtSessionKey; sessionKeyTemplate[i].ulValueLen = GOST_KUZNECHIK_KEY_SIZE; break; } /************************************************************************* * Маскирование ключа * *************************************************************************/ /* Создать ключ, который будет маскирован */ printf("Creating the GOST 28147-89 key to wrap"); rv = pFunctionList->C_CreateObject(hSession, // Хэндл сессии, открытой с правами Пользователя sessionKeyTemplate, // Шаблон создаваемого ключа arraysize(sessionKeyTemplate), // Размер шаблона &hTempKey); // Хэндл созданного ключа if (rv != CKR_OK) { printf(" -> Failed\n"); goto wrap_exit; } printf(" -> OK\n"); /* Получить размер буфера, содержащего значение маскированного ключа */ printf("Defining wrapping key size"); rv = pFunctionList->C_WrapKey(hSession, // Хэндл сессии, открытой с правами Пользователя gostKExp15Mech, // Механизм маскирования hDerivedTwinKey, // Хэндл ключа, которым будет маскироваться ключ hTempKey, // Хэндл ключа, который будет маскирован NULL_PTR, // Указатель на буфер с маскированным ключом &ulWrappedKeySize); // Размер маскированного ключа if (rv != CKR_OK) { printf(" -> Failed\n"); goto wrap_exit; } printf(" -> OK\n"); pbtWrappedKey = (CK_BYTE*)malloc(ulWrappedKeySize); if (pbtWrappedKey == NULL_PTR) { printf("Memory allocation for pbtWrappedKey failed! \n"); goto wrap_exit; } memset(pbtWrappedKey, 0, ulWrappedKeySize * sizeof(CK_BYTE)); /* Получить маскированный ключ на стороне отправителя */ printf("Wrapping key"); rv = pFunctionList->C_WrapKey(hSession, // Хэндл сессии, открытой с правами Пользователя gostKExp15Mech, // Механизм маскирования hDerivedTwinKey, // Хэндл ключа, которым будет маскироваться ключ hTempKey, // Хэндл ключа, который будет маскирован pbtWrappedKey, // Указатель на буфер с маскированным ключом &ulWrappedKeySize); // Размер маскированного ключа if (rv != CKR_OK) { printf(" -> Failed\n"); goto wrap_exit; } printf(" -> OK\n"); /* Распечатать буфер, содержащий маскированный ключ */ printf("Wrapped key data is:\n"); for (int i = 0; i < ulWrappedKeySize; i++) { printf("%02X ", pbtWrappedKey[i]); if ((i + 1) % 9 == 0) printf("\n"); } wrap_exit: 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"); goto exit; } /************************************************************************* * Демаскирование ключа * *************************************************************************/ printf("Unwrapping key"); rv = pFunctionList->C_UnwrapKey(hSession, // Хэндл сессии, открытой с правами Пользователя gostKExp15Mech, // Механизм маскирования hDerivedTwinKey, // Хэндл ключа, которым был маскирован ключ pbtWrappedKey, // Указатель на буфер с маскированным ключом ulWrappedKeySize, // Размер буфера с маскированным ключом unwrapSessionKeyTemplate, // Указатель на шаблон для демаскированного ключа arraysize(unwrapSessionKeyTemplate), // Размер шаблона для демаскированного ключа &hTempKey); // Указатель на буфер с маскированным ключом if (rv != CKR_OK) { printf(" -> Failed\n"); goto unwrap_exit; } 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"); goto unwrap_exit; } printf(" -> OK\n"); /* Выделить необходимое количество памяти для значения атрибута */ attrValue.pValue = (CK_BYTE*)malloc(attrValue.ulValueLen); if (attrValue.pValue == NULL_PTR) { printf("Memory allocation for attrValue failed! \n"); goto unwrap_exit; } 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"); goto unwrap_exit; } printf(" -> OK\n"); /* Распечатать буфер со значением демаскированного ключа */ printf("Unwrapped key data:\n"); for (int i = 0; i < attrValue.ulValueLen; i++) { printf("%02X ", ((CK_BYTE_PTR)attrValue.pValue)[i]); if ((i + 1) % 8 == 0) printf("\n"); } unwrap_exit: 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"); goto exit; } /* Сравнить первоначальное значение сессионного ключа со значением демаскированного ключа */ if ((ulUnwrappedKeySize != GOST_KUZNECHIK_KEY_SIZE) || (memcmp(pbtSessionKey, attrValue.pValue, GOST_KUZNECHIK_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"); exit: printf("Finish"); |
...
CKM_MD2
для хеширования алгоритмом MD2 (только программно),CKM_MD5
для хеширования алгоритмом MD5 (только программно),CKM_SHA_1
для хеширования алгоритмом SHA-1 (только программно),CKM_GOSTR3411SHA256
для хеширования алгоритмом SHA-256 (только программно),CKM_SHA512
для хеширования алгоритмом SHA-512 (только программно),CKM_GOSTR3411
для для хеширования алгоритмом ГОСТ Р 34.11.94 (программно и аппаратно),CKM_GOSTR3411_12_256
для хеширования алгоритмом ГОСТ Р 34.11.2012 с длиной значения 256 бит (только программно и аппаратно),CKM_GOSTR3411_12_512
для хеширования алгоритмом ГОСТ Р 34.11.2012 с длиной закрытого ключа 512 бит (только программно и аппаратно).
Хеширование данных
...
Code Block | ||||
---|---|---|---|---|
| ||||
/* Данные для хеширования в виде двоичной строки */
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 | ||||
---|---|---|---|---|
| ||||
/* Данные для хеширования в виде двоичной строки */
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
для алгоритма взятия хеша с последующим взятием подписи по алгоритму RSACKM_ECDSA
для подписи алгоритмом ECDSA.
...
Подпись данных отдельными механизмами хеширования и подписи
...
Пример подписи данных по алгоритму ГОСТ Р 34.10-2012 отдельными механизмами хеширования и подписи для всех устройств Рутокен
...
При использовании совместного механизма и хеширование, и подпись выполняются функцией C_Sign()
. Сначала в функцию C_SignInit()
передается совместный механизм (например, CKM_GOSTR3410_WITH_GOSTR3411
), а затем в функцию C_Sign()
– сообщение.
Пример подписи данных по алгоритму ГОСТ Р 34.10-2012 совместным механизмом хеширования и подписи
...
Пример подписи данных по алгоритму ECDSA отдельными механизмами хеширования и подписи
Code Block | ||||
---|---|---|---|---|
| ||||
/************************************************************************* * Данные для цифровой подписи * ************************************************************************ * Данные для цифровой подписи****/ CK_BYTE pbtData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; CK_MECHANISM sha256Mech = { CKM_SHA256, NULL_PTR, 0 }; CK_MECHANISM ecdsaSigVerMech = { CKM_ECDSA, NULL_PTR, 0 }; CK_BYTE_PTR pbtSignature; // Указатель на буфер, содержащий цифровую подпись для данных CK_ULONG ulSignatureSize ; // Размер буфера, содержащего цифровую подпись для данных, в байтах CK_BYTE_PTR pbtHash ; // Указатель на временный буфер для хэш-кода от данных CK_ULONG ulHashSize; * *************************************************************************/ CK_BYTE pbtData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; CK_MECHANISM sha256Mech = { CKM_SHA256 // Размер временного буфера в байтах while (TRUE) { ... /* Инициализировать операцию хеширования */ rv = pFunctionList->C_DigestInit(hSession, &sha256Mech); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Определить размер значения хеша данных */ printf("C_Digest step 1"); rv = pFunctionList->C_Digest(hSession, pbtData, sizeof(pbtData), NULL_PTR, 0 }&ulHashSize); CK_MECHANISM ecdsaSigVerMech = { CKM_ECDSA, NULL_PTR, 0 }; CK_BYTE_PTR pbtSignature; // Указатель на буфер, содержащий цифровую подпись для данных CK_ULONG ulSignatureSize ; // Размер буфера, содержащего цифровую подпись для данных, в байтах CK_BYTE_PTR pbtHash ; // Указатель на временный буфер для хэш-кода от данных CK_ULONG ulHashSize; // Размер временного буфера в байтах while if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtHash = (CK_BYTE*)malloc(ulHashSize); if (pbtHash == NULL_PTR) { 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, sizeof(pbtData), pbtHash, &ulHashSize); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Инициализировать операцию подписи данных */ printf("C_SignInit"); rv = pFunctionList->C_SignInit(hSession, &ecdsaSigVerMech, hPrivateKey); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtSignature = (CK_BYTE*)malloc(ulSignatureSize); if (pbtSignature == NULL_PTR) { printf("Memory allocation for pbtSignature failed! \n"); break; } memset(pbtSignature, 0, ulSignatureSize * sizeof(CK_BYTE)); /* Подписать исходные данные */ printf("C_Sign step 2"); rv = pFunctionList->C_Sign(hSession, pbtHash, ulHashSize, NULL_PTR, &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"); } break; } |
Проверка подписи
Для проверки подписи данных служат функции C_Verify
и Init()
C_Verify()
. Сначала операцию подписи нужно инициализировать через C_VerifyInit()
, передав в нее идентификатор сессии, механизма и открытого ключа. Затем можно проверить подпись функцией C_Verify()
.
Совместные механизмы хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411)
не поддерживаются C_VerifyInit().
В
C_Verify
передаются предварительно прохешированные функцией ()
C_Digest()
исходные данные.
Code Block | ||||
---|---|---|---|---|
| ||||
while(TRUE) { ... /* Инициализировать операцию хешированияпроверки подписи */ printf(" C_VerifyInit"); rv = pFunctionList->C_DigestInitVerifyInit(hSession, &sha256Mech); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Определить размер значения хеша данных */ printf("C_Digest step 1"); rv = pFunctionList->C_Digest(hSession, pbtData, sizeof(pbtData), NULL_PTR, &ulHashSize); // Хэндл сессии &SigVerMech, // Механизм подписи hPublicKey); // Хэндл открытого ключа if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtHash = (CK_BYTE*)malloc(ulHashSize); if (pbtHash == NULL_PTR) { printf("Memory allocation for pbtHash failed! \n"); break; } memset(pbtHash, 0, (ulHashSize * sizeof(CK_BYTE))); /* СформироватьПроверить хешподпись отдля исходных данных */ printf(" C_Digest step 2Verify"); rv = pFunctionList->C_DigestVerify(hSession, pbtData, sizeof(pbtData), pbtHash, &ulHashSize); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Инициализировать операцию подписи данных */ printf("C_SignInit"); rv = pFunctionList->C_SignInit(hSession, &ecdsaSigVerMech, hPrivateKey); // Хэндл сессии pbHash, // Буфер с значением хеша исходногосообщения ulHashSize, // Длина буфера pbtSignature, // Буфер с подписью ulSignatureSize); // Длина подписи if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtSignature = (CK_BYTE*)malloc(ulSignatureSize break; } ... if (pbtSignature) { free(pbtSignature); if (pbtSignature == NULL_PTR; } if (pbHash) { printf("Memory allocation for pbtSignature failed! \n"free(pbHash); breakpbHash= NULL_PTR; }} |
Поточная подпись и проверка подписи
При работе с большим количеством данных бывает удобно отправлять данные токену частями. При таком режиме работе с токеном необходимо использовать функции C_SignInit/C_VerifyInit
, C_SignUpdate/C_VerifyUpdate
и C_SignFinal/C_VerifyFinal
.
Code Block | ||||
---|---|---|---|---|
| ||||
/* Инициализировать операцию подписи данных memset(pbtSignature, 0, ulSignatureSize * sizeof(CK_BYTE)); /* Подписать исходные данные */ printf("C_Sign step 2SignInit"); rv = pFunctionList->C_SignSignInit( hSession, pbtHash, ulHashSize, NULL_PTR, &ulSignatureSize); // Хэндл сессии &SigVerMech256, // Механизм подписи (SigVerMech256 или SigVerMech512) hPrivateKey ); // Хэндл закрытого ключа 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("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; } |
Проверка подписи
Для проверки подписи данных служат функции C_Verify
и Init()
C_Verify()
. Сначала операцию подписи нужно инициализировать через C_VerifyInit()
, передав в нее идентификатор сессии, механизма и открытого ключа. Затем можно проверить подпись функцией C_Verify()
.
Совместные механизмы хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411)
не поддерживаются C_VerifyInit().
В
C_Verify
передаются предварительно прохешированные функцией ()
C_Digest()
исходные данные.
Code Block | ||||
---|---|---|---|---|
| ||||
while(TRUE) { ... /* Инициализировать операцию проверки подписи } printf(" -> OK\n"); /* Определить размер подписи*/ printf(" C_VerifyInitSignFinal step 1"); rv = pFunctionList->C_VerifyInitSignFinal(hSession, // Хэндл сессии &SigVerMechpbtSignature, // Буфер Механизмс подписиподписью hPublicKey&ulSignatureSize); // ХэндлДлина открытого ключаподписи if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /*pbtSignature Проверить подпись для исходных данных */ = (CK_BYTE*)malloc(ulSignatureSize); if (pbtSignature == NULL) { printf(" C_VerifyMemory allocation for pbtSignature failed! \n"); rv = pFunctionList->C_Verify(hSession, // Хэндл сессии break; } memset( pbtSignature, 0, pbHash, // Буфер с значением хеша исходногосообщения ulHashSize, // Длина буфера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"); break; } ... if (pbtSignature) { free(pbtSignature); pbtSignature = NULL_PTR; } if (pbHash) { free(pbHash); pbHash= NULL_PTR; } |
Шифрование и расшифрование
...
CKM_GOST28147_ECB
для шифрования алгоритмом ГОСТ 28147-89 в режиме простой замены,CKM_GOST28147
для шифрования алгоритмом ГОСТ 28147-89 в режиме гаммирования с обратной связью (программное и аппаратное),CKM_KUZNECHIK_ECB
для шифрования алгоритмом Кузнечик в режиме простой замены (ГОСТ 34.13-2018),CKM_KUZNECHIK_CTR_ACPKM
для шифрования алгоритмом Кузнечик в режиме гаммирования CTR с мешингом ACPKM (ГОСТ 34.13Р 1323565.1.017-2018),CKM_MAGMA_ECB
для шифрования алгоритмом Магма в режиме простой замены (ГОСТ 34.13-2018),CKM_MAGMA_CTR_ACPKM
для шифрования алгоритмом Магма в режиме гаммирования CTR с мешингом ACPKM (ГОСТ 34.13Р 1323565.1.017-2018),CKM_RSA_PKCS
для шифрования алгоритмом RSA.
...
Сначала операцию шифрования нужно инициализировать вызовом функции C_EncryptInit()
, передав в нее идентификатор сессии, механизма и секретного ключа. В параметрах механизмов для ГОСТ 28147-89 и ГОСТ Р 34.12-2015 можно задать вектор инициализации и его длину.
...
Code Block | ||||
---|---|---|---|---|
| ||||
/* Данные для шифрования */ 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; } |
...