Table of Contents maxLevel 3 outline true style none
Введение
Устройства Рутокен охватывают широкий спектр средств, предназначенных для строгой двухфакторной аутентификации, защиты электронной переписки, установления защищенных соединений, проведения финансовых транзакций и криптографической защиты информации
Рутокен S
Рутокен S – устройство для авторизации в компьютерных системах и защиты персональных данных российским стандартом шифрования "на борту".
...
- генерация и импорт ключей шифрования ГОСТ 28147-89,
- шифрование данных по алгоритму ГОСТ 28147-89 в режимах простой замены, гаммирования и гаммирования с обратной связью,
- вычисление (и проверка?) имитовставки по алгоритму ГОСТ 28147-89 длиной 32 бит,
- генерация последовательности случайных чисел длиной 256 бит.
Рутокен Lite
Рутокен Lite – ключевой носитель для безопасного хранения ключей шифрования и электронной подписи, паролей и других данных во встроенной защищенной памяти устройства.
Рутокен ЭЦП
Рутокен ЭЦП – электронный идентификатор с аппаратной реализацией российских и зарубежных стандартов электронной подписи, шифрования и хеширования.
- алгоритмы ГОСТ Р 34.10-2012 и ГОСТ Р 34.10-2001: генерация ключевых пар с проверкой качества, импорт ключевых пар, формирование и проверка электронной подписи, срок действия закрытых ключей до 3-х лет.
- алгоритмы ГОСТ Р 34.11-2012 и ГОСТ Р 34.11-94: вычисление значения хеш-функции данных, в том числе с возможностью последующего формирования электронной подписи.
- алгоритм ГОСТ 28147-89: генерация и импорт ключей шифрования, шифрование данных в режимах простой замены, гаммирования и гаммирования с обратной связью, вычисление и проверка криптографической контрольной суммы данных (имитовставки ГОСТ).
- выработка сессионных ключей (ключей парной связи): по схеме VKO GOST R 34.10-2001 (RFC 4357), расшифрование по схеме EC El-Gamal.
- алгоритм RSA: поддержка ключей размером до 2048 бит, генерация ключевых пар с настраиваемой проверкой качества, импорт ключевых пар, формирование электронной подписи.
- генерация последовательности случайных чисел требуемой длины.
Рутокен PINPad
Рутокен PINPad представляет собой решение класса TrustScreen, которое позволяет визуализировать подписываемый документ на экране доверенного устройства перед наложением электронной подписи. Устройство позволяет реализовать следующие незаменимые в PKI-инфраструктуре возможности:
...
- алгоритмы ГОСТ Р 34.10-2012 и ГОСТ Р 34.10-2001: генерация ключевых пар с проверкой качества, импорт ключевых пар, формирование и проверка электронной подписи, срок действия закрытых ключей до 3-х лет.
- алгоритмы ГОСТ Р 34.11-2012 и ГОСТ Р 34.11-94: вычисление значения хеш-функции данных, в том числе с возможностью последующего формирования электронной подписи.
- алгоритм ГОСТ 28147-89: генерация и импорт ключей шифрования, шифрование данных в режимах простой замены, гаммирования и гаммирования с обратной связью, вычисление и проверка криптографической контрольной суммы данных (имитовставки ГОСТ).
- выработка сессионных ключей (ключей парной связи): по схеме VKO GOST R 34.10-2001 (RFC 4357), расшифрование по схеме EC El-Gamal.
- генерация последовательности случайных чисел требуемой длины.
Начало работы
Подключение библиотеки
Для работы с устройствами Рутокен по стандарту PKCS#11 приложение предварительно должно динамически загрузить библиотеку, реализующую интерфейс стандарта. Рутокен SDK предоставляет две библиотеки rtPKCS11 и rtPKCS11ECP, подробнее об особенностях выбора и использования которых можно ознакомиться в разделе Использование библиотек rtPKCS11 и rtPKCS11ECP. Основная разница заключается в том, что российские алгоритмы доступны в библиотеке rtPKCS11ECPбиблиотеке rtPKCS11ECP, а зарубежные – в rtPKCS11– в rtPKCS11.
После загрузки библиотеки нужно получить адрес экспортируемой библиотекой функции функции C_GetFunctionList()
и и вызвать ее для получения списка функций PKCS#11. Теперь все готово для работы с библиотекой.
Для работы с функциями расширения необходимо получить необходимо получить адрес функции CK_C_EX_GetFunctionListExtended()
и вызвать ее для получения списка функций расширения PKCS#11.
После работы с библиотекой ее нужно выгрузить из памяти.
...
После загрузки библиотеки нужно ее инициализировать вызовом функции функции C_Initialize()
. Параметр NULL при вызове данной функции означает, что функции библиотеки не будут вызываться из нескольких потоков, в противном случае в параметре должен быть передан указатель на структуру типа CK_INITIALIZE_ARGS.
...
Доступ к каждому подключенному устройству осуществляется с помощью идентификатора слота, к которому оно подключено. Для получения списка всех слотов предназначена функция функция C_GetSlotList()
. Значение первого параметра указывает, должен ли список включать слоты только с подключенным токенами (CK_TRUE) или все слоты (CK_FALSE).
...
Для получения актуальной информации о состоянии конкретного слота вызывается функция функция C_GetSlotInfo()
, в которую передается идентификатор слота. Ее вызов запускает обновление информации обо всех слотах. Если токен извлечь из разъема и затем снова вставить в тот же самый разъем, то он может подключиться к любому свободному слоту, а не обязательно к тому же самому.
...
Для мониторинга событий извлечения и подключения токенов для всех слотов используется функция C_WaitForSlotEvent()
, запущенная в отдельном потоке.
При вызове вызове C_WaitForSlotEvent()
с флагом с флагом CKF_DONT_BLOCK функция возвращает код CKR_NO_EVENT при отсутствии событий или код CKR_OK при его наличии (вместе с идентификатором соответствующего событию слота).
...
Получить информацию о подключенном к слоту токене можно с помощью функции расширения C_EX_GetTokenInfoExtended()
, которая возвращает расширенные данные в виде структуры типа CK_TOKEN_INFO_EXTENDED
. Поля ulTokenClass
и и ulTokenType
содержат содержат информацию о классе и типе устройства соответственно и могут быть использованы для их определения.
...
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ввести PIN-код на тачскрине устройства.
Поддерживаемые типы ключей
Устройства Рутокен поддерживают следующие типы ключей асимметричной криптографии (CK_KEY_TYPE
) :
CKK_GOSTR3410
для ключей ГОСТ для ключей ГОСТ Р 34.10-2001,CKK_GOSTR3410_
512512
для ключей ГОСТ ключей ГОСТ Р 34.10-2012,CKK_RSA
для ключей RSAдля ключей RSA.
Примеры шаблонов ключей
Ниже представлены примеры шаблонов закрытого и открытого ключа ГОСТ Р 34.10-2001 с пояснениями.
...
Поддерживаемые механизмы генерации ключей
Устройства Рутокен поддерживают следующие механизмы генерации ключевой пары:
CKM_GOSTR3410_KEY_PAIR_GEN
для генерации ключевой пары ГОСТ Р 34.10.2001,CKM_GOSTR3410_512_KEY_PAIR_GEN
для генерации ключевой пары ГОСТ Р 34.10.2012 с длиной ключа 512 бит,CKM_RSA_PKCS_KEY_PAIR_GEN
для генерации ключевой пары RSA.
...
Code Block | ||||
---|---|---|---|---|
| ||||
/* Вычисление размера массива */ #define arraysize(a) (sizeof(a)/sizeof(a[0])) CK_MECHANISM KeyGenMech = {CKM_GOSTR3410_KEY_PAIR_GEN, NULL_PTR, 0}; // Генерация ключа ГОСТ Р 34.10-2001 CK_OBJECT_HANDLE hPublicKey = NULL_PTR; // Хэндл открытого ключа CK_OBJECT_HANDLE hPrivateKey = NULL_PTR; // Хэндл закрытого ключа ... printf("Generating key pair"); rv = pFunctionList->C_GenerateKeyPair(hSession, // Хэндл открытой сессии &KeyGenMech, // Используемый механизм генерации ключевой пары GOST34_10_2001PublicKey, // Шаблон открытого ключа arraysize(GOST34_10_2001PublicKey), // Размер шаблона открытого ключа GOST34_10_2001PrivateKey, // Шаблон закрытого ключа arraysize(GOST34_10_2001PrivateKey), // Размер шаблона закрытого ключа &hPublicKey, // Хэндл открытого ключа &hPrivateKey); // Хэндл закрытого ключа if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); |
Генерация секретного ключа
Атрибуты ключевых объектов
Все поддерживаемые устройствами Рутокен атрибуты объектов представлены в разделе Объекты секретных ключей.
Поддерживаемые типы ключей
Устройства Рутокен поддерживают следующие типы секретных ключей (CK_KEY_TYPE
) :
CKK_GENERIC_SECRET
для абстрактных ключей произвольной длины,CKK_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_GOST28147_PARAMS, GOST28147params, sizeof(GOST28147params)} // Параметры алгоритма }; |
Поддерживаемые Поддерживаемые механизмы генерации ключей
Устройства Рутокен поддерживают следующие механизмы генерации секретного ключа:
CKM_GOST28147_KEY_GEN
для генерации секретного ключа ГОСТ 28147-89 89 (библиотекой rtPKCS11ECP),CKM_GOST_KEY_GEN
для генерации секретного ключа ГОСТ 28147-89 (библиотекой rtPKCS11).
...
Code Block | ||||
---|---|---|---|---|
| ||||
/* Вычисление размера массива */ #define arraysize(a) (sizeof(a)/sizeof(a[0])) CK_MECHANISM 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); // Хэндл секретного ключа 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); // Размер значения хеша 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.
...
Для вычисления подписи сообщения служат функции 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 Рутокен 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, // Длина подписываемых данных 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, // Длина подписываемых данных 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"); } break; } |
Проверка подписи
Для проверки подписи данных служат функции C_Verify
и Init()
C_Verify()
. Сначала операцию подписи нужно инициализировать через C_VerifyInit()
, передав в нее идентификатор сессии, механизма и открытого ключа. Затем можно проверить подпись функцией C_Verify()
.
Подпись запроса на сертификат на Рутокен PINPad в формате PKCS#10
Помимо особого формата представления данных, Рутокен PINPad распознает и отображает на экране поля сформированного запроса на сертификат в формате PKCS#10. Процесс подписи запроса на сертификат ничем не отличается от подписи обычных данных: сначала данные хешируются функцией С_Digest()
и запоминаются в памяти Рутокен PINPad, затем вызывается функция C_Sign().
Сохраненные в памяти Рутокен PINPad данные и их хеш cверяются с переданными функцией и подписываются после подтверждения пользователем. При использовании совместного алгоритма хеширования и подписи все необходимые действия выполняются одной функцией C_Sign()
При использовании совместных механизмов хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411)
в C_Verify
передается исходный текст, при использовании отдельного механизма подписи (например, ()
CKM_GOSTR3410
) – предварительно прохешированные функцией C_Digest()
исходные данные.
Code Block | |||||
---|---|---|---|---|---|
| |||||
/* Сформированный запрос на сертификат в виде двоичной строки */ CK_BYTE pbtReqCert[] = {0x30, 0x82, 0x02, 0x69, 0x02, 0x01, 0x00, 0x30, 0x82, 0x01, 0x83, 0x31, 0x0b, 0x30, 0x09, 0x06,while(TRUE) { ... /* Инициализировать операцию проверки подписи */ printf(" C_VerifyInit"); rv = pFunctionList->C_VerifyInit(hSession, // Хэндл сессии &SigVerMech, // Механизм подписи hPublicKey); // Хэндл открытого ключа if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Проверить подпись для исходных данных */ printf(" C_Verify"); rv = pFunctionList->C_Verify(hSession, // Хэндл сессии pbHash, // Буфер с исходным сообщением или значением его хеша ulHashSize, // Длина буфера pbtSignature, // Буфер с подписью0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x52, 0x55, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x06, 0x4d, 0x6f, 0x73, 0x63, 0x6f, 0x77, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x03, 0x6d, 0x73, 0x6b, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x09, 0x13, 0x06, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, ulSignatureSize); // Длина подписи if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); break; } ... if (pbtSignature) { free(pbtSignature); pbtSignature = NULL_PTR; } if (pbHash) { free(pbHash); pbHash= NULL_PTR; } |
Шифрование и расшифрование
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы шифрования:
CKM_GOST28147_ECB
для шифрования алгоритмом ГОСТ 28147-89 в режиме простой замены,CKM_GOST28147
для шифрования алгоритмом ГОСТ 28147-89 в режиме гаммирования с обратной связью,CKM_RSA_PKCS
для шифрования алгоритмом RSA.
Шифрование данных
Для шифрования данных одним блоком служат функции C_EncryptInit()
и C_Encrypt()
, для поточного – С_EncryptInit(), C_EncryptUpdate()
и C_EncryptFinal().
Сначала операцию шифрования нужно инициализировать вызовом функции C_EncryptInit()
, передав в нее идентификатор сессии, механизма и секретного ключа. В параметрах механизма для ГОСТ 28147-89 можно задать вектор инициализации и его длину.
Далее шифрование можно выполнить для всего блока данных целиком, вызвав функцию C_Encrypt()
, или по частям, вызывая C_EncryptUpdate()
для каждого непоследнего блока и C_EncryptFinal()
для завершающего блока. Если в C_EncryptFinal()
передать пустой блок данных, то функция вернет суммарный размер всех блоков зашифрованных данных.
Пример шифрования данных по алгоритму ГОСТ 28147-89
0x0a, 0x13, 0x05, 0x41, 0x6b, 0x74, 0x69, 0x76, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x0b, 0x13, 0x02, 0x49, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x10, 0x13, 0x0e,
0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x31, 0x1b,
0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x0c, 0x1e, 0x12, 0x04, 0x34, 0x04, 0x3e, 0x04, 0x3b, 0x04,
0x36, 0x04, 0x3d, 0x04, 0x3e, 0x04, 0x41, 0x04, 0x42, 0x04, 0x4c, 0x31, 0x19, 0x30, 0x17, 0x06,
0x08, 0x2a, 0x85, 0x03, 0x03, 0x81, 0x03, 0x01, 0x01, 0x12, 0x0b, 0x31, 0x32, 0x33, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x38, 0x37, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x2a, 0x85, 0x03, 0x64,
0x03, 0x12, 0x0b, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x38, 0x37, 0x31, 0x16,
0x30, 0x14, 0x06, 0x05, 0x2a, 0x85, 0x03, 0x64, 0x01, 0x12, 0x0b, 0x31, 0x32, 0x33, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x38, 0x37, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x2a, 0x85, 0x03, 0x64,
0x05, 0x12, 0x0b, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x38, 0x37, 0x31, 0x2f,
0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x1e, 0x26, 0x04, 0x24, 0x04, 0x30, 0x04, 0x3c, 0x04,
0x38, 0x04, 0x3b, 0x04, 0x38, 0x04, 0x4f, 0x00, 0x20, 0x04, 0x18, 0x04, 0x3c, 0x04, 0x4f, 0x00,
0x20, 0x04, 0x1e, 0x04, 0x47, 0x04, 0x35, 0x04, 0x41, 0x04, 0x42, 0x04, 0x32, 0x04, 0x3e, 0x31,
0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x41, 0x13, 0x09, 0x70, 0x73, 0x65, 0x75, 0x64, 0x6f,
0x6e, 0x79, 0x6d, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x04, 0x13, 0x07, 0x73, 0x75,
0x72, 0x6e, 0x61, 0x6d, 0x65, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x2a, 0x13, 0x0a,
0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x63,
0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43,
0x00, 0x04, 0x40, 0x26, 0x68, 0x22, 0x87, 0x6b, 0x3e, 0x60, 0xde, 0x6e, 0xcf, 0x7d, 0x9b, 0xc5,
0x99, 0x49, 0x88, 0xe3, 0xce, 0x8d, 0x05, 0xb2, 0x0a, 0x3c, 0x3d, 0x2c, 0xb3, 0x7c, 0xc6, 0x9e,
0x7e, 0x5a, 0xc6, 0x95, 0xde, 0x97, 0x86, 0x9a, 0x56, 0xe3, 0xc5, 0xf5, 0xc5, 0xca, 0x9a, 0x4a,
0xd9, 0x11, 0xa0, 0x40, 0x08, 0xca, 0x70, 0x29, 0x13, 0x64, 0x7f, 0xa1, 0x6c, 0x5b, 0x5b, 0x25,
0xc9, 0xa6, 0x0c, 0xa0, 0x78, 0x30, 0x76, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x09, 0x0e, 0x31, 0x69, 0x30, 0x67, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03,
0x02, 0x06, 0xc0, 0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x0c, 0x30,
0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04, 0x30, 0x13, 0x06, 0x03, 0x55,
0x1d, 0x20, 0x04, 0x0c, 0x30, 0x0a, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85, 0x03, 0x64, 0x71, 0x01,
0x30, 0x2b, 0x06, 0x05, 0x2a, 0x85, 0x03, 0x64, 0x6f, 0x04, 0x22, 0x0c, 0x20, 0xd0, 0xa1, 0xd0,
0x9a, 0xd0, 0x97, 0xd0, 0x98, 0x20, 0x22, 0xd0, 0xa0, 0xd0, 0xa3, 0xd0, 0xa2, 0xd0, 0x9e, 0xd0,
0x9a, 0xd0, 0x95, 0xd0, 0x9d, 0x20, 0xd0, 0xad, 0xd0, 0xa6, 0xd0, 0x9f, 0x22
};
/* Механизм хеширования ГОСТ Р 34.11-94 */
CK_MECHANISM HashMech = {CKM_GOSTR3411, NULL_PTR, 0};
/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 */
CK_MECHANISM SigVerMech = {CKM_GOSTR3410, NULL_PTR, 0};
CK_BYTE_PTR pbtHash = NULL_PTR; // Указатель на буфер для значения хеша данных
CK_ULONG ulHashSize = 0; // Размер буфера в байтах
CK_BYTE_PTR pbtSignature = NULL_PTR; // Указатель на буфер, содержащий подпись для исходных данных
CK_ULONG ulSignatureSize = 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, // Хэндл сессии
pbtReqCert, // Буфер с запросом на сертификат
arraysize(pbtReqCert), // Размер буфера с запросом на сертификат
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, // Хэндл сессии
pbtReqCert, // Буфер с запросом на сертификат
arraysize(pbtReqCert), // Размер буфера с запросом на сертификат
pbtHash, // Буфер для значения хеша
&ulHashSize); // Размер значения хеша
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
/* Инициализировать операцию подписи данных */
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, // Длина подписываемых данных
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, // Длина подписываемых данных
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");
}
break;
}
|
Проверка подписи
Для проверки подписи данных служат функции C_Verify
и Init()
C_Verify()
. Сначала операцию подписи нужно инициализировать через C_VerifyInit()
, передав в нее идентификатор сессии, механизма и открытого ключа. Затем можно проверить подпись функцией C_Verify()
.
При использовании совместных механизмов хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411)
в C_Verify
передается исходный текст, при использовании отдельного механизма подписи (например, ()
CKM_GOSTR3410
) – предварительно прохешированные функцией C_Digest()
исходные данные.
Code Block | ||||
---|---|---|---|---|
| ||||
while(TRUE)
{
...
/* Инициализировать операцию проверки подписи */
printf(" C_VerifyInit");
rv = pFunctionList->C_VerifyInit(hSession, // Хэндл сессии
&SigVerMech, // Механизм подписи
hPublicKey); // Хэндл открытого ключа
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
/* Проверить подпись для исходных данных */
printf(" C_Verify");
rv = pFunctionList->C_Verify(hSession, // Хэндл сессии
pbHash, // Буфер с исходным сообщением или значением его хеша
ulHashSize, // Длина буфера
pbtSignature, // Буфер с подписью
ulSignatureSize); // Длина подписи
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
break;
}
...
if (pbtSignature)
{
free(pbtSignature);
pbtSignature = NULL_PTR;
}
if (pbHash)
{
free(pbHash);
pbHash= NULL_PTR;
} |
Шифрование и расшифрование
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы шифрования:
CKM_GOST28147_ECB
для шифрования алгоритмом ГОСТ 28147-89 в режиме простой замены,CKM_GOST28147
для шифрования алгоритмом ГОСТ 28147-89 в режиме гаммирования с обратной связью,CKM_RSA_PKCS
для шифрования алгоритмом RSA.
Шифрование данных
Для шифрования данных одним блоком служат функции C_EncryptInit()
и C_Encrypt()
, для поточного – С_EncryptInit(), C_EncryptUpdate()
и C_EncryptFinal().
Сначала операцию шифрования нужно инициализировать вызовом функции C_EncryptInit()
, передав в нее идентификатор сессии, механизма и секретного ключа. В параметрах механизма для ГОСТ 28147-89 можно задать вектор инициализации и его длину.
Далее шифрование можно выполнить для всего блока данных целиком, вызвав функцию C_Encrypt()
, или по частям, вызывая C_EncryptUpdate()
для каждого непоследнего блока и C_EncryptFinal()
для завершающего блока. Если в C_EncryptFinal()
передать пустой блок данных, то функция вернет суммарный размер всех блоков зашифрованных данных.
Пример шифрования данных по алгоритму ГОСТ 28147-89
Code Block | ||||
---|---|---|---|---|
| ||||
/* Данные для шифрования */
CK_BYTE pbtData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00 };
/* Механизм шифрования/расшифрования по алгоритму ГОСТ 28147-89 в режиме простой замены */
CK_MECHANISM EncDecMech = {CKM_GOST28147_ECB, NULL_PTR, 0};
CK_BYTE_PTR pbtEncryptedData = NULL_PTR; // Указатель на буфер, содержащий зашифрованные данные
CK_ULONG ulEncryptedDataSize = 0; // Размер буфера с зашифрованными данными, в байтах
while(TRUE)
{
...
/* Инициализировать операцию шифрования */
printf("C_EncryptInit");
rv = pFunctionList->C_EncryptInit(hSession, // Хэндл сессии
| ||||
Code Block | ||||
| ||||
/* Данные для шифрования */ CK_BYTE pbtData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08&EncDecMech, // Механизм шифрования 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, hSecKey); // Хэндл секретного ключа if (rv != CKR_OK) { printf(" 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00 }; /* Механизм шифрования/расшифрования по алгоритму ГОСТ 28147-89 в режиме простой замены */ CK_MECHANISM EncDecMech = {CKM_GOST28147_ECB, NULL_PTR, 0}; CK_BYTE_PTR pbtEncryptedData = NULL_PTR;-> Failed\n"); break; } printf(" -> OK\n"); /* Получить размер зашифрованного текста */ printf("Getting encrypted data size"); rv = pFunctionList->C_Encrypt(hSession, // Хэндл сессии // Указатель на буфер, содержащий зашифрованные данные CK_ULONG ulEncryptedDataSize = 0; pbtData, // Буфер с открытыми данными для шифрования // Размер буфера с зашифрованными данными, в байтах while(TRUE) { ... /* Инициализировать операцию шифрования */ printf("C_EncryptInit"); rv = pFunctionList->C_EncryptInit(hSession, // Хэндл сессииarraysize(pbtData), // Длина буфера с открытыми данными, в байтах &EncDecMech, NULL, // Механизм шифрованияБуфер с зашифрованными данными hSecKey&ulEncryptedDataSize); // Хэндл секретного ключаДлина буфера с зашифрованными данными if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); \n"); break; } printf(" -> OK\n"); pbtEncryptedData = (CK_BYTE*)malloc(ulEncryptedDataSize); memset(pbtEncryptedData, 0, (ulEncryptedDataSize * sizeof(CK_BYTE))); /* ПолучитьЗашифровать размероткрытый зашифрованноготекст текста */ printf("Getting encrypted data sizeC_Encrypt"); rv = pFunctionList->C_Encrypt(hSession, // Хэндл сессии pbtData, // Буфер с открытыми данными для шифрования arraysize(pbtData), // Длина буфера с открытыми данными, в байтах NULLpbtEncryptedData, // Буфер с зашифрованными данными &ulEncryptedDataSize); // Длина буфера с зашифрованными данными if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtEncryptedData = (CK_BYTE*)malloc(ulEncryptedDataSize); memset(pbtEncryptedData, 0, (ulEncryptedDataSize * sizeof(CK_BYTE))); /* Зашифровать открытый текст */ printf("C_Encrypt"); rv = pFunctionList->C_Encrypt(hSession, // Хэндл сессии printf("Encrypted buffer is:\n"); for (i = 0; i < ulEncryptedDataSize; i++) { printf("%02X ", pbtEncryptedData[i]); if ((i + 1) % 8 == 0) printf("\n"); } break; } |
Code Block | ||||
---|---|---|---|---|
| ||||
/* Данные для шифрования */ CK_BYTE pbtData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, pbtData, // Буфер с открытыми данными для шифрования 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x03, 0x04, 0x05, arraysize(pbtData), // Длина буфера с открытыми данными, в байтах pbtEncryptedData, // Буфер с зашифрованными данными 0x06, 0x07, 0x08, 0x09, 0x00 }; CK_BYTE IV[] = {1, 2, 3, 4, 5, 6, 7, 8}; // Значение вектора инициализации CK_ULONG ulIVLen = 8; &ulEncryptedDataSize); // Длина буфера вектора инициализации /* Механизм шифрования/расшифрования по алгоритму ГОСТ 28147-89 в режиме гаммирования с зашифрованными данными if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); printf("Encrypted buffer is:\n"); for (i = 0; i < ulEncryptedDataSize; i++) { printf("%02X ", pbtEncryptedData[i]); if ((i + 1) % 8 == 0) printf("\n"); } break; } | ||||
Code Block | ||||
| ||||
/* Данные для шифрования */ CK_BYTE pbtData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, обратной связью */ CK_MECHANISM EncDecStreamMech = {CKM_GOST28147, IV, ulIVLen}; CK_BYTE_PTR pbtEncryptedData = NULL_PTR; // Указатель на буфер, содержащий зашифрованные данные CK_ULONG ulEncryptedDataSize = 0; // Размер буфера с зашифрованными данными, в байтах CK_ULONG ulBlockSize = 32; // Размер блока данных, в байтах CK_ULONG ulCurrentPosition = 0; // Текущее начало блока CK_ULONG ulRestLen = 0; // Размер оставшегося буфера, в байтах while(TRUE) { ... /* Инициализировать операцию шифрования */ printf("C_EncryptInit"); rv = pFunctionList->C_EncryptInit(hSession, // Хэндл сессии 0x02, 0x03, 0x04, 0x05, 0x06, 0x07&EncDecStreamMech, // 0x08,Механизм 0x09,шифрования 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00 }; CK_BYTE IV[] = {1, 2, 3, 4, 5, 6, 7, 8}; // Значение вектора инициализации CK_ULONG ulIVLen = 8; // Длина вектора инициализации /* Механизм шифрования/расшифрования по алгоритму ГОСТ 28147-89 в режиме гаммирования с обратной связью */ CK_MECHANISM EncDecStreamMech = {CKM_GOST28147, IV, ulIVLen}; CK_BYTE_PTR pbtEncryptedData = NULL_PTR; // Указатель на буфер, содержащий зашифрованные данные CK_ULONG ulEncryptedDataSize = 0; // Размер буфера с зашифрованными данными, в байтах CK_ULONG ulBlockSize = 32;hSecKey); // Хэндл секретного ключа if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Зашифровать открытый текст */ ulEncryptedDataSize = arraysize(pbtData); ulRestLen = arraysize(pbtData); pbtEncryptedData = (CK_BYTE*)malloc(ulEncryptedDataSize); memset( pbtEncryptedData, 0, (ulEncryptedDataSize * sizeof(CK_BYTE))); while (ulRestLen) { if (ulBlockSize > ulRestLen) ulBlockSize = ulRestLen; printf("Block size: %u B (Total: %u of %u) ", ulBlockSize, ulCurrentPosition + ulBlockSize, ulEncryptedDataSize); rv = pFunctionList->C_EncryptUpdate(hSession, // Хэндл сессии pbtData + ulCurrentPosition, // Буфер с блоком данных для шифрования ulBlockSize, // Размер блока, в байтах pbtEncryptedData + ulCurrentPosition, // Буфер с блоком зашифрованных данных &ulBlockSize); // Размер блока данных, в байтах CK_ULONG ulCurrentPosition = 0; // Текущее начало блока CK_ULONG ulRestLen = 0; // Размер оставшегося буфера, в байтах while(TRUE) { ... /* Инициализировать операцию шифрования */ printf("C_EncryptInit if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); ulCurrentPosition += ulBlockSize; ulRestLen -= ulBlockSize; } if (rv != CKR_OK) break; printf("Finalizing encryption"); rv = pFunctionList->C_EncryptInitEncryptFinal( hSession, // Хэндл сессии NULL_PTR, // Буфер с последним блоком &EncDecStreamMech,данных &ulEncryptedDataSize); // МеханизмДлина шифрованиябуфера if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Распечатать буфер, содержащий зашифрованные данные*/ printf("Encrypted buffer is:\n"); for (i = 0; i < ulEncryptedDataSize; hSecKey); // Хэндл секретного ключа if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OKi++) { printf("%02X ", pbtEncryptedData[i]); if ((i + 1) % 8 == 0) printf("\n"); /* Зашифровать открытый текст */ ulEncryptedDataSize = arraysize(pbtData); ulRestLen = arraysize(pbtData); pbtEncryptedData = (CK_BYTE*)malloc(ulEncryptedDataSize); memset( pbtEncryptedData, 0, (ulEncryptedDataSize * sizeof(CK_BYTE))); while (ulRestLen) { if (ulBlockSize > ulRestLen) ulBlockSize = ulRestLen; printf("Block size: %u B (Total: %u of %u) ", ulBlockSize, ulCurrentPosition + ulBlockSize, ulEncryptedDataSize); } break; } |
Расшифрование данных
Для расшифрования данных служат функции C_DecryptInit()
и C_Decrypt()
для любого режима шифрования.
Сначала операцию расшифрования нужно инициализировать вызовом функции C_DecryptInit()
, передав в нее идентификатор сессии, механизма и секретного ключа. В параметрах механизма для ГОСТ 28147-89 можно задать вектор инициализации и его длину.
Далее расшифрование выполняется вызовом функции C_Decrypt()
с передачей в нее зашифрованные данные. Размер расшифрованных данных можно узнать, вызвав C_Decrypt()
с пустым указателем вместо указателя на буфера для расшифрованных данных.
Пример расшифрования данных по алгоритму ГОСТ 28147-89
Code Block | ||||
---|---|---|---|---|
| ||||
while(TRUE) { ... /* Инициализировать операцию расшифрования */ printf("C_DecryptInit"); rv = pFunctionList->C_EncryptUpdateDecryptInit(hSession, // Хэндл сессии pbtData + ulCurrentPosition, // Буфер с блоком данных для шифрования ulBlockSize, // Размер блока, в байтах pbtEncryptedData + ulCurrentPosition, // Буфер с блоком зашифрованных данных &ulBlockSize &EncDecStreamMech, // Механизм расшифрования hSecKey); // РазмерХэндл блока, в байтах секретного ключа if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); ulCurrentPosition += ulBlockSize; ulRestLen -= ulBlockSize; } if (rv != CKR_OK) break; /* Расшифровать шифротекст */ printf("Finalizing encryptionGetting decrypted data size"); rv = pFunctionList->C_EncryptFinalDecrypt( hSession, // Хэндл сессии pbtEncryptedData, NULL_PTR, // Буфер с зашифрованными данными ulEncryptedDataSize, // Буфер с последним блокомРазмер зашифрованных данных NULL_PTR, &ulEncryptedDataSize); // Длина буфера if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Распечатать буфер, содержащий зашифрованные данные*/ printf("Encrypted buffer is:\n"); for (i = 0; i < ulEncryptedDataSize; i++) { printf("%02X ", pbtEncryptedData[i]); if ((i + 1) % 8 == 0) printf("\n"); } break; } |
Расшифрование данных
Для расшифрования данных служат функции C_DecryptInit()
и C_Decrypt()
для любого режима шифрования.
Сначала операцию расшифрования нужно инициализировать вызовом функции C_DecryptInit()
, передав в нее идентификатор сессии, механизма и секретного ключа. В параметрах механизма для ГОСТ 28147-89 можно задать вектор инициализации и его длину.
Далее расшифрование выполняется вызовом функции C_Decrypt()
с передачей в нее зашифрованные данные. Размер расшифрованных данных можно узнать, вызвав C_Decrypt()
с пустым указателем вместо указателя на буфера для расшифрованных данных.
Пример расшифрования данных по алгоритму ГОСТ 28147-89
Code Block | ||||
---|---|---|---|---|
| ||||
while(TRUE) { ... /* Инициализировать операцию расшифрования */Буфер с расшифрованными данными &ulDecryptedDataSize); // Размер расшифрованных данных if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtDecryptedData = (CK_BYTE*)malloc(ulDecryptedDataSize); memset(pbtDecryptedData, 0, (ulDecryptedDataSize * sizeof(CK_BYTE))); printf("C_DecryptInitDecrypt"); rv = pFunctionList->C_DecryptInitDecrypt(hSession, // Хэндл сессии &EncDecStreamMechpbtEncryptedData, // Буфер с Механизмзашифрованными расшифрованияданными hSecKey);ulEncryptedDataSize, // ХэндлРазмер секретного ключа if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Расшифровать шифротекст */ printf("Getting decrypted data size"); rv = pFunctionList->C_Decrypt(hSession, // Хэндл сессии зашифрованных данных pbtEncryptedDatapbtDecryptedData, // Буфер с зашифрованнымирасшифрованными данными ulEncryptedDataSize, // Размер зашифрованных данных &ulDecryptedDataSize); // Размер расшифрованных данных if (rv != CKR_OK) { printf(" NULL_PTR, // Буфер с расшифрованными данными &ulDecryptedDataSize); // Размер расшифрованных данных if (rv != CKR_OK) { printf(" -> Failed-> Failed\n"); break; } printf(" -> OK\n"); /* Распечатать буфер, содержащий расшифрованный текст */ printf("Decrypted buffer is:\n"); for (i = 0; i < ulDecryptedDataSize; i++) { printf("%02X ", pbtDecryptedData[i]); if ((i + 1) % 8 == 0) printf("\n"); } break; }} if (pbtEncryptedData) { printf(" -> OK\n"free(pbtEncryptedData); pbtDecryptedDatapbtEncryptedData = (CK_BYTE*)malloc(ulDecryptedDataSize); memset(pbtDecryptedData, 0, (ulDecryptedDataSize * sizeof(CK_BYTE))); printf("C_Decrypt"NULL_PTR; } if (pbtDecryptedData) { free(pbtDecryptedData); rvpbtDecryptedData = pFunctionList->C_Decrypt(hSession, NULL_PTR; } |
Работа с токеном
Установка и смена локального PIN-кода
Помимо двух глобальных ролей Администратора и Пользователя, устройства Рутокен поддерживают до 29 PIN-кодов Локальных Пользователей для разных технических нужд.
Установка или смена локального PIN-кода должна выполняться Пользователем Рутокен и не требует открытой сессии и авторизации – PIN-код Пользователя передается прямо в функцию C_EX_SetLocalPin().
Code Block | ||||
---|---|---|---|---|
| ||||
CK_SLOT_ID slotID; // Хэндл сессии Идентификатор слота, к которому подключен токен CK_UTF8CHAR_PTR pUserPin; // PIN-код Пользователя Рутокен CK_ULONG pbtEncryptedData, ulUserPinLen; // Буфер с зашифрованными данными Длина PIN-кода Пользователя Рутокен CK_UTF8CHAR_PTR pNewLocalPin; // Локальный PIN-код CK_ULONG ulNewLocalPinLen; // Длина локального PIN-кода CK_ULONG ulLocalID; ulEncryptedDataSize, // РазмерИдентификатор зашифрованных данных локального PIN-кода printf("Setting Local PIN-code"); rv = pfGetFunctionListEx->C_EX_SetLocalPIN( slotID, // Идентификатор слота, к которому подключен токен pbtDecryptedData pUserPin, // Буфер с расшифрованными данными Текущий PIN-код Пользователя Рутокен ulUserPinLen, // Длина текущего PIN-кода Пользователя Рутокен &ulDecryptedDataSize); // Размер расшифрованных данных if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Распечатать буфер, содержащий расшифрованный текст */ printf("Decrypted buffer is:\n"); for (i = 0; i < ulDecryptedDataSize; i++) { printf("%02X ", pbtDecryptedData[i]); if ((i + 1) % 8 == 0) printf(" pNewLocalPin, // Новый локальный PIN-код &ulNewLocalPinLen, // Длина нового локального PIN-кода ulLocalID); // Идентификатор локального PIN-кода if (rv != CKR_OK) { printf(" -> Failed\n"); } break; } if (pbtEncryptedData) { free(pbtEncryptedData); pbtEncryptedData = NULL_PTR; } if (pbtDecryptedData) { free(pbtDecryptedData); pbtDecryptedData = NULL_PTR; }printf(" -> OK\n"); |