...
Для работы с устройствами Рутокен по стандарту PKCS#11 приложение предварительно должно динамически загрузить библиотеку, реализующую интерфейс стандарта. Рутокен SDK предоставляет две библиотеки rtPKCS11 .dll и rtPKCS11ECP.dll, подробнее об особенностях выбора и использования которых можно ознакомиться в разделе Использование библиотек rtPKCS11 и rtPKCS11ECP. Основная разница заключается в том, что российские алгоритмы доступны в библиотеке rtPKCS11ECP.dll, а зарубежные - в– в rtPKCS11. dllБиблиотеки доступны для платформ Windows, Linux и MacOS X.
После загрузки библиотеки нужно получить адрес экспортируемой библиотекой функции C_GetFunctionList()
и вызвать ее для получения списка функций PKCS#11. Теперь все готово для работы с библиотекой.
...
Инициализация и деинициализация библиотеки
После загрузки библиотеки нужно ее инициализировать вызовом функции C_Initialize()
. Параметр NULL при вызове данной функции означает, что функции библиотеки не будут вызываться из нескольких потоков, в противном случае в параметре должен быть передан указатель на структуру типа CK_INITIALIZE_ARGS.
Для завершения работы с библиотекой ее нужно деинициализировать вызовом функции C_Finalize()
.
Code Block | ||||
---|---|---|---|---|
| ||||
... /* Инициализировать библиотеку */ printf("Initializing library"); rv = pFunctionList->C_Initialize(NULL_PTR); if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); ... /* Деинициализировать библиотеку */ if (pFunctionList) { printf("Finalizing library"); rvTemp = pFunctionList->C_Finalize(NULL_PTR); if (rvTemp != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); pFunctionList = NULL_PTR; } |
...
Для получения актуальной информации о состоянии конкретного слота вызывается функция C_GetSlotInfo()
, в которую передается идентификатор слота. Ее вызов запускает обновление информации обо всех слотах. Если токен извлечь из разъема и затем снова вставить в тот же самый разъем, то он может подключиться к любому свободному слоту, а не обязательно к тому же самому.
Мониторинг событий в слоте
Для мониторинга событий извлечения и подключения токенов для всех слотов используется функция функция C_WaitForSlotEvent()
, запущенная в отдельном потоке.
При вызове C_WaitForSlotEvent()
с флагом CKF_DONT_BLOCK функция возвращает код CKR_NO_EVENT при отсутствии событий или код CKR_OK при его наличии (вместе с идентификатором соответствующего событию слота).
При вызове C_WaitForSlotEvent()
с флагом 0 выполнение функции блокируется до возникновения события и функция возвращает код CKR_OK и номер соответствующего слота.
Code Block | ||||
---|---|---|---|---|
| ||||
...
Code Block | ||||
---|---|---|---|---|
| ||||
CK_C_EX_GetFunctionListExtended pfGetFunctionListEx = NULL_PTR; // Указатель на функцию C_EX_GetFunctionListExtended CK_FUNCTION_LIST_EXTENDED_PTR pFunctionListEx = NULL_PTR; // Указатель на список функций расширения PKCS#11, хранящийся в структуре CK_FUNCTION_LIST_EXTENDED CK_TOKEN_INFO_EXTENDED tokenInfoEx; tokenInfoEx; // Структура данных типа CK_TOKEN_INFO_EXTENDED с информацией о токене while(TRUE) { ... printf("Determining token type"); /* Получить адрес функции запроса структуры с указателями на функции расширения */ pfGetFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(hModule, "C_EX_GetFunctionListExtended"); if (pfGetFunctionListEx == NULL_PTR) { "C_EX_GetFunctionListExtended"); if (pfGetFunctionListEx == NULL_PTR) { printf(" -> Failed\n"); break; } /* Получить структуру с указателями на функции расширения */ rv = pfGetFunctionListEx(&pFunctionListEx); if (rv != CKR_OK) { { printf(" -> Failed\n"); break; } memset(&tokenInfoEx, 0, sizeof(CK_TOKEN_INFO_EXTENDED)); tokenInfoEx.ulSizeofThisStructure = sizeof(CK_TOKEN_INFO_EXTENDED); /* Получить расширенную информацию о подключенном токене */ rv = pFunctionListEx->C_EX_GetTokenInfoExtended(aSlots[0], // Идентификатор слота, к которому подключен токен &tokenInfoEx); // Буфер для помещения информации о токене if (rv != CKR_OK) { { printf(" -> Failed\n"); break; } /* Определить класс токена */ if (tokenInfoEx.ulTokenClass == TOKEN_CLASS_S) { { bIsRutokenPINPad = FALSE; printf(": Rutoken / Rutoken S\n"); } else if (tokenInfoEx.ulTokenClass == TOKEN_CLASS_ECP) { { bIsRutokenPINPad = FALSE; printf(": Rutoken ECP\n"); } else if (tokenInfoEx.ulTokenClass == TOKEN_CLASS_LITE) { { bIsRutokenPINPad = FALSE; printf(": Rutoken Lite\n"); } else if (tokenInfoEx.ulTokenClass == TOKEN_CLASS_WEB) { { bIsRutokenPINPad = FALSE; printf(": Rutoken WEB\n"); } else if (tokenInfoEx.ulTokenClass == TOKEN_TYPE_RUTOKEN_PINPAD_FAMILY) { { bIsRutokenPINPad = TRUE; printf(": Rutoken PINPad\n"); } else { { bIsRutokenPINPad = FALSE; printf(": undefined\n"); } } break; } |
Открытие и закрытие сессии
// Про колбэк
Code Block | ||||
---|---|---|---|---|
| ||||
CK_SESSION_HANDLE hSession = NULL_PTR; // Хэндл открытой сессии ... /* Открыть RW сессию в первом доступном слоте */ printf("Opening Session"); rv = pFunctionList->C_OpenSession(aSlots[0], // Идентификатор слота CKF_SERIAL_SESSION | CKF_RW_SESSION, // Флаги сессии NULL_PTR, NULL_PTR, &hSession); // Хэндл сессии if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); ... /* Закрыть все открытые сессии в слоте */ printf("C_CloseAllSession"); rv = pFunctionList->C_CloseAllSessions(aSlots[0]); if (rvTemp != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); hSession = NULL_PTR; |
Получение и сброс прав доступа
В PKCS#11 доступны две роли: CKU_USER -- пользователь Рутокен, CKU_SO -- администратор Рутокен.
Code Block | ||||
---|---|---|---|---|
| ||||
/* DEMO PIN-код Пользователя Рутокен */ CK_UTF8CHAR USER_PIN[] = {'1', '2', '3', '4', '5', '6', '7', '8'}; ... /* Выполнить аутентификацию Пользователя */ printf("Logging in"); rv = pFunctionList->C_Login(hSession, // Хэндл сессии CKU_USER, // Тип пользователя USER_PIN, // PIN-код пользователя sizeof(USER_PIN)); // Длина PIN-кода if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); ... /*Сбросить права доступа */ printf("Logging out"); rv = pFunctionList->C_Logout(hSession); if ((rv == CKR_OK) || (rv == CKR_USER_NOT_LOGGED_IN)) printf(" -> OK\n"); else printf(" -> Failed\n"); |
Генерация ключевой пары
Атрибуты ключевых объектов
Все поддерживаемые устройствами Рутокен атрибуты объектов представлены в разделе Объекты PKCS #11.
Атрибуты ключевых объектов Рутокен объектов Рутокен PINPad
Рутокен PINPad имеет два специфических атрибута закрытого ключа, которые влияют на поведение устройства при осуществлении криптографических операций с использованием такого ключа: CKA_VENDOR_KEY_CONFIRM_OP
и CKA_VENDOR_KEY_PIN_ENTER
. Оба атрибута присваиваются закрытому ключу при генерации ключевой пары соответственно указанным в шаблоне значениям и поэтому не могут быть изменены после генерации. Помимо закрытого ключа, эти атрибуты могут быть присвоены также секретному ключу.
...
Если ключ был создан с флагом повышенной защиты CKA_VENDOR_KEY_PIN_ENTER
, то для подписи таким ключом таким ключом перед операцией потребуется ввести PIN-код на тачскрине устройства.
Поддерживаемые типы ключей
Устройства Рутокен поддерживают следующие типы ключей асимметричной криптографии (CK_KEY_TYPE
) :
CKK_GOSTR3410
для ключей ГОСТ для ключей ГОСТ Р 34.10-2001,CKK_GOSTR3410_512
для ключей ГОСТ Р 34.10-2012,CKK_RSA
для ключей RSA.
Примеры шаблонов ключей
Ниже представлены примеры шаблонов закрытого и открытого ключа ГОСТ Р 34.10-2001 с пояснениями.
...
Все поддерживаемые устройствами Рутокен атрибуты объектов представлены в разделе Объекты секретных ключей.
Атрибуты ключевых объектов Рутокен объектов Рутокен PINPad
Рутокен PINPad имеет два специфических атрибута секретного ключа, которые влияют на поведение устройства при осуществлении криптографических операций с использованием такого ключа: CKA_VENDOR_KEY_CONFIRM_OP
и CKA_VENDOR_KEY_PIN_ENTER
. Оба атрибута присваиваются закрытому ключу при генерации ключевой пары соответственно указанным в шаблоне значениям и поэтому не могут быть изменены после генерации. Помимо закрытого ключа, эти атрибуты могут быть присвоены также секретному ключу.
...
Если ключ был создан с флагом повышенной защиты CKA_VENDOR_KEY_PIN_ENTER
, то для шифрования таким ключом перед операцией потребуется ввести PIN-код на тачскрине устройства.
Поддерживаемые типы ключей
Устройства Рутокен поддерживают следующие типы секретных ключей (CK_KEY_TYPE
) :
CKK_GENERIC_SECRET
для абстрактных ключей произвольной длины,CKK_
GOST28147 дляGOST28147
для ключей ГОСТ 28147-89.
Примеры шаблона секретного ключа
Code Block | ||||
---|---|---|---|---|
| ||||
CK_OBJECT_CLASS ocPubKey = CKO_SECRET_KEY; CK_UTF8CHAR SecKeyLabel[] = {"GOST Secret Key"}; CK_BYTE SecKeyID[] = {"GOST Secret Key"}; CK_KEY_TYPE KeyType = CKK_GOST28147; CK_BBOOL bTrue = CK_TRUE; CK_BBOOL bFalse = CK_FALSE; /* Набор параметров КриптоПро A алгоритма ГОСТ 28147-89 */ CK_BYTE GOST28147params[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01 }; CK_ATTRIBUTE attrGOST28147_89SecKey[] = { { CKA_CLASS, &ocSeckey, sizeof(ocSeckey)}, // Объект секретного ключа ГОСТ 28147-89 { CKA_LABEL, &SecKeyLabel, sizeof(SecKeyLabel) - 1}, // Метка ключа { CKA_ID, &SecKeyID, sizeof(SecKeyID) - 1}, // Идентификатор ключа { CKA_KEY_TYPE, &KeyType, sizeof(KeyType)}, // Тип ключа { CKA_ENCRYPT, &bTrue, sizeof(bTrue)}, // Ключ предназначен для зашифрования { CKA_DECRYPT, &bTrue, sizeof(bTrue)}, // Ключ предназначен для расшифрования { CKA_TOKEN, &bTrue, sizeof(bTrue)}, // Ключ является объектом токена { CKA_PRIVATE, &bFalse, sizeof(bFalse)}, // Ключ доступен без авторизации на токене { CKA_VENDOR_KEY_CONFIRM_OP, &bTrue, sizeof(bTrue) }, // Операция шифрования/расшифрования требует подтверждения на PINPad (только для Рутокен PINPad) { CKA_VENDOR_KEY_PIN_ENTER, &bTrue, sizeof(bTrue) }, // Операция шифрования/расшифрования требует ввода PIN-кода на PINPad (только для Рутокен PINPad) { CKA_GOST28147_PARAMS, GOST28147params, sizeof(GOST28147params)} // Параметры алгоритма }; |
Поддерживаемые Поддерживаемые механизмы генерации ключей
...
CKM_GOST28147_KEY_GEN
для генерации секретного ключа ГОСТ 28147-89 (библиотекой rtPKCS11ECP),CKM_GOST_KEY_GEN
для генерации секретного ключа ГОСТ 28147-89 (библиотекой rtPKCS11).
Пример генерации секретного ключа
Для генерации секретного ключа предназначена функция C_GenerateKey()
, в которую передается механизм генерации и шаблон ключа.
Code Block | ||||
---|---|---|---|---|
| ||||
/* Вычисление размера массива */ #define arraysize(a) (sizeof(a)/sizeof(a[0])) CK_MECHANISM KeyGenMech = KeyGenMech = {CKM_GOST28147_KEY_GEN, NULL_PTR, 0}; // Генерация ключа ГОСТ 28147-89 CK_OBJECT_HANDLE hSecKey = NULL_PTR; // Хэндл cекретного ключа ... printf("\n Generating key"); rv = pFunctionList->C_GenerateKey(hSession, // Хэндл открытой сессии &KeyGenMech, // Используемый механизм генерации ключа attrGOST28147_89SecKey, // Шаблон для создания секретного ключа arraysize(attrGOST28147_89SecKey), // Размер шаблона секретного ключа &hSecKey); // Хэндл открытой сессии &KeyGenMech, // Используемый механизм генерации ключа attrGOST28147_89SecKey, // Шаблон для создания секретного ключа arraysize(attrGOST28147_89SecKey), // Размер шаблона секретного ключа &hSecKey); // Хэндл секретного ключа if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); |
// TO DO Импорт ключа
// TO DO Удаление объектов
Вычисление значения хеш-функции
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы хеширования:
CKM_MD2
для хеширования алгоритмом MD2,CKM_MD5
для хеширования алгоритмом MD5,CKM_SHA_1
для хеширования алгоритмом SHA-1,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
()
секретного ключа if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); |
// TO DO Импорт ключа
// TO DO Удаление объектов
Вычисление значения хеш-функции
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы хеширования:
CKM_MD2
для хеширования алгоритмом MD2,CKM_MD5
для хеширования алгоритмом MD5,CKM_SHA_1
для хеширования алгоритмом SHA-1,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
()
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 }; /* Механизм хеширования ГОСТ Р 34.11-94 */ CK_MECHANISM HashMech = {CKM_GOSTR3411, NULL_PTR, 0}; CK_BYTE_PTR pbtHash = NULL_PTR; // Указатель на буфер для хешированных данных CK_ULONG ulHashSize = 0; // Размер буфера в байтах while(TRUE) { ... /* Инициализировать операцию хеширования */ printf("C_DigestInit"); rv = pFunctionList->C_DigestInit(hSession, &HashMech); 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); memset(pbtHash, 0, (ulHashSize * sizeof(CK_BYTE))); /* Сформировать хеш от исходных данных */ printf("C_Digest step 2"); rv = pFunctionList->C_Digest(hSession, pbtData, arraysize(pbtData), pbtHash, &ulHashSize); | ||||
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 }; /* Механизм хеширования ГОСТ Р 34.11-94 */ CK_MECHANISM HashMech = {CKM_GOSTR3411, NULL_PTR, 0}; CK_BYTE_PTR pbtHash = NULL_PTR; // Указатель на буфер для хешированных данных CK_ULONG ulHashSize = 0; // Размер буфера в байтах while(TRUE) { ... /* Инициализировать операцию хеширования */ printf("C_DigestInit"); rv = pFunctionList->C_DigestInit(hSession, &HashMech); 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); memset(pbtHash, 0, (ulHashSize * sizeof(CK_BYTE))); /* Сформировать хеш от исходных данных */ printf("C_Digest step 2"); rv = pFunctionList->C_Digest(hSession, pbtData, arraysize(pbtData), pbtHash, &ulHashSize); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); break; } |
Подпись и проверка подписи
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы подписи:
CKM_GOSTR3410
подписи алгоритмом ГОСТ Р 34.10.2001,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.
Формат данных для подписи, отображаемый Рутокен PINPad
Если у закрытого ключа, которым подписываются данные, выставлен флаг визуализации, перед подписью Рутокен PINPad выведет на экран подписываемые данные для проверки и будет ожидать подтверждения или отмены операции. Чтобы Рутокен PINPad мог отобразить подписываемые данные, они должны иметь определенный формат:
Code Block | ||||
---|---|---|---|---|
| ||||
<!PINPADFILE RU> // обязательный признак строки, которая будет распознаваться Rutoken PINPad
<!>some text // текст, нераспознаваемый Rutoken PINPad
<N>some text // наименование поля
<V>some text // значение поля |
Подпись данных
Для вычисления отделяемой подписи сообщения служат функции C_SignInit()
и C_Sign()
. Сначала операцию подписи нужно инициализировать через C_SignInit()
, передав в нее идентификатор сессии, механизма и закрытого ключа. Затем размер буфера подписанных данных можно определить, вызвав C_Sign()
, и подписать данные, вызвав C_Sign()
второй раз.
При использовании совместных алгоритмов хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411)
в C_Sign()
передается открытый текст для подписи, при использовании только алгоритма подписи (например, CKM_GOSTR3410
) – уже прохешированные данные.
При использовании совместных алгоритмов хеширования и подписи в механизме должны быть заданы параметры алгоритма хеширования.
...
break; } |
Подпись и проверка подписи
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы подписи:
CKM_GOSTR3410
подписи алгоритмом ГОСТ Р 34.10.2001,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.
Формат данных для подписи, отображаемый Рутокен PINPad
Если у закрытого ключа, которым подписываются данные, выставлен флаг визуализации, перед подписью Рутокен PINPad выведет на экран подписываемые данные для проверки и будет ожидать подтверждения или отмены операции. Чтобы Рутокен PINPad мог отобразить подписываемые данные, они должны иметь определенный формат:
Code Block | ||||
---|---|---|---|---|
| ||||
<!PINPADFILE RU> // обязательный признак строки, которая будет распознаваться Rutoken PINPad <!>some text // текст, нераспознаваемый Rutoken PINPad <N>some text // наименование поля <V>some text // значение поля |
Подпись данных
Для вычисления отделяемой подписи сообщения служат функции C_SignInit()
и C_Sign()
. Сначала операцию подписи нужно инициализировать через C_SignInit()
, передав в нее идентификатор сессии, механизма и закрытого ключа. Затем размер буфера подписанных данных можно определить, вызвав C_Sign()
, и подписать данные, вызвав C_Sign()
второй раз.
При использовании совместных алгоритмов хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411)
в C_Sign()
передается открытый текст для подписи, при использовании только алгоритма подписи (например, CKM_GOSTR3410
) – уже прохешированные данные.
При использовании совместных алгоритмов хеширования и подписи в механизме должны быть заданы параметры алгоритма хеширования.
В качестве данных на подпись может быть передан запрос на сертификат, представленный в байт-коде.
Подпись на Рутокен PINPad совместным механизмом хеширования и подписи
При использовании совместного механизма хеширования и подписи в функцию C_Sign
с совместным механизмом (например, CKM_GOSTR3410_WITH_GOSTR3411
) передается текст в специальным формате для отображения его на экране Рутокен PINPad.
При вызове функции C_Sign
на экране Рутокен PINPad появится текст сообщения, а функция будет ожидать нажатия пользователем кнопки подтверждения или отказа от операции на экране Рутокен PINPad.
Если пользователь подтверждает выполнение операции, то сообщение сначала хешируется внутри Рутокен PINPad, а затем подписывается. Функция C_Sign возвращает управление и 64-байтовый блок сформированной цифровой подписи .
Если пользователь отклоняет операцию подписи, функция C_Sign
немедленно возвращает управление и код ошибки. Никаких вычислений хеша или цифровой подписи не производится.
Подпись на Рутокен PINPad отдельными механизмами хеширования и подписи
При использовании отдельных механизмов хеширования и подписи сначала в функцию C_Digest
с механизмом хеширования (например, CKM_GOSTR3411
) передается текст в специальном формате для отображения его на экране Рутокен PINPad.
При вызове функция C_Digest
вычисляет хеш и возвращает управление вместе с значением хеша. Исходное сообщение и значение хеша запоминаются внутри Рутокен PINPad.
Затем вызывается функция C_Sign
с механизмом подписи (например, CKM_GOSTR3410
) и произвольным значением хеша. Рутокен PINPad подставляет сохраненное значение хеша вместо переданного функцией C_Sign
значения и отображает на экране текст исходного сообщения. Функция C_Sign
ожидает нажатия пользователем кнопки подтверждения или отказа от операции на экране Рутокен PINPad.
Если пользователь подтверждает выполнение операции, то сохраненное значение хеша в Рутокен PINPad подписывается, и функция C_Sign
возвращает управление и 64-байтовый блок сформированной цифровой подписи.
Если пользователь отклоняет операцию подписи, функция C_Sign
немедленно возвращает управление и код ошибки. Вычисления цифровой подписи не производится.
Пример подписи данных по алгоритму ГОСТ Р 34.10-2001
Code Block | ||||
---|---|---|---|---|
| ||||
/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 */ CK_MECHANISM SigVerMech = {CKM_GOSTR3410, NULL_PTR, 0}; /* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-1994 */ CK_BYTE GOST3411params[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01 }; /* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 с хешированием по алгоритму ГОСТ Р 34.11-94*/ CK_MECHANISM HashSigVerMech = {CKM_GOSTR3410_WITH_GOSTR3411, GOST3411params, sizeof(GOST3411params)}; CK_BYTE_PTR pbtSignature = NULL_PTR; // Указатель на буфер, содержащий подпись для исходных данных CK_ULONG ulSignatureSize = 0; // Размер буфера, содержащего подпись для исходных данных, в байтах while(TRUE) { ... /* Инициализировать операцию подписи данных */ printf("C_SignInit"); rv = pFunctionList->C_SignInit( hSession, // Хэндл сессии &SigVerMech, // Механизм подписи hPrivateKey ); // Хэндл закрытого ключа if (rv != CKR_OK) { { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Определить размер подписанных данных */ printf("C_Sign step 1"); rv = pFunctionList->C_Sign( hSession, // Хэндл сессии pbtHash, // Буфер с данными для подписи ulHashSize, подписи ulHashSize, // Длина подписываемых данных pbtSignature, // Буфер с подписанными данными &ulSignatureSize); // Длина подписанных данных if (rv != CKR_OK) { { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtSignature = (CK_BYTE*)malloc(ulSignatureSize); memset( pbtSignature, 0, ulSignatureSize * sizeof(CK_BYTE)); /* Подписать исходные данные */ printf("C_Sign step 2"); rv = pFunctionList->C_Sign( hSession, // Хэндл сессии pbHash, // Буфер с данными для подписи ulHashSize, подписи ulHashSize, // Длина подписываемых данных pbtSignature, // Буфер с подписанными данными &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"); } |
Подпись данных в формате CMS (PKCS#7)
Для вычисления подписи в формате PKCS#7 формате PKCS#7 существует функция C_EX_PKCS7Sign(), в которую сразу передаются все необходимые для операции данные. Для Для такой подписи необходимо наличие сертификата, которым будут подписываться данные.
После окончания работы с функцией необходимо освободить буфер, содержащий подпись, вызвав функцию функцию C_EX_FreeBuffer().
Code Block | ||||
---|---|---|---|---|
| ||||
CK_OBJECT_HANDLE hCert; // Хэндл сертификата ... /* Подпись данных */ printf("PKCS7 Sign"); rv = pFunctionListEx->C_EX_PKCS7Sign( hSession, // Хэндл сессии pbtData, // Буфер с данными для подписи arraysize(pbtData), // Размер данных для подписи hCert, // Хэндл сертификата &pbtSignature, // Буфер для подписанных данных &ulSignatureSize, // Размер подписанных данных hPrvKey, // Хэндл закрытого ключа, соответствующего сертификату NULL, // Указатель на массив сертификатов 0, // Размер массива 0); // Формат подписи: 0 0 - неотделяемая подпись (подпись вместе с исходными данными); // PKCS7_DETACHED_SIGNATURE - отделяемая подпись (подпись без исходных данных) if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); ... /* Освобождение памяти*/ printf("C_EX_FreeBuffer"); rv = pFunctionListEx->C_EX_FreeBuffer(pbtSignature); if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); |
Проверка подписи
Для проверки подписи данных служат функции C_SignInit()
и C_Sign()
. Сначала операцию подписи нужно инициализировать через C_SignInit()
, передав в нее идентификатор сессии, механизма и закрытого ключа. Затем размер буфера подписанных данных можно определить, вызвав C_Sign()
, и подписать данные, вызвав C_Sign()
второй раз.
При использовании совместных алгоритмов хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411)
в C_Sign()
передается открытый текст для подписи, при использовании только алгоритма подписи (например, CKM_GOSTR3410
) – уже прохешированные данные.
Шифрование и расшифрование
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы шифрования:
CKM_GOST28147_ECB
для шифрования алгоритмом ГОСТ 28147-89 в режиме простой замены,CKM_GOST28147
для шифрования алгоритмом ГОСТ 28147-89 в режимах гаммирования и гаммирования с обратной связью,CKM_RSA_PKCS
для шифрования алгоритмом RSA.
Режим гаммирования
Режим гаммирования с обратной связью
...