...
- создание, запись, чтение, изменение, удаление двоичных файлов,
- генерация и импорт ключей шифрования ГОСТ 28147-89,
- шифрование данных по алгоритму ГОСТ 28147-89 в режимах простой замены, гаммирования и гаммирования с обратной связью,
- вычисление имитовставки по алгоритму ГОСТ 28147-89 длиной 32 бит,
- генерация последовательности случайных чисел длиной 256 бит.
Info | ||
---|---|---|
| ||
|
Рутокен Lite
Рутокен Lite – это ключевой носитель для безопасного хранения ключей шифрования и электронной подписи, паролей и других данных во встроенной защищенной памяти устройства.
...
- создание, запись, чтение, изменение, удаление двоичных файлов.
Рутокен ЭЦП 2.0
Рутокен ЭЦП 2.0 – электронный идентификатор с аппаратной реализацией отечественных и зарубежных стандартов электронной подписи, шифрования и хеширования.
Через интерфейс PKCS#11 доступны следующие возможности Рутокен ЭЦП 2.0:
- алгоритмы ГОСТ Р 34.10-2012 и ГОСТ Р 34.10-2001: генерация ключевых пар с проверкой качества, импорт ключевых пар, формирование и проверка электронной подписи,
- алгоритмы ГОСТ Р 34.11-2012 и ГОСТ Р 34.11-94: вычисление значения хеш-функции данных, в том числе с возможностью последующего формирования электронной подписи внутри устройства,
- алгоритм алгоритмы ГОСТ 28147-89: генерация и импорт ключей шифрования, шифрование данных в режимах простой замены, гаммирования и гаммирования с обратной связью, вычисление и проверка криптографической контрольной суммы данных (имитовставки).
- выработка сессионных ключей (ключей парной связи): по схемам VKO GOST R 34.10-2012 (RFC 7836), VKO GOST R 34.10-2001 (RFC 4357), расшифрование по схеме EC El-Gamal.
- алгоритм RSA: поддержка ключей размером до 2048 бит, генерация ключевых пар с настраиваемой проверкой качества, импорт ключевых пар, формирование электронной подписи.
- генерация последовательности случайных чисел требуемой длины.
Начало работы
Подключение библиотеки
Для работы с устройствами Рутокен через программный интерфейс PKCS#11 приложение должно предварительно загрузить библиотеку, содержащую реализацию функций и механизмов стандарта PKCS#11.
Рутокен SDK предоставляет две библиотеки rtPKCS11 и rtPKCS11ECP, подробнее об особенностях выбора и использования которых можно ознакомиться в разделе Использование библиотек rtPKCS11 и rtPKCS11ECP. Основная разница заключается в том, что российские алгоритмы доступны в библиотеке rtPKCS11ECP, а зарубежные – в rtPKCS11.
Кроме функций стандартного интерфейса PKCS#11 библиотеки экспортируют функции расширения, которые могут быть удобны при использовании специфической функциональности устройств Рутокен.
После загрузки библиотеки нужно получить адрес экспортируемой библиотекой функции C_GetFunctionList()
и вызвать ее для получения списка функций PKCS#11. Теперь все готово для работы с библиотекой.
Для работы с функциями расширения необходимо получить адрес функции CK_C_EX_GetFunctionListExtended()
и вызвать ее для получения списка функций расширения PKCS#11.
После работы с библиотекой ее нужно выгрузить из памяти.
Рутокен ЭЦП 3.0
Рутокен ЭЦП 3.0 – новый электронный идентификатор с аппаратной реализацией отечественных и зарубежных стандартов электронной подписи, шифрования и хеширования.
Через интерфейс PKCS#11 доступны следующие возможности Рутокен ЭЦП 3.0:
- алгоритмы ГОСТ Р 34.10-2012 и ГОСТ Р 34.10-2001: генерация ключевых пар с проверкой качества, импорт ключевых пар, формирование и проверка электронной подписи,
- алгоритмы ГОСТ Р 34.11-2012 и ГОСТ Р 34.11-94: вычисление значения хеш-функции данных, в том числе с возможностью последующего формирования электронной подписи внутри устройства,
- алгоритмы ГОСТ 28147-89 и ГОСТ Р 34.12-2015: генерация и импорт ключей шифрования, шифрование данных в режимах простой замены, гаммирования и гаммирования с обратной связью, вычисление и проверка криптографической контрольной суммы данных (имитовставки).
- выработка сессионных ключей (ключей парной связи): по схемам VKO GOST R 34.10-2012 (RFC 7836), VKO GOST R 34.10-2001 (RFC 4357), расшифрование по схеме EC El-Gamal.
- алгоритм RSA: поддержка ключей размером до 4096 бит, генерация ключевых пар с настраиваемой проверкой качества, импорт ключевых пар, формирование электронной подписи.
- алгоритм ECDSA с кривыми secp256k1 и secp256r1: генерация ключевых пар с настраиваемой проверкой качества, импорт ключевых пар, формирование электронной подписи.
- генерация последовательности случайных чисел требуемой длины.
Начало работы
Подключение библиотеки
Для работы с устройствами Рутокен через программный интерфейс PKCS#11 приложение должно предварительно загрузить библиотеку, содержащую реализацию функций и механизмов стандарта PKCS#11.
Рутокен SDK предоставляет две библиотеки rtPKCS11 и rtPKCS11ECP, подробнее об особенностях выбора и использования которых можно ознакомиться в разделе Использование библиотек rtPKCS11 и rtPKCS11ECP. Основная разница заключается в том, что российские алгоритмы доступны в библиотеке rtPKCS11ECP, а зарубежные – в rtPKCS11.
Кроме функций стандартного интерфейса PKCS#11 библиотеки экспортируют функции расширения, которые могут быть удобны при использовании специфической функциональности устройств Рутокен.
После загрузки библиотеки нужно получить адрес экспортируемой библиотекой функции C_GetFunctionList()
и вызвать ее для получения списка функций PKCS#11. Теперь все готово для работы с библиотекой.
Для работы с функциями расширения необходимо получить адрес функции CK_C_EX_GetFunctionListExtended()
и вызвать ее для получения списка функций расширения PKCS#11.
После работы с библиотекой ее нужно выгрузить из памяти.
Code Block | ||||
---|---|---|---|---|
| ||||
/* Имя библиотеки PKCS#11 */ #ifdef _WIN32 /* Библиотека для Рутокен S, Рутокен Lite и Рутокен ЭЦП, поддерживает только алгоритмы RSA */ #define PKCS11_LIBRARY_NAME "rtPKCS11.dll" /* Библиотека для Рутокен Lite, Рутокен ЭЦП поддерживает алгоритмы ГОСТ и RSA */ #define PKCS11ECP_LIBRARY_NAME "rtPKCS11ECP.dll" #endif #ifdef __unix__ /* Библиотека для Рутокен Lite, Рутокен ЭЦП поддерживает алгоритмы ГОСТ и RSA */ #define PKCS11_LIBRARY_NAME "librtpkcs11ecp.so" #define PKCS11ECP_LIBRARY_NAME "librtpkcs11ecp.so" #endif #ifdef __APPLE__ /* Библиотека для Рутокен Lite, Рутокен ЭЦП поддерживает алгоритмы ГОСТ и RSA */ #define PKCS11_LIBRARY_NAME "librtpkcs11ecp.dylib" #define PKCS11ECP_LIBRARY_NAME "librtpkcs11ecp.dylib" #endif HMODULE hModule = NULL_PTR; // Хэндл загруженной библиотеки PKCS#11 CK_FUNCTION_LIST_PTR pFunctionList = NULL_PTR; // Указатель на список функций PKCS#11, хранящийся в структуре CK_FUNCTION_LIST CK_C_GetFunctionList pfGetFunctionList = NULL_PTR; // Указатель на функцию C_GetFunctionList CK_RV rv = CKR_OK; // Вспомогательная переменная для хранения кода возврата while (TRUE) { /* Загрузить библиотеку */ printf("Loading library %s", PKCS11ECP_LIBRARY_NAME); hModule = LoadLibrary(PKCS11ECP_LIBRARY_NAME); if (hModule == NULL_PTR) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Получить адрес функции запроса структуры с указателями на функции */ printf("Getting GetFunctionList function"); pfGetFunctionList = (CK_C_GetFunctionList)GetProcAddress(hModule, "C_GetFunctionList"); if (pfGetFunctionList == NULL_PTR) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Получить структуру с указателями на функции */ printf("Getting function list"); rv = pfGetFunctionList(&pFunctionList); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); ... break; } /* Выгрузить библиотеку из памяти */ if (hModule) { printf("Unloading library"); if (FreeLibrary(hModule) != TRUE) printf(" -> Failed\n"); else printf(" -> OK\n"); hModule = NULL_PTR; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
CK_OBJECT_CLASS ocPrivKey = CKO_PRIVATE_KEY; CK_UTF8CHAR PrivKeyLabel[] = {"GOST Private Key"}; CK_BYTE KeyPairID[] = {"GOST keypair"}; CK_KEY_TYPE keyTypeGostR3410 = CKK_GOSTR3410; // Для закрытого ключа длиной 256 бит CK_KEY_TYPE keyTypeGostR3410_512 = CKK_GOSTR3410_512; // Для закрытого ключа длиной 512 бит CK_BBOOL bTrue = CK_TRUE; /* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-20012012(256) */ CK_BYTE paramsGostR3410parametersGostR3410_2012_256[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 }; /* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-2012(512) */ CK_BYTE paramsGostR3410parametersGostR3410_2012_512[] = { 0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02, 0x01, 0x02, 0x01 }; /* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-2012(256) */ CK_BYTE parametersGostR3411_2012_256[] = { 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x02 }; /* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-2012(512) */ CK_BYTE parametersGostR3411_2012_512[] = { 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x03 }; CK_ATTRIBUTE GOST34_10_2012_256_PrivateKey[] = { // Шаблон для ключа длиной 256 бит { CKA_CLASS, &ocPrivKey, sizeof(ocPrivKey)}, // Объект закрытого ключа { CKA_LABEL, &PrivKeyLabel, sizeof(PrivKeyLabel) - 1}, // Метка ключа { CKA_ID, &KeyPairID, sizeof(KeyPairID) - 1}, // Идентификатор ключевой пары #1 (должен совпадать у открытого и закрытого ключей) { CKA_KEY_TYPE, &keyTypeGostR3410, sizeof(keyTypeGostR3410)}, // Тип ключа { CKA_TOKEN, &bTrue, sizeof(bTrue)}, // Ключ является объектом токена { CKA_PRIVATE, &bTrue, sizeof(bTrue)}, // Ключ доступен только после авторизации на токене { CKA_DERIVE, &bTrue, sizeof(bTrue)}, // Ключ поддерживает деривацию (из него могут быть получены другие ключи) { CKA_GOSTR3410_PARAMS, parametersGostR3410_2012_256, sizeof(parametersGostR3410_2012_256)}, // Параметры алгоритма }; CK_ATTRIBUTE GOST34_10_2012_512_ { CKA_GOSTR3411_PARAMS, parametersGostR3411_2012_256, sizeof(parametersGostR3411_2012_256)} // Параметры алгоритма ГОСТ Р 34.11-2012(256) }; CK_ATTRIBUTE GOST34_10_2012_512_PrivateKey[] = { // Шаблон для ключа длиной 512 бит { CKA_CLASS, &ocPrivKey, sizeof(ocPrivKey)}, // Объект закрытого ключа { CKA_LABEL, &PrivKeyLabel, sizeof(PrivKeyLabel) - 1}, // Метка ключа { CKA_ID, &KeyPairID, sizeof(KeyPairID) - 1}, // Идентификатор ключевой пары #1 (должен совпадать у открытого и закрытого ключей) { CKA_KEY_TYPE, &keyTypeGostR3410_512, sizeof(keyTypeGostR3410)_512}, // Тип ключа { CKA_TOKEN, &bTrue, sizeof(bTrue)}, // Ключ является объектом токена { CKA_PRIVATE, &bTrue, sizeof(bTrue)}, // Ключ доступен только после авторизации на токене { CKA_DERIVE, &bTrue, sizeof(bTrue)}, // Ключ поддерживает деривацию (из него могут быть получены другие ключи) { CKA_GOSTR3410_PARAMS, parametersGostR3410_2012_512, sizeof(parametersGostR3410_2012_512)}, // Параметры алгоритма { CKA_GOSTR3411_PARAMS, paramsGostR3410parametersGostR3411_2012_512, sizeof(paramGostR3410parametersGostR3411_2012_512)} // Параметры алгоритма алгоритма ГОСТ Р 34.11-2012(512) }; |
Code Block | ||||
---|---|---|---|---|
| ||||
CK_OBJECT_CLASS ocPubKey = CKO_PUBLIC_KEY; CK_UTF8CHAR PubKeyLabel[] = {"GOST Public Key"}; CK_BYTE KeyPairID[] = {"GOST keypair"}; CCK_KEY_TYPE keyTypeGostR3410 = CKK_GOSTR3410; // Для закрытого ключа длиной 256 бит CK_KEY_TYPE keyTypeGostR3410_512 = CKK_GOSTR3410_512; // Для закрытого ключа длиной 512 бит CK_BBOOL bTrue = CK_TRUE; CK_BBOOL bFalse = CK_FALSE; /* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-20012012(256) */ CK_BYTE paramsGostR3410parametersGostR3410_2012_256[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 }; /* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-2012(512) */ CK_BYTE paramsGostR3410parametersGostR3410_2012_512[] = { 0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02, 0x01, 0x02, 0x01 }; /* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-2012(256) */ CK_BYTE paramsGostR3411parametersGostR3411_2012_256[] = { 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x02 }; /* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-2012(512) */ CK_BYTE paramsGostR3411parametersGostR3411_2012_512[] = { 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x03 }; CK_ATTRIBUTE GOST34_10_2012_256_PublicKey[] = { // Шаблон для открытого ключа, соответствуюзего закрытому длиной 256 бит { CKA_CLASS, &ocPubKey, sizeof(ocPubKey)}, // Объект открытого ключа { CKA_LABEL, &PubKeyLabel, sizeof(PubKeyLabel)-1}, // Метка ключа { CKA_ID, &KeyPairID, sizeof(KeyPairID)-1}, // Идентификатор ключевой пары { CKA_KEY_TYPE, &keyTypeGostR3410, sizeof(keyTypeGostR3410)}, // Тип ключа { CKA_TOKEN, &bTrue, sizeof(bTrue)}, // Ключ является объектом токена { CKA_PRIVATE, &bFalse, sizeof(bFalse)}, // Ключ доступен без авторизации на токене { CKA_DERIVE, &bTrue, sizeof(bTrue)}, // Ключ поддерживает деривацию (из него могут быть получены другие ключи) { CKA_GOSTR3410_PARAMS, paramsGostR3410, sizeof(paramsGostR3410)}, // Параметры алгоритма { CKA_GOSTR3411_PARAMS, paramsGostR3411_256, sizeof(paramsGostR3411_256)} // Параметры алгоритма }; CK_ATTRIBUTE GOST34_10_2012_512_PublicKey[] = { // Шаблон для открытого ключа, соответствуюзего закрытому длиной 512бит { CKA_CLASS, &ocPubKey, sizeof(ocPubKey)}, // Объект открытого ключа { CKA_LABEL, &PubKeyLabel, sizeof(PubKeyLabel)-1}, // Метка ключа { CKA_ID, &KeyPairID, sizeof(KeyPairID)-1}, // Идентификатор ключевой пары { CKA_KEY_TYPE, &keyTypeGostR3410_512, sizeof(keyTypeGostR3410_512)}, // Тип ключа { CKA_TOKEN, &bTrue, sizeof(bTrue)}, // Ключ является объектом токена { CKA_PRIVATE, &bFalse, sizeof(bFalse)}, // Ключ доступен без авторизации на токене { CKA_DERIVE, &bTrue, sizeof(bTrue)}, // Ключ поддерживает деривацию (из него могут быть получены другие ключи) { CKA_GOSTR3410_PARAMS, paramsGostR3410parametersGostR3410_2012_512, sizeof(paramsGostR3410parametersGostR3410_2012_512)}, // Параметры алгоритма алгоритма { CKA_GOSTR3411_PARAMS, paramsGostR3411parametersGostR3411_2012_512, sizeof(paramsGostR3411parametersGostR3411_2012_512)} // Параметры алгоритма алгоритма ГОСТ Р 34.11-2012(512) }; |
Поддерживаемые механизмы генерации ключей
...
Code Block | ||||
---|---|---|---|---|
| ||||
/* Вычисление размера массива */ #define arraysize(a) (sizeof(a)/sizeof(a[0])) CK_MECHANISM gostR3410KeyPairGenMechgostR3410_256KeyPairGenMech = {CKM_GOSTR3410_KEY_PAIR_GEN, NULL_PTR, 0}; // Механизм генерации ключевой пары ГОСТ Р 34.10-20012012(256) CK_MECHANISM gostR3410_512KeyPairGenMech = {CKM_GOSTR3410_512_KEY_PAIR_GEN, NULL_PTR, 0}; // Механизм генерации ключевой пары ГОСТ Р 34.10-2012(512) */ CK_OBJECT_HANDLE hPublicKey_256 = NULL_PTR; // Хэндл открытого ключа CK_OBJECT_HANDLE hPrivateKey_256 = NULL_PTR; // Хэндл закрытого ключа CK_OBJECT_HANDLE hPublicKey_512 = NULL_PTR; // Хэндл открытого ключа CK_OBJECT_HANDLE hPrivateKey_512 = NULL_PTR; // Хэндл закрытого ключа ... printf("Generating 256 bit key pair"); rv = pFunctionList->C_GenerateKeyPair(hSession, // Хэндл открытой сессии &gostR3410KeyPairGenMech, // Используемый механизм генерации ключевой пары GOST34_10_2012_256_PublicKey, // Шаблон открытого ключа arraysize(GOST34_10_2012_256_PublicKey), // Размер шаблона открытого ключа GOST34_10_2012_256_PrivateKey, // Шаблон закрытого ключа arraysize(GOST34_10_2012_256_PrivateKey), // Размер шаблона закрытого ключа &hPublicKey_256, // Хэндл открытого ключа &hPrivateKey_256); // Хэндл закрытого ключа if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); printf("Generating 512 bit key pair"); rv = pFunctionList->C_GenerateKeyPair(hSession, // Хэндл открытой сессии &gostR3410_512KeyPairGenMech, // Используемый механизм генерации ключевой пары GOST34_10_2012_512_PublicKey, // Шаблон открытого ключа arraysize(GOST34_10_2012_512_PublicKey), // Размер шаблона открытого ключа GOST34_10_2012_512_PrivateKey, // Шаблон закрытого ключа arraysize(GOST34_10_2012_512_PrivateKey), // Размер шаблона закрытого ключа &hPublicKey_512, // Хэндл открытого ключа &hPrivateKey_512); // Хэндл закрытого ключа if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); |
...
CKM_GOSTR3410_DERIVE
для алгоритма и ключей VKO GOST R 34.10-2001;CKM_GOSTR3410_12_DERIVE
для алгоритма и ключей VKO GOST R 34.10-2012 (256 и 512 бит).
Выработанный общий ключ согласно VKO GOST R 34.10-2001 может быть возвращен в одном из следующих форматов:
...
- флаг формата возвращаемого ключа (
CKD_NULL
илиCKD_CPDIVERSIFY_KD
), - значение открытого ключа второй стороны и его размер,
- вектор синхронизации и его длину.
Пример выработки общего ключа парной связи по алгоритму VKO GOST R 34.10-
...
2012
Code Block | ||||
---|---|---|---|---|
| ||||
/* Значение синхропосылки */ 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 = {#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[] = { 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, /************************************************************************* * Поместить в структуру типа CK_MECHANISM параметры, необходимые * * для выработки ключа обмена 0, (ckDeriveParams.ulPublicDataLen * sizeof(CK_BYTE))) /* Поместить в структуру типа CK_GOSTR3410_DERIVE_PARAMS открытый ключ получателя */ ckDeriveParams.pPublicData = &cbPubRecipientKey; ckDeriveParams.ulPublicDataLen = arraysize(cbPubRecipientKey); /* Поместить в структуру типа CK_MECHANISM параметры, необходимые для выработки общего ключа */ ckmDerivationMech.pParameter = &ckDeriveParams; ckmDerivationMech * *************************************************************************/ ulongToBuffer(deriveParameters2012_256, CKM_KDF_GOSTR3411_2012_256); ulongToBuffer(deriveParameters2012_256 + keyLengthOffset, publicKeyValueSize); memcpy(deriveParameters2012_256 + publicKeyValueOffset, publicKeyValue, publicKeyValueSize); ulongToBuffer(deriveParameters2012_256 + ukmLengthOffset, ukmSize); memcpy(deriveParameters2012_256 + ukmDataOffset, ukm, ukmSize); gostR3410_12DerivationMech.pParameter = deriveParameters2012_256; gostR3410_12DerivationMech.ulParameterLen = sizeof(ckDeriveParamsderiveParameters2012_256); /* Выработать общий ключ ГОСТ 28147-89 на основании закрытого ключа отправителя и открытого ключа получателя */ printf("C_DeriveKey"); rv = pFunctionList->C_DeriveKey(hSession, // Хэндл открытой с правами Пользователя сессии &ckmDerivationMech2001, gostR3410_12DerivationMech, // Механизм ключевого обмена hPrivateKey, // Хэндл закрытого ключа отправителя attrGOST28147DerivedKey, // Шаблон создания общего ключа arraysize(attrGOST28147DerivedKey), // Размер шаблона &hDerivedKey_1); // Хэндл общего выработанного ключа if (rv != CKR_OK) { printf(" -> Failed\n"); breakgoto exit; } 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"); breakgoto exit; } printf(" -> OK\n"); /* Выделить необходимое количество памяти для значения атрибута */ attrDerivedKeyValue.pValue = (CK_BYTE*)malloc(attrDerivedKeyValue.ulValueLen); if (attrDerivedKeyValue.pValue == NULL) { printf("Memory allocation for attrDerivedKeyValue failed! \n"); breakgoto exit; } 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"); breakgoto exit; } 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; }exit: 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"); |
Маскирование секретного ключа
Для маскирования (шифрования) симметричного ключа используются функция C_WrapKey()
для маскирования и C_UnwrapKey()
для обратной процедуры.
секретного ключа
Для маскирования (шифрования) симметричного ключа используются функция C_WrapKey()
для маскирования и C_UnwrapKey()
для обратной процедуры.
В этом примере мы генерируем случайным образом сессионный ключ (CEK), а затем маскируем его общим ключом KEK, полученным из С помощью функции маскирования вычисляется значение сессионного ключа (CEK) для алгоритмов VKO GOST R 34.10-2001 и VKO GOST R 34.10-2012. В качестве значения сессионного ключа для маскирования используется случайно сгенерированная строка. Затем сессионный ключ шифруется (маскируется) полученным с помощью функции C_Derive()
общим ключом KEK .
Code Block | ||||
---|---|---|---|---|
| ||||
/* Размер симметричного ключа ГОСТ 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) алгоритма ГОСТ 28147-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; // Хэндл ключа, который будет маскироваться/демаскироваться /*Установить параметры в структуре типа CK_MECHANISM для маскирования ключа*/ ckmWrapMech.ulParameterLen = 8; GenerateRandomData(ckmWrapMech.ulParameterLen, (PBYTE *)&ckmWrapMech.pParameter); /* Заполнить шаблон сессионного ключа случайными данными */ GenerateRandomData(GOST_28147_KEY_SIZE, &pbtSessionKey); for (i = 0; i < // Размер буфера со значением демаскированного на стороне получателя сессионного ключа, в байтах CK_OBJECT_HANDLE hTempKey = NULL_PTR;arraysize(attrGOST28147KeyToWrap); i++) if (attrGOST28147KeyToWrap[i].type == CKA_VALUE) { attrGOST28147KeyToWrap[i].pValue = pbtSessionKey; attrGOST28147KeyToWrap[i].ulValueLen = GOST_28147_KEY_SIZE; break; } /************************************************************************* * Маскирование ключа // Хэндл ключа, который будет маскироваться/демаскироваться 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"); breakgoto wrap_exit; } 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"); breakgoto wrap_exit; } printf(" -> OK\n"); pbtWrappedKey = (CK_BYTE*)malloc(ulWrappedKeySize); if (pbtWrappedKey == NULL) { printf("Memory allocation for pbtWrappedKey failed! \n"); breakgoto wrap_exit; } 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"); breakgoto wrap_exit; } 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"); } wrap_exit: if (hTempKey) { pFunctionList->C_DestroyObject(hSession, hTempKey); hTempKey = NULL_PTR; } break; } if (hTempKey) { pFunctionList->C_DestroyObject(hSession, if (rv == CKR_OK) printf("\nWrapping has been completed successfully.\n"); else { printf("\nWrapping failed!\n"); goto exit; } /************************************************************************* * Демаскирование ключа 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"); breakgoto 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"); breakgoto unwrap_exit; } printf(" -> OK\n"); /* Выделить необходимое количество памяти для значения атрибута */ attrValue.pValue = (CK_BYTE*)malloc(attrValue.ulValueLen); if (attrValue.pValue== NULL) { printf("Memory allocation for attrValue failed! \n"); breakgoto 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"); breakgoto unwrap_exit; } 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; } 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"); breakgoto exit; } /* Сравнить первоначальное значение сессионного ключа со значением демаскированного ключа */ 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; } exit: printf("Finish"); |
Вычисление значения хеш-функции
...
Подпись данных отдельными механизмами хеширования и подписи
...
Пример подписи данных по алгоритму ГОСТ Р 34.10-2012 отдельными механизмами хеширования и подписи для всех устройств Рутокен
...
При использовании совместного механизма и хеширование, и подпись выполняются функцией C_Sign()
. Сначала в функцию C_SignInit()
передается совместный механизм (например, CKM_GOSTR3410_WITH_GOSTR3411
), а затем в функцию C_Sign()
– сообщение.
Пример подписи данных по алгоритму ГОСТ Р 34.10-2012 совместным механизмом хеширования и подписи
...