Министерство науки и высшего образования Российской Федерации
Федеральное государственное автономное образовательное учреждение высшего образования
ТОМСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ СИСТЕМ УПРАВЛЕНИЯ И РАДИОЭЛЕКТРОНИКИ (ТУСУР)
Кафедра комплексной информационной безопасности электронно-вычислительных систем (КИБЭВС)
ШИФРОВАНИЕ ДАННЫХ С ПОМОЩЬЮ ETOKEN
Отчет по лабораторной работе №6
по дисциплине «Программно-аппаратные средства защиты информации»
Выполнил:
Студент гр. 712-2
_______ Л.С. Болтушкин
_______ 2026
Руководитель
Преподаватель кафедры КИБЭВС
_______ С.А. Пашкевич
_______ 2026
Введение
Целью данной лабораторной работы является ознакомление с типами шифрования и механизмами, обеспечивающими генерацию ключей eToken, а также приобретение навыков шифрования и расшифрования данных с помощью eToken.
1 Ход работы
Первым делом были созданы 2 уникальных файла с инициалами и группой, которые понадобятся для шифрования и дешифрования, важным условием является то, что один файл более 128 байт, второй менее (рисунок 1.1).
Рисунок 1.1 – Создание файлов
Далее прописана функция CreateSessionKey для того, чтобы создать сессионный ключ и получить его идентификатор (рисунок 1.2).
Рисунок 1.2 – Функция CreateSessionKey
Далее реализованы функции C_EncryptInit и C_EncryptUpdate, для шифрования данных (рисунок 1.3 – 1.4). В качестве механизма используйте алгоритм шифрования CKM_DES3_CBC, переменная ckm_DES3, что видно на рисунке 1.2.
Рисунок 1.3 – Реализация шифрования, часть 1
Рисунок 1.4 – Реализация шифрования, часть 2
Для расшифрования данных были использованы функции: C_DecryptInit и C_DecryptUpdate (рисунок 1.5 – 1.6).
Рисунок 1.5 – Реализация расшифрования, часть 1
Рисунок 1.6 - Реализация расшифрования, часть 2
Далее проверена работоспособность программы на ранее созданных файлах, что представлено на рисунках 1.7 – 1.9.
Рисунок 1.7 – Успешная проверка на файле размером более 128 байт, часть 1
Рисунок 1.8 - Успешная проверка на файле размером более 128 байт, часть 2
Рисунок 1.9 - Успешная проверка на файле размером менее 128 байт
В Приложении А представлен полный листинг программы.
Заключение
В ходе выполнения данной лабораторной работы были изучены типы шифрования и механизмы, обеспечивающие генерацию ключей eToken, а также получены навыки работы с шифрованием и расшифрованием данных с помощью eToken.
Приложение а
(обязательное)
Листинга программы
#include "stdlib.h"
#include "stdio.h"
#include "include\eTPkcs11.h"
#include <windows.h>
#include <string.h>
using namespace std;
void init();
void leave(const char*);
//Глобальные переменные
CK_FUNCTION_LIST_PTR pFunctionList = NULL;
CK_C_GetFunctionList pGFL = 0;
bool wasInit = false;
void init()
{
// Загружаем dll
HINSTANCE hLib = LoadLibraryA("etpkcs11.DLL");
if (hLib == NULL)
{
leave("Cannot load DLL.");
}
// Ищем точку входа для C_GetFunctionList
(FARPROC&)pGFL = GetProcAddress(hLib, "C_GetFunctionList");
if (pGFL == NULL)
{
leave("Cannot find GetFunctionList().");
}
//Берем список функций
if (CKR_OK != pGFL(&pFunctionList))
{
leave("Can't get function list. \n");
}
// Инициализируем библиотеку PKCS#11
if (CKR_OK != pFunctionList->C_Initialize(0))
{
leave("C_Initialize failed...\n");
}
wasInit = true;
}
static void leave(const char * message)
{
if (message) printf("%s\n", message);
if (wasInit)
{
// Закрываем библиотеку PKCS#11
if (CKR_OK != pFunctionList->C_Finalize(0))
{
printf("C_Finalize failed...\n");
}
wasInit = false;
}
exit(message ? -1 : 0);
}
/* Convinience method to retrieve the first PKCS#11 slot of a connected token */
static CK_ULONG GetFirstSlotId()
{
CK_ULONG slotID = -1;
CK_ULONG ulCount = 0;
CK_SLOT_ID_PTR pSlotIDs = NULL_PTR;
CK_ULONG i;
if (pFunctionList->C_GetSlotList(TRUE, NULL_PTR, &ulCount) == CKR_OK)
{
if (ulCount > 0)
{
pSlotIDs = new CK_SLOT_ID[ulCount];
if ((pFunctionList->C_GetSlotList(TRUE, pSlotIDs, &ulCount)) == CKR_OK)
{
for (i = 0; i < ulCount; i++)
{
CK_SLOT_INFO info;
if ((pFunctionList->C_GetSlotInfo(pSlotIDs[i], &info)) == CKR_OK)
{
if (info.flags & (CKF_HW_SLOT | CKF_TOKEN_PRESENT))
{
slotID = pSlotIDs[i];
break;
}
}
}
}
}
}
if (pSlotIDs)
{
delete[] pSlotIDs;
pSlotIDs = NULL_PTR;
}
return slotID;
}
//Читаем файл в массив byte
static bool ReadDataFromFile(const char* fileName, CK_BYTE_PTR* data, DWORD* dataSize)
{
bool ret = false;
HANDLE file = CreateFileA(fileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (file != INVALID_HANDLE_VALUE)
{
DWORD size = GetFileSize(file, NULL);
if (size != INVALID_FILE_SIZE)
{
*data = new BYTE[size];
if (ReadFile(file, *data, size, dataSize, NULL))
{
ret = true;
}
}
CloseHandle(file);
}
return ret;
}
//записываем массив в файл
static bool SaveDataToFile(const char* fileName, CK_BYTE_PTR data, DWORD dataSize)
{
bool ret = false;
HANDLE file = CreateFileA(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file != INVALID_HANDLE_VALUE)
{
DWORD tmp = 0;
if (WriteFile(file, data, dataSize, &tmp, NULL))
{
ret = true;
}
CloseHandle(file);
}
return ret;
}
CK_OBJECT_CLASS cko_SecretKey = CKO_SECRET_KEY;
CK_KEY_TYPE ckk_DES3 = CKK_DES3;
CK_BYTE ck_False = FALSE;
CK_MECHANISM ckm_DES3_KEY_GEN = {CKM_DES3_KEY_GEN, NULL, 0};
CK_MECHANISM ckm_DES3_CBC = {CKM_DES3_CBC, NULL, 0};
#define sizeofarray(a) (sizeof(a)/sizeof(a[0]))
// Создаем сессионный ключ шифрования
CK_OBJECT_HANDLE CreateSessionKey(CK_SESSION_HANDLE hSession)
{
CK_ATTRIBUTE SessionKeyTemplate[] =
{
{ CKA_CLASS, &cko_SecretKey, sizeof(cko_SecretKey)},
{ CKA_KEY_TYPE, &ckk_DES3, sizeof(ckk_DES3)},
{ CKA_TOKEN, &ck_False, sizeof(ck_False)}
};
CK_OBJECT_HANDLE hSessionKey = NULL;
int rv = pFunctionList->C_GenerateKey(
hSession,
&ckm_DES3_KEY_GEN,
SessionKeyTemplate,
sizeofarray(SessionKeyTemplate),
&hSessionKey);
if (rv != CKR_OK) leave("Failed to create session key");
return hSessionKey;
}
int main()
{
init();
char path[100] = "D:\\file1.txt";
char pass[20];
printf("Path to file: ");
gets(path);
printf("Token PIN: ");
gets(pass);
// Находим токен
CK_ULONG slotID = GetFirstSlotId();
if (slotID == -1)
{
leave("No token is connected.");
}
// Открываем сессию
CK_SESSION_HANDLE hSession;
if (pFunctionList->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &hSession) != CKR_OK)
{
leave("Unable to open session with the token.");
}
// Логин
if (pFunctionList->C_Login(hSession, CKU_USER, (CK_BYTE_PTR)pass, strlen(pass)) != CKR_OK)
{
leave("Unable to login to token.");
}
CK_BYTE_PTR file = NULL;
DWORD fileSize;
// Читаем файл
if (!ReadDataFromFile(path, &file, &fileSize))
{
leave("Unable to read file.");
}
printf("File size: %d bytes\n", fileSize);
printf("Original data:\n%.*s\n\n", fileSize, file);
// 1. Создаем ключ шифрования
printf("Creating session key...\n");
CK_OBJECT_HANDLE hKey = CreateSessionKey(hSession);
printf("Session key created successfully.\n\n");
// Вычисляем размер зашифрованных данных (кратный 8 байтам для DES3)
// DES3 работает с блоками по 8 байт, но в методике указаны блоки по 128 байт
DWORD encrSize = ((fileSize + 7) / 8) * 8; // Выравнивание до ближайшего кратного 8
if (encrSize < 128) encrSize = 128; // Минимальный размер для CBC режима
CK_BYTE_PTR pEncryptedData = new BYTE[encrSize];
CK_BYTE_PTR pDecryptedData = new BYTE[encrSize];
memset(pEncryptedData, 0, encrSize);
memset(pDecryptedData, 0, encrSize);
// Устанавливаем IV (инициализационный вектор) для CBC режима
CK_BYTE iv[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
ckm_DES3_CBC.pParameter = iv;
ckm_DES3_CBC.ulParameterLen = sizeof(iv);
// 2. Шифрование данных
printf("Encrypting data...\n");
// Инициализация шифрования
CK_RV rv = pFunctionList->C_EncryptInit(hSession, &ckm_DES3_CBC, hKey);
if (rv != CKR_OK) leave("C_EncryptInit failed");
// Шифрование блоками по 128 байт
CK_ULONG bytesProcessed = 0;
CK_ULONG encryptedTotal = 0;
CK_ULONG bytesToEncrypt;
CK_ULONG encryptedPartLen;
while (bytesProcessed < fileSize)
{
// Определяем размер текущего блока (не более 128 байт)
bytesToEncrypt = (fileSize - bytesProcessed) > 128 ? 128 : (fileSize - bytesProcessed);
// Создаем буфер для текущего блока с выравниванием
CK_BYTE inputBlock[128];
memset(inputBlock, 0, 128);
memcpy(inputBlock, file + bytesProcessed, bytesToEncrypt);
// Шифруем блок
encryptedPartLen = 128;
rv = pFunctionList->C_EncryptUpdate(hSession, inputBlock, 128,
pEncryptedData + encryptedTotal, &encryptedPartLen);
if (rv != CKR_OK) leave("C_EncryptUpdate failed");
encryptedTotal += encryptedPartLen;
bytesProcessed += bytesToEncrypt;
printf("Processed %d bytes, encrypted %lu bytes\n", bytesProcessed, encryptedTotal);
}
// Завершаем шифрование
CK_ULONG lastPartLen = encrSize - encryptedTotal;
rv = pFunctionList->C_EncryptFinal(hSession, pEncryptedData + encryptedTotal, &lastPartLen);
if (rv != CKR_OK) leave("C_EncryptFinal failed");
encryptedTotal += lastPartLen;
printf("Encryption completed. Total encrypted: %lu bytes\n\n", encryptedTotal);
// Выводим зашифрованные данные в шестнадцатеричном формате
printf("Encrypted data (hex):\n");
for (DWORD i = 0; i < encryptedTotal; i++)
{
printf("%02X ", pEncryptedData[i]);
if ((i + 1) % 16 == 0) printf("\n");
}
printf("\n\n");
// 3. Расшифрование данных
printf("Decrypting data...\n");
// Инициализация расшифрования (с тем же IV)
rv = pFunctionList->C_DecryptInit(hSession, &ckm_DES3_CBC, hKey);
if (rv != CKR_OK) leave("C_DecryptInit failed");
// Расшифрование блоками по 128 байт
bytesProcessed = 0;
CK_ULONG decryptedTotal = 0;
CK_ULONG decryptedPartLen;
while (bytesProcessed < encryptedTotal)
{
// Определяем размер текущего блока (128 байт, кроме последнего)
CK_ULONG bytesToDecrypt = (encryptedTotal - bytesProcessed) > 128 ? 128 : (encryptedTotal - bytesProcessed);
decryptedPartLen = 128;
rv = pFunctionList->C_DecryptUpdate(hSession, pEncryptedData + bytesProcessed, bytesToDecrypt,
pDecryptedData + decryptedTotal, &decryptedPartLen);
if (rv != CKR_OK) leave("C_DecryptUpdate failed");
decryptedTotal += decryptedPartLen;
bytesProcessed += bytesToDecrypt;
printf("Decrypted %lu bytes\n", decryptedTotal);
}
// Завершаем расшифрование
CK_ULONG finalPartLen = encrSize - decryptedTotal;
rv = pFunctionList->C_DecryptFinal(hSession, pDecryptedData + decryptedTotal, &finalPartLen);
if (rv != CKR_OK)
{
printf("Warning: C_DecryptFinal returned 0x%08X\n", rv);
}
else
{
decryptedTotal += finalPartLen;
}
printf("Decryption completed. Total decrypted: %lu bytes\n\n", decryptedTotal);
// Выводим расшифрованные данные
printf("Decrypted data (first %d bytes):\n", fileSize);
for (DWORD i = 0; i < fileSize; i++)
{
printf("%c", pDecryptedData[i]);
}
printf("\n\n");
// Проверка результатов
if (memcmp(file, pDecryptedData, fileSize) == 0)
{
printf("SUCCESS: Decrypted data matches original!\n");
}
else
{
printf("ERROR: Decrypted data does not match original!\n");
}
// Сохраняем зашифрованные данные в файл
char encryptedFileName[120];
sprintf(encryptedFileName, "%s.enc", path);
if (SaveDataToFile(encryptedFileName, pEncryptedData, encryptedTotal))
{
printf("Encrypted data saved to %s\n", encryptedFileName);
}
// Закрываем
pFunctionList->C_Logout(hSession);
pFunctionList->C_CloseSession(hSession);
delete[] file;
delete[] pEncryptedData;
delete[] pDecryptedData;
printf("\nPress any key to exit...");
getchar();
getchar();
leave(NULL);
return 0;
}
Томск 2026
