...
Подпись на Рутокен 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, // Длина подписываемых данных 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; } |
Подпись данных в формате CMS (PKCS#7)
...
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()
передать пустой блок данных, то функция вернет суммарный размер всех блоков зашифрованных данных.
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, // Хэндл сессии
&EncDecMech, // Механизм шифрования
hSecKey); // Хэндл секретного ключа
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
/* Получить размер зашифрованного текста */
printf("Getting encrypted data size");
rv = pFunctionList->C_Encrypt(hSession, // Хэндл сессии
pbtData, // Буфер с открытыми данными для шифрования
arraysize(pbtData), // Длина буфера с открытыми данными, в байтах
NULL, // Буфер с зашифрованными данными
&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, // Хэндл сессии
pbtData, // Буфер с открытыми данными для шифрования
arraysize(pbtData), // Длина буфера с открытыми данными, в байтах
pbtEncryptedData, // Буфер с зашифрованными данными
&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;
}
|
Code Block | ||||
---|---|---|---|---|
| ||||
/* Данные для шифрования */
CK_BYTE pbtData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00 };
CK_BYTE IV[] = {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; // Размер блока данных, в байтах
CK_ULONG ulCurrentPosition = 0; // Текущее начало блока
CK_ULONG ulRestLen = 0; // Размер оставшегося буфера, в байтах
while(TRUE)
{
...
/* Инициализировать операцию шифрования */
printf("C_EncryptInit");
rv = pFunctionList->C_EncryptInit(hSession, // Хэндл сессии
&EncDecStreamMech, // Механизм шифрования
hSecKey); // Хэндл секретного ключа
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
/* Зашифровать открытый текст */
ulEncryptedDataSize = arraysize(pbtData);
ulRestLen = arraysize(pbtData);
pbtEncryptedData = (CK_BYTE*)malloc(ulEncryptedDataSize);
memset( pbtEncryptedData,
0,
(ulEncryptedDataSize * sizeof(CK_BYTE)));
while (ulRestLen)
{
if (ulBlockSize > ulRestLen)
ulBlockSize = ulRestLen;
printf("Block size: %u B (Total: %u of %u) ", ulBlockSize, ulCurrentPosition + ulBlockSize, ulEncryptedDataSize);
rv = pFunctionList->C_EncryptUpdate(hSession, // Хэндл сессии
pbtData + ulCurrentPosition, // Буфер с блоком данных для шифрования
ulBlockSize, // Размер блока, в байтах
pbtEncryptedData + ulCurrentPosition, // Буфер с блоком зашифрованных данных
&ulBlockSize); // Размер блока, в байтах
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
ulCurrentPosition += ulBlockSize;
ulRestLen -= ulBlockSize;
}
if (rv != CKR_OK)
break;
printf("Finalizing encryption");
rv = pFunctionList->C_EncryptFinal( hSession, // Хэндл сессии
NULL_PTR, // Буфер с последним блоком данных
&ulEncryptedDataSize); // Длина буфера
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
/* Распечатать буфер, содержащий зашифрованные данные*/
printf("Encrypted buffer is:\n");
for (i = 0;
i < ulEncryptedDataSize;
i++)
{
printf("%02X ", pbtEncryptedData[i]);
if ((i + 1) % 8 == 0)
printf("\n");
}
break;
} |
Расшифрование данных
Для расшифрования данных служат функции C_DecryptInit()
и C_Decrypt()
для любого режима шифрования.
Сначала операцию расшифрования нужно инициализировать вызовом функции C_DecryptInit()
, передав в нее идентификатор сессии, механизма и секретного ключа. В параметрах механизма для ГОСТ 28147-89 можно задать вектор инициализации и его длину.
Далее расшифрование выполняется вызовом функции C_Decrypt()
с передачей в нее зашифрованные данные. Размер расшифрованных данных можно узнать, вызвав C_Decrypt()
с пустым указателем вместо указателя на буфера для расшифрованных данных.
Code Block | ||||
---|---|---|---|---|
| ||||
while(TRUE)
{
...
/* Инициализировать операцию расшифрования */
printf("C_DecryptInit");
rv = pFunctionList->C_DecryptInit(hSession, // Хэндл сессии
&EncDecStreamMech, // Механизм расшифрования
hSecKey); // Хэндл секретного ключа
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
/* Расшифровать шифротекст */
printf("Getting decrypted data size");
rv = pFunctionList->C_Decrypt(hSession, // Хэндл сессии
pbtEncryptedData, // Буфер с зашифрованными данными
ulEncryptedDataSize, // Размер зашифрованных данных
NULL_PTR, // Буфер с расшифрованными данными
&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_Decrypt");
rv = pFunctionList->C_Decrypt(hSession, // Хэндл сессии
pbtEncryptedData, // Буфер с зашифрованными данными
ulEncryptedDataSize, // Размер зашифрованных данных
pbtDecryptedData, // Буфер с расшифрованными данными
&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("\n");
}
break;
}
if (pbtEncryptedData)
{
free(pbtEncryptedData);
pbtEncryptedData = NULL_PTR;
}
if (pbtDecryptedData)
{
free(pbtDecryptedData);
pbtDecryptedData = NULL_PTR;
} |