- Где скачать бесплатно бессрочную лицензию КриптоПро CSP 4
- Временная лицензия КриптоПро CSP 4
- Активация лицензии КриптоПро CSP 4. 0 по серийному номеру
- Сколько стоит лицензия КриптоПро 4
- Вычисление значения хеш-функции
- Поддерживаемые механизмы
- Хеширование данных
- Пример хеширования данных по алгоритму ГОСТ Р 34. 11-94 и ГОСТ Р 34. 11-2012
- Можно ли скачать бесплатно бессрочную лицензию КриптоПро CSP 5
- Бессрочная лицензия КриптоПро CSP 5. 0 бесплатно
- Выработка сеансового симметричного ключа
- VKO GOST R 34.10-2001
- VKO GOST R 34.10-2012 (256 бит и 512 бит)
- KDF_TREE_GOSTR3411_2012_256
- CKM_GOST_KEG
- Пример выработки общего ключа парной связи по алгоритму VKO GOST R 34.10- 2012
- Пример выработки двойственного ключа по алгоритму KEG
- Маскирование секретного ключа
- Пример экспорта и импорта ключа по алгоритму Kexp15
Где скачать бесплатно бессрочную лицензию КриптоПро CSP 4
CSP CryptoPro — платный продукт. Передача прав на использование программы осуществляется на основании лицензионного соглашения. Лицензию можно заказать непосредственно на сайте разработчика или приобрести у официальных дилеров.
Бессрочную лицензию КриптоПро CSP 4.0 нельзя скачать бесплатно, но можно воспользоваться тестовым периодом, в течение которого клиенту предоставляется доступ к демонстрационной версии СКЗИ.
Оформим ЭЦП за один день без вашего участия!
Оставьте заявку и получите консультацию в течение 5 минут.
Временная лицензия КриптоПро CSP 4
Временная лицензия КриптоПро CSP 4.0 действует 90 дней. На этот период пользователь получает бесплатный доступ к полному набору инструментов, имеет возможность изучить функциональность, на практике протестировать софт и принять окончательное решение по дальнейшей эксплуатации продукта.
Примечание! Тестовый период предоставляется только при первой установке ПО. При повторной инсталляции такая возможность не предусмотрена.
По истечении 3 месяцев необходимо приобрести бессрочную или годовую лицензию. Лицензированной программой можно пользоваться только на одном рабочем месте. Если на предприятии планируется поставить СКЗИ для нескольких сотрудников, лицензионный ключ придется покупать на каждый компьютер.
Для серверных операционных систем пользовательская лицензия не подойдет — необходимо приобрести специальный лицензионный ключ для сервера. Лицензирование осуществляется по принципу: 1 серверная машина — 1 лицензионный ключ (независимо от количества подключенных пользователей).
Активация лицензии КриптоПро CSP 4. 0 по серийному номеру
Лицензия на право пользования СКЗИ состоит из сублицензионного договора и бланка с серийным номером. После оплаты ее можно лично забрать у дистрибьютора, заказать доставку или получить в электронном виде на e-mail. Для активации лицензии КриптоПро CSP 4.0 необходимо запустить криптопровайдер:
- Перейдите в меню «Пуск» → «Все программы» → «КРИПТО-ПРО» → «КриптоПро CSP».
- Откройте вкладку «Общие» и нажмите на клавишу «Ввод лицензии».
- В открывшемся окне «Сведения о пользователе» укажите Ф. И. О. владельца, наименование предприятия и серийный номер (с бланка лицензии).
- Подтвердите операцию нажатием «ОК».
После активации права на использование программы в поле «Срок действия» появится статус «Постоянная» или дата окончания срока, а в «Тип лицензии» — «Клиентская» или «Серверная».
Сколько стоит лицензия КриптоПро 4
На сайте компании размещена подробная информация о том, сколько стоит лицензия КриптоПро 4.0 в зависимости от типа лицензирования и наличия дополнительных возможностей. Зайдите в раздел «Приобретение» в ЛК, выберете «Продукты/купить» и кликните на ссылку с нужным ПО. Откроется таблица с перечнем лицензий и кнопкой формирования заказа.
На июнь 2019 года одна бессрочная клиентская лицензия КриптоПро стоит 2 700 р. (годовая — 500 р.). Если к пакету добавить круглосуточный бессрочный доступ на портал техподдержки, цена увеличивается до 4 950 р. Лицензия на сервер обойдется пользователям в разы дороже — порядка 37 500 р.
При обновлении устаревших релизов до версии 4.0 владельцу ЭЦП также придется доплатить за лицензию (1 125 р.), поскольку серийный номер 3.6, 3.8 или 3.9 не подойдет для четвертой сборки. Лицензионный ключ на обновление серверной версии стоит 9 тыс. р. Отметим, лицензии на программное обеспечение не облагаются НДС.
Вам будет интересно: КриптоПро 4.0 — возможности и инструкция по установке
Вычисление значения хеш-функции
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы хеширования:
- CKM_MD2 для хеширования алгоритмом MD2 (только программно),
- CKM_MD5 для хеширования алгоритмом MD5 (только программно),
- CKM_SHA_1 для хеширования алгоритмом SHA-1 (только программно),
- CKM_SHA256 для хеширования алгоритмом 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 бит (программно и аппаратно).
Хеширование данных
Для хеширования данных служат функции C_DigestInit() и C_Digest(). Сначала операцию хеширования нужно инициализировать через C_DigestInit(), передав в нее идентификатор сессии и ссылку на механизм хеширования. Затем размер буфера хешированных данных можно определить, вызвав C_Digest(), и выполнить хеширование данных, вызвав C_Digest() второй раз.
Предварительно должна быть открыта сессия чтения/записи.
Пример хеширования данных по алгоритму ГОСТ Р 34. 11-94 и ГОСТ Р 34. 11-2012
/* Данные для хеширования в виде двоичной строки */ CK_BYTE pbtData[] = { 0x3C, 0x21, 0x50, 0x49, 0x4E, 0x50, 0x41, 0x44, 0x46, 0x49, 0x4C, 0x45, 0x20, 0x52, 0x55, 0x3E, 0x3C, 0x21, 0x3E, 0xED, 0xE5, 0xE2, 0xE8, 0xE4, 0xE8, 0xEC, 0xFB, 0xE9, 0x20, 0xF2, 0xE5, 0xEA }; /* Механизм хеширования ГОСТ Р 34.11-94 */ CK_MECHANISM gostR3411_946HashMech = {CKM_GOSTR3411, NULL_PTR, 0}; /* Механизм хеширования ГОСТ Р 34.11-2012(256) */ CK_MECHANISM gostR3411_12_256HashMech = {CKM_GOSTR3411_12_256, NULL_PTR, 0}; /* Механизм хеширования ГОСТ Р 34.11-2012(512) */ CK_MECHANISM gostR3411_12_512HashMech = {CKM_GOSTR3411_12_512, NULL_PTR, 0 }; CK_BYTE_PTR pbtHash = NULL_PTR; // Указатель на буфер для значения хеша данных CK_ULONG ulHashSize = 0; // Размер буфера в байтах while(TRUE) { ... /* Инициализировать операцию хеширования */ printf("C_DigestInit"); rv = pFunctionList->C_DigestInit(hSession, // Хэндл сессии &gostR3411_946HashMech ); // Механизм хеширования: необходимо выбрать соответствующий из // gostR3411_946HashMech, gostR3411_12_256HashMech или gostR3411_12_512HashMech if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Определить размер значения хеша данных */ printf("C_Digest step 1"); rv = pFunctionList->C_Digest( hSession, // Хэндл сессии pbtData, // Буфер с данными для хеширования arraysize(pbtData), // Размер данных для хеширования pbtHash, // Буфер для вычисленного значения хеша &ulHashSize); // Размер значения хеша if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtHash = (CK_BYTE*)malloc(ulHashSize); if (pbtHash == NULL) { printf("Memory allocation for pbtHash failed! \n"); break; } memset(pbtHash, 0, (ulHashSize * sizeof(CK_BYTE))); /* Сформировать хеш от исходных данных */ printf("C_Digest step 2"); rv = pFunctionList->C_Digest(hSession, // Хэндл сессии pbtData, // Буфер с данными для хеширования arraysize(pbtData), // Размер данных для хеширования pbtHash, // Буфер для вычисленного значения хеша &ulHashSize); // Размер значения хеша if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); break; }
Можно ли скачать бесплатно бессрочную лицензию КриптоПро CSP 5
CryptoPro 5-й сборки относится к категории криптопровайдеров нового поколения. В ней реализован полный набор опций от предыдущей версии, в том числе поддержка ГОСТа 2012 года, и добавлены новые функциональные возможности.
Основная особенность обновленного СКЗИ — поддержка облачных токенов с неизвлекаемыми ключами. Такая технология постепенно тестируется и внедряется в различных сферах использования криптографических средств, обеспечивая повышенный уровень безопасности ключей без жесткой привязки к одному рабочему месту (доступ к ключевой паре можно получить из любой точки, где есть интернет).
Для работы КриптоПро с облачными ключами не требуется перерабатывать и перепрошивать ПО, остается единый интерфейс доступа, а работа с облаком происходит по тому же алгоритму, что и с физическими токенами.
При инсталляции появилась новая полезная функция — установка всех корневых сертификатов одним кликом. Теперь пользователю не придется тратить время за загрузку каждого сертификата, программа сделает это автоматически. Кроме того, добавлена поддержка платформы Android, которой не было в предыдущих сборках.
Бессрочная лицензия КриптоПро CSP 5. 0 бесплатно
Так же, как и предыдущие версии СКЗИ, бессрочную лицензию КриптоПро CSP 5.0 нельзя скачать бесплатно. Категорически не рекомендуется загружать «ломаные» программы с посторонних ресурсов, дистрибутив необходимо скачивать с официального сайта разработчика или у его официальных дилеров. В линейке присутствует клиентская и серверная лицензии с такой же стоимостью, как и у «четверки».
«Пятерка» пока не лицензирована ФСБ, ее функциональность еще дорабатывается и совершенствуется. На текущий момент этот релиз еще нельзя использовать в полноценном режиме для работы с ЭЦП на электронных площадках, но планируется, что уже в ближайшее время программа получит сертификат соответствия в ФСБ. За актуальной информацией о действующих сертификатах следите в соответствующем разделе.
Выработка сеансового симметричного ключа
Функция C_DeriveKey
позволяет получить одинаковый симметричный ключ для сеансовой связи на каждой из сторон, имея закрытый ключ одной стороны и открытый ключ другой стороны.()
Устройства Рутокен поддерживают следующие механизмы согласования ключей:
CKM_GOSTR3410_DERIVE
для алгоритма VKO GOST R 34.10-2001;CKM_GOSTR3410_12_DERIVE
для алгоритма VKO GOST R 34.10-2012 (256 и 512 бит).CKM_KDF_TREE_GOSTR3411_2012_256
для алгоритма KDF_TREE_GOSTR3411_2012_256CKM_VENDOR_GOST_KEG
для алгоритма Keg определенного в стандарте ГОСТ Р 1323565.1.020-2018
VKO GOST R 34.10-2001
Выработанный общий ключ согласно VKO GOST R 34.10-2001 может быть возвращен в одном из следующих форматов:
- не диверсифицированный Key Encryption Key (KEK)
- KEK, диверсифицированный по RFC-4357, п.6.5.
Параметры механизма CKM_GOSTR3410_DERIVE задаются структурой CK_GOSTR3410_DERIVE_PARAMS, которая имеет следующие поля:
typedef struct CK_GOSTR3410_DERIVE_PARAMS{ CK_EC_KDF_TYPE kdf; CK_BYTE_PTR pPublicData; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pUKM; CK_ULONG ulUKMLen; } CK_GOSTR3410_DERIVE_PARAMS;
- kdf – идентификатор механизма диверсификации. Может быть использован один из двух механизмов:
- CKD_NULL – нет диверсификации
- CKD_CPDIVERSIFY_KDF
- pPublicData – открытый ключ получателя
- pUKM – синхропосылка
VKO GOST R 34.10-2012 (256 бит и 512 бит)
Выработанный общий ключ согласно VKO GOST R 34.10-2012 может быть возвращен только в формате не диверсифицированного Key Encryption Key (KEK).
Параметры механизма CKM_GOSTR3410_12_DERIVE задаются байтовым массивом, который имеет следующую структуру:
- 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) , длина определена выше.
KDF_TREE_GOSTR3411_2012_256
Механизм CKM_KDF_TREE_GOSTR3411_2012_256 позволяет вырабатывать секретные и двойственные ключи из уже имеющегося секретного ключа. Этот механизм может применяется к ключу, выработанному с помощью алгоритма VKO.
Механизм может применяться к ключам шифрования CKK_GOST28147, CKK_KUZNYECHIK, CKK_MAGMA и CKK_GENERIC_SECRET.
Результатом работы этого механизма могут быть ключи типа CKK_GOST28147, CKK_KUZNYECHIK, CKK_MAGMA, CKK_GENERIC_SECRET, CKK_KUZNYECHIK_TWIN_KEY и CKK_MAGMA_TWIN_KEY.
Для задания параметров механизма используется структура CK_KDF_TREE_GOST_PARAMS :
typedef struct CK_KDF_TREE_GOST_PARAMS { CK_ULONG ulLabelLength; CK_BYTE_PTR pLabel; CK_ULONG ulSeedLength; CK_BYTE_PTR pSeed; CK_ULONG ulR; CK_ULONG ulL; CK_ULONG ulOffset; } CK_KDF_TREE_GOST_PARAMS;
- pLabel, pSeed – строки задающие параметры label и seed.
- ulR – количество байт в счетчике итераций, с возможными значениями 1, 2, 3, 4.
- ulL – необходимая байтовая длина вырабатываемого ключевого материала.
- ulOffset – байтовое смещение, в последовательности ключевого материала, начиная с которого полученные байты используются для получения диверсифицированного ключа.
CKM_GOST_KEG
Механизм CKM_GOST_KEG позволяет вырабатывать двойственный ключ из закрытого ключа отправителя и открытого ключа получателя.
Механизм может применяться к ключам ГОСТ Р 34.10-2012 с длиной ключа 256 и 512 бит.
Результатом работы этого механизма могут быть ключи типа CKK_KUZNYECHIK_TWIN_KEY и CKK_MAGMA_TWIN_KEY.
Для задания параметров механизма используется структура CK_ECDH1_DERIVE_PARAMS:
typedef struct CK_ECDH1_DERIVE_PARAMS { CK_EC_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE_PTR pSharedData; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; };
- pPublicData – открытый ключ получателя
- pUKM – синхропосылка.
Пример выработки общего ключа парной связи по алгоритму VKO GOST R 34.10-2012
/* Размер синхропосылки в байтах */ #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
/* Размер синхропосылки в байтах */ #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 }; /* Значение открытого ключа получателя для ГОСТ 2012-512*/ /*CK_BYTE cbPubRecipientKey[] = { 0xFC, 0xD5, 0xD3, 0x91, 0xEF, 0x58, 0x66, 0x50, 0x26, 0x59, 0x6C, 0x71, 0xE5, 0x89, 0x35, 0xC7, 0x35, 0x71, 0x28, 0xA4, 0xAD, 0x3C, 0xD5, 0x0A, 0xA3, 0xF8, 0xB1, 0xD9, 0xC1, 0x77, 0xB3, 0x17, 0x65, 0x0C, 0x7E, 0x6E, 0x11, 0x12, 0xC2, 0x62, 0xB3, 0xDF, 0x43, 0x32, 0x54, 0xB4, 0x7C, 0x7D, 0xF3, 0x3C, 0x1F, 0xD7, 0xEA, 0x02, 0xE7, 0x70, 0x15, 0xCC, 0xFC, 0x28, 0xC6, 0xAE, 0x91, 0x29, 0x58, 0xFB, 0x75, 0x14, 0x7B, 0x0E, 0x99, 0x59, 0xF9, 0x4B, 0xE9, 0x80, 0xA5, 0xBB, 0x18, 0x8E, 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, &derivedKuznechikTwinKeyLabel, sizeof(derivedKuznechikTwinKeyLabel) - 1}, // Метка ключа { CKA_CLASS, &secretKeyObject, sizeof(secretKeyObject) }, // Класс - секретный ключ { CKA_KEY_TYPE, &keyTypeKuznechikTwin, sizeof(keyTypeKuznechikTwin)}, // Тип ключа - двойственный Кузнечик { 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 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)}, // Ключ может быть изменен после создания // { 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; // Хэндл объекта ... /************************************************************************* * Установить параметры в структуре типа CK_VENDOR_GOST_KEG_PARAMS * * для выработки двойственного ключа * *************************************************************************/ rv = pFunctionList->C_GenerateRandom(hSession, ukm, sizeof(ukm)); if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } /************************************************************************* * Поместить в структуру типа 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_DeriveKey(hSession, // Хэндл открытой с правами Пользователя сессии &gostKegDerifivationMech, // Механизм ключевого обмена hPrivateKey, // Хэндл закрытого ключа отправителя derivedTwinKeyTemplate, // Шаблон создания общего ключа arraysize(derivedTwinKeyTemplate), // Размер шаблона &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))); /* Получить значение общего двойственного ключа */ printf("Getting object value"); rv = pFunctionList->C_GetAttributeValue(hSession, // Хэндл открытой с правами Пользователя сессии hDerivedKey, // Хэндл общего ключа &attrDerivedKeyValue, // Шаблон получения значения атрибута 1); // Количество атрибутов в шаблоне if (rv != CKR_OK) { printf(" -> Failed\n"); goto exit; } printf(" -> OK\n"); /* Распечатать буфер со значением общего двойственного ключа */ 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");
Маскирование секретного ключа
Для получения сеансового ключ (CEK), зашифрованного на KEK с синхропосылкой CEK, необходимо после получения ключа функцией C_DeriveKey() использовать функцию маскирования C_WrapKey().
Для выработки сеансового ключ (CEK) в оперативной памяти токена, зашифрованного на KEK с синхропосылкой CEK, необходимо использовать функцию расширения C_EX_WrapKey().
Для маскирования (шифрования) симметричного ключа используются функция C_WrapKey()
для маскирования и C_UnwrapKey()
для обратной процедуры.
В этом примере мы генерируем случайным образом сессионный ключ (CEK), а затем маскируем его общим ключом KEK, полученным из функции C_Derive()
.
/* Размер синхропосылки в байтах */ #define UKM_LENGTH 8 /* Размер симметричного ключа ГОСТ 28147-89 в байтах */ #define GOST_28147_KEY_SIZE 0x20 /* Набор параметров КриптоПро A алгоритма ГОСТ 28147-89 */ CK_BYTE GOST28147params[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01 }; CK_BYTE ukm[UKM_LENGTH] = {0x01, 0x02 ,0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; // Синхропосылка /* Механизм для маскирования/демаскирования ключа */ 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, &UnWrapKeyLabel, sizeof(UnWrapKeyLabel) - 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; // Хэндл выработанного общего ключа 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; // Хэндл ключа, который будет маскироваться/демаскироваться ... /*Установить синхропосылку для маскирования ключа*/ ckmWrapMech.ulParameterLen = sizeof(ukm); ckmWrapMech.pParameter = ukm; /* Заполнить шаблон сессионного ключа случайными данными */ GenerateRandomData(GOST_28147_KEY_SIZE, &pbtSessionKey); for (int i = 0; i < arraysize(attrGOST28147KeyToWrap); i++) if (attrGOST28147KeyToWrap[i].type == CKA_VALUE) { attrGOST28147KeyToWrap[i].pValue = pbtSessionKey; attrGOST28147KeyToWrap[i].ulValueLen = GOST_28147_KEY_SIZE; break; } /************************************************************************* * Маскирование ключа * *************************************************************************/ /* Создать ключ, который будет маскирован */ 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"); goto wrap_exit; } printf(" -> OK\n"); /* Получить размер буфера, содержащего значение маскированного ключа */ printf("Defining wrapping key size"); rv = pFunctionList->C_WrapKey(hSession, // Хэндл сессии, открытой с правами Пользователя &ckmWrapMech, // Механизм маскирования hDerivedKey, // Хэндл ключа, которым будет маскироваться ключ 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) { 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, // Хэндл сессии, открытой с правами Пользователя &ckmWrapMech, // Механизм маскирования hDerivedKey, // Хэндл ключа, которым будет маскироваться ключ 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, // Хэндл сессии, открытой с правами Пользователя &ckmWrapMech, // Механизм маскирования hDerivedKey, // Хэндл ключа, которым был маскирован ключ pbtWrappedKey, // Указатель на буфер с маскированным ключом ulWrappedKeySize, // Размер буфера с маскированным ключом attrGOST28147UnwrappedKey, // Указатель на шаблон для демаскированного ключа arraysize(attrGOST28147UnwrappedKey), // Размер шаблона для демаскированного ключа &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) { 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_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"); exit: printf("Finish");
Пример экспорта и импорта ключа по алгоритму Kexp15
/* Синхропосылка для механизма импорта и экспорта ключа алгоритма 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");