Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

МСЗИ_23_ИСТ_1_1_Какушкина_Ольга_Витальевна_ЛР_2

.docx
Скачиваний:
0
Добавлен:
23.06.2025
Размер:
146.95 Кб
Скачать

МИНОБРНАУКИ РОССИИ

Ф едеральное государственное бюджетное образовательное учреждение высшего образования

НИЖЕГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ

УНИВЕРСИТЕТ им. Р.Е.АЛЕКСЕЕВА

Институт радиоэлектроники и информационных технологий

Кафедра информатики и систем управления

ОТЧЕТ по лабораторной работе №2

Стандарт шифрования данных DES в режиме «Обратная связь по шифру».

по дисциплине

Методы и средства защиты информации

(наименование дисциплины)

РУКОВОДИТЕЛЬ:

________________ Жуков М. С.

(подпись) (фамилия, и.,о.)

СТУДЕНТ:

________________ Какушкина О.В.

(подпись) (фамилия, и.,о.)

23-ИСТ-1-1

(шифр группы)

Работа защищена «___» ____________

С оценкой ________________________

Нижний Новгород 2025

Текст задания №2.3:

Реализовать стандарт шифрования данных DES в режиме «Обратная связь по шифру».

Данная программа реализует алгоритм шифрования DES (Data Encryption Standard) в режиме обратной связи по шифру (CFB). Это симметричный блочный шифр, работающий с 64-битными блоками данных.

Таблицы перестановок и преобразований

  1. PC1 - Первоначальная перестановка ключа (64 бита → 56 бит)

  2. PC2 - Перестановка для генерации подключей (56 бит → 48 бит)

  3. IP - Начальная перестановка блока данных

  4. IP_INV - Конечная перестановка (обратная IP)

  5. E - Расширяющая перестановка (32 бита → 48 бит)

  6. S_BOX - 8 S-блоков для нелинейного преобразования

  7. P - Перестановка после S-блоков

  8. SHIFT_SCHEDULE - График сдвигов для генерации ключей

Класс DES_CFB

Приватные методы

  1. permutePC1(const bitset<64>& key)

    • Назначение: Первоначальная перестановка ключа по таблице PC1

    • Вход: 64-битный ключ

    • Выход: 56-битный ключ

  2. permutePC2(const bitset<56>& key)

    • Назначение: Перестановка для генерации подключа по таблице PC2

    • Вход: 56-битный ключ

    • Выход: 48-битный подключ

  3. generateRoundKeys(const bitset<64>& key)

    • Назначение: Генерация 16 раундовых ключей

    • Алгоритм:

      1. Применяет PC1 к ключу

      2. Разделяет на две 28-битные половины

      3. Для каждого раунда:

        • Сдвигает половины согласно графику

        • Объединяет и применяет PC2

        • Сохраняет подключ

  4. leftShift(bitset<28> bits, int shifts)

    • Назначение: Циклический сдвиг влево

    • Вход: 28 бит, количество сдвигов

    • Выход: Сдвинутые 28 бит

  5. permuteIP(const bitset<64>& block)

    • Назначение: Начальная перестановка блока данных

    • Вход: 64-битный блок

    • Выход: Переставленный 64-битный блок

  6. permuteIPInv(const bitset<64>& block)

    • Назначение: Конечная перестановка (обратная IP)

    • Вход: 64-битный блок

    • Выход: Переставленный 64-битный блок

  7. feistel(const bitset<32>& right, const bitset<48>& roundKey)

    • Назначение: Функция Фейстеля для одного раунда

    • Алгоритм:

  1. Расширение до 48 бит (E)

  2. XOR с подключом

  3. Проход через S-блоки

  4. Перестановка P

  1. processBlock(const bitset<64>& block, bool isDecrypt)

    • Назначение: Обработка одного блока (шифрование/дешифрование)

    • Алгоритм:

  1. Начальная перестановка (IP)

  2. 16 раундов Фейстеля

  3. Конечная перестановка (IP_INV)

  1. stringToBitset(const string& s)

    • Назначение: Преобразование строки в 64-битный блок

    • Особенности: Дополняет нулями при необходимости

  2. bitsetToString(const bitset<64>& bits)

    • Назначение: Преобразование 64-битного блока в строку

Публичные методы

  1. Конструктор DES_CFB(const string& keyStr, const string& ivStr)

    • Инициализирует ключи и вектор инициализации

  2. encrypt(const string& plaintext)

    • Назначение: Шифрование в режиме CFB

    • Алгоритм:

      1. Начинает с IV

      2. Для каждого блока:

        • Шифрует регистр обратной связи

        • XOR с блоком открытого текста

        • Результат становится новым регистром

  3. decrypt(const string& ciphertext)

    • Назначение: Дешифрование в режиме CFB

    • Алгоритм:

  1. Начинает с IV

  2. Для каждого блока:

    • Шифрует регистр обратной связи

    • XOR с блоком шифртекста

    • Шифрблок становится новым регистром

  3. Удаляет дополнение

Вспомогательные функции

  1. enterText()

    • Запрашивает у пользователя текст для обработки

  2. main()

    • Точка входа в программу

    • Реализует интерактивный интерфейс:

      • Ввод ключа и IV

      • Выбор операции (шифрование/дешифрование)

      • Обработка и вывод результатов

Примеры шифрования и расшифровывания:

  1. Исходное сообщение: kakushkinaolga

  2. Зашифрованные данные: 0dfbc78329f0de4c4cae48c27d4b8d2

  3. Расшифрованные данные: kakushkinaolga

#include <iostream>

#include <string>

#include <bitset>

#include <vector>

#include <algorithm>

#include <iomanip>

#include <stdexcept>

using namespace std;

// первоначальное преобразование

const int PC1[] = {

57, 49, 41, 33, 25, 17, 9,

1, 58, 50, 42, 34, 26, 18,

10, 2, 59, 51, 43, 35, 27,

19, 11, 3, 60, 52, 44, 36,

63, 55, 47, 39, 31, 23, 15,

7, 62, 54, 46, 38, 30, 22,

14, 6, 61, 53, 45, 37, 29,

21, 13, 5, 28, 20, 12, 4

};

// второе преобразование

const int PC2[] = {

14, 17, 11, 24, 1, 5,

3, 28, 15, 6, 21, 10,

23, 19, 12, 4, 26, 8,

16, 7, 27, 20, 13, 2,

41, 52, 31, 37, 47, 55,

30, 40, 51, 45, 33, 48,

44, 49, 39, 56, 34, 53,

46, 42, 50, 36, 29, 32

};

// таблица для определения количества сдвигов в каждом раунде

const int SHIFT_SCHEDULE[] = {

1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1

};

// матрица начальной перестановки

const int IP[] = {

58, 50, 42, 34, 26, 18, 10, 2,

60, 52, 44, 36, 28, 20, 12, 4,

62, 54, 46, 38, 30, 22, 14, 6,

64, 56, 48, 40, 32, 24, 16, 8,

57, 49, 41, 33, 25, 17, 9, 1,

59, 51, 43, 35, 27, 19, 11, 3,

61, 53, 45, 37, 29, 21, 13, 5,

63, 55, 47, 39, 31, 23, 15, 7

};

// матрица конечной перестановки

const int IP_INV[] = {

40, 8, 48, 16, 56, 24, 64, 32,

39, 7, 47, 15, 55, 23, 63, 31,

38, 6, 46, 14, 54, 22, 62, 30,

37, 5, 45, 13, 53, 21, 61, 29,

36, 4, 44, 12, 52, 20, 60, 28,

35, 3, 43, 11, 51, 19, 59, 27,

34, 2, 42, 10, 50, 18, 58, 26,

33, 1, 41, 9, 49, 17, 57, 25

};

//Функция расширитель E

const int E[] = {

32, 1, 2, 3, 4, 5,

4, 5, 6, 7, 8, 9,

8, 9, 10, 11, 12, 13,

12, 13, 14, 15, 16, 17,

16, 17, 18, 19, 20, 21,

20, 21, 22, 23, 24, 25,

24, 25, 26, 27, 28, 29,

28, 29, 30, 31, 32, 1

};

// S-блоки

const int S_BOX[8][4][16] = {

// S1

{

{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},

{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},

{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},

{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}

},

// S2

{

{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},

{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},

{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},

{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}

},

// S3

{

{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},

{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},

{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},

{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}

},

// S4

{

{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},

{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},

{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},

{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}

},

// S5

{

{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},

{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},

{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},

{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}

},

// S6

{

{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},

{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},

{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},

{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}

},

// S7

{

{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},

{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},

{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},

{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}

},

// S8

{

{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},

{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},

{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},

{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}

}

};

// перестановка

const int P[] = {

16, 7, 20, 21,

29, 12, 28, 17,

1, 15, 23, 26,

5, 18, 31, 10,

2, 8, 24, 14,

32, 27, 3, 9,

19, 13, 30, 6,

22, 11, 4, 25

};

class DES_CFB {

private:

vector<bitset<48>> roundKeys;

bitset<64> iv; // вектор инициализации

// выполняем начальную перестановку 64-битного ключа в 56-битный с использованием таблицы PC1

bitset<56> permutePC1(const bitset<64>& key) {

bitset<56> result;

for (int i = 0; i < 56; i++) {

result[55 - i] = key[64 - PC1[i]];

}

return result;

}

// Перестановка 56-битного ключа в 48-битный с использованием таблицы PC2

bitset<48> permutePC2(const bitset<56>& key) {

bitset<48> result;

for (int i = 0; i < 48; i++) {

result[47 - i] = key[56 - PC2[i]];

}

return result;

}

// Гнерация ключей

void generateRoundKeys(const bitset<64>& key) {

bitset<56> permutedKey = permutePC1(key); // началаьная перестановка PC1

bitset<28> left, right;

// Разделяет ключ на две 28-битные половины (left и right)

for (int i = 0; i < 28; i++) {

left[27 - i] = permutedKey[55 - i];

right[27 - i] = permutedKey[27 - i];

}

roundKeys.clear();

for (int round = 0; round < 16; round++) {

// Выполняет циклический сдвиг влево для обеих половин

left = leftShift(left, SHIFT_SCHEDULE[round]);

right = leftShift(right, SHIFT_SCHEDULE[round]);

// Объединяет половины

bitset<56> combined;

for (int i = 0; i < 28; i++) {

combined[55 - i] = left[27 - i];

combined[27 - i] = right[27 - i];

}

// Применяет перестановку PC2 для получения раундового ключа и сохраняет ключ в roundKeys

roundKeys.push_back(permutePC2(combined));

}

}

// Выполняет циклический сдвиг битов влево на указанное количество позиций

bitset<28> leftShift(bitset<28> bits, int shifts) {

bitset<28> result;

for (int i = 0; i < 28; i++) {

result[i] = bits[(i + shifts) % 28];

}

return result;

}

// Начальная перестановка блока данных (64 бита) с использованием таблицы IP

bitset<64> permuteIP(const bitset<64>& block) {

bitset<64> result;

for (int i = 0; i < 64; i++) {

result[63 - i] = block[64 - IP[i]];

}

return result;

}

// Обратная перестановка блока данных с использованием таблицы IP_INV

bitset<64> permuteIPInv(const bitset<64>& block) {

bitset<64> result;

for (int i = 0; i < 64; i++) {

result[63 - i] = block[64 - IP_INV[i]];

}

return result;

}

// основная функция преобразования - функция Фейстеля

bitset<32> feistel(const bitset<32>& right, const bitset<48>& roundKey) {

// 32-битный блок расширяется до 48 бит с использованием таблицы E

bitset<48> expanded;

for (int i = 0; i < 48; i++) {

expanded[47 - i] = right[32 - E[i]];

}

// XOR с раундовым ключом

expanded ^= roundKey;

// 48-битный блок разделяется на 8 6-битных частей, каждая преобразуется в 4 бита с помощью соответствующих S-боксов

bitset<32> substituted;

for (int i = 0; i < 8; i++) {

int row = expanded[47 - (i * 6)] * 2 + expanded[47 - (i * 6 + 5)];

int col = expanded[47 - (i * 6 + 1)] * 8 +

expanded[47 - (i * 6 + 2)] * 4 +

expanded[47 - (i * 6 + 3)] * 2 +

expanded[47 - (i * 6 + 4)];

int val = S_BOX[i][row][col];

for (int j = 0; j < 4; j++) {

substituted[31 - (i * 4 + j)] = (val >> (3 - j)) & 1;

}

}

// результат преобразуется с использованием таблицы P

bitset<32> result;

for (int i = 0; i < 32; i++) {

result[31 - i] = substituted[32 - P[i]];

}

return result;

}

// Обработка блока

bitset<64> processBlock(const bitset<64>& block, bool isDecrypt) {

bitset<64> permuted = permuteIP(block); // Применяет начальную перестановку IP

// Разделяет блок на две 32 - битные половины(left и right)

bitset<32> left, right;

for (int i = 0; i < 32; i++) {

left[31 - i] = permuted[63 - i];

right[31 - i] = permuted[31 - i];

}

// Выполняет 16 раундов Фейстеля

// для шифрования в прямом порядке 0-15, для дешифр в обратном 15 - 0

for (int round = 0; round < 16; round++) {

bitset<32> newRight = left ^ feistel(right, roundKeys[isDecrypt ? 15 - round : round]);

left = right;

right = newRight;

}

// объединяет половины (меняя лево и право местами)

bitset<64> combined;

for (int i = 0; i < 32; i++) {

combined[63 - i] = right[31 - i];

combined[31 - i] = left[31 - i];

}

// Применяет обратную перестановку IP_INV

return permuteIPInv(combined);

}

// Преобразует строку (до 8 символов) в 64-битный блок, каждый символ кодируется в 8 бит

bitset<64> stringToBitset(const string& s) {

if (s.length() > 8) {

throw runtime_error("Key must be 8 characters or less");

}

bitset<64> result;

for (size_t i = 0; i < s.length(); i++) {

for (int j = 0; j < 8; j++) {

result[i * 8 + j] = (s[i] >> (7 - j)) & 1;

}

}

return result;

}

// Преобразует 64-битный блок обратно в строку (8 символов)

string bitsetToString(const bitset<64>& bits) {

string result;

for (int i = 0; i < 8; i++) {

char c = 0;

for (int j = 0; j < 8; j++) {

c |= bits[i * 8 + j] << (7 - j);

}

result += c;

}

return result;

}

public:

DES_CFB(const string& keyStr, const string& ivStr = "defaultiv") {

// Преобразование строки ключа в битовый набор

bitset<64> key = stringToBitset(keyStr);

// Генерация раундовых ключей

generateRoundKeys(key);

// Установка вектора инициализации (IV)

iv = stringToBitset(ivStr.substr(0, 8));

}

// шифрование

string encrypt(const string& plaintext) {

string ciphertext;

bitset<64> feedback = iv; // Начинаем с IV

for (size_t i = 0; i < plaintext.length(); i += 8) {

// // Берём блок открытого текста (8 символов = 64 бита)

string blockStr = plaintext.substr(i, 8);

while (blockStr.length() < 8) blockStr += '\0'; // Дополнение нулями

// Шифруем регистр обратной связи (feedback)

bitset<64> encryptedFeedback = processBlock(feedback, false);

// XOR с блоком открытого текста → получаем шифрблок

bitset<64> plainBlock = stringToBitset(blockStr);

bitset<64> cipherBlock = plainBlock ^ encryptedFeedback;

// Обновляем feedback для следующего блока

feedback = cipherBlock;

// Добавляем шифрблок к результату

ciphertext += bitsetToString(cipherBlock);

}

return ciphertext;

}

// дешифрование

string decrypt(const string& ciphertext) {

string plaintext;

bitset<64> feedback = iv; // // Начинаем с IV

for (size_t i = 0; i < ciphertext.length(); i += 8) {

// Берём блок шифртекста (8 символов = 64 бита)

string blockStr = ciphertext.substr(i, 8);

// Шифруем регистр обратной связи (feedback)

bitset<64> encryptedFeedback = processBlock(feedback, false);

// XOR с блоком шифртекста → получаем открытый текст

bitset<64> cipherBlock = stringToBitset(blockStr);

bitset<64> plainBlock = cipherBlock ^ encryptedFeedback;

// Обновляем feedback для следующего блока

feedback = cipherBlock;

// Добавляем расшифрованный блок к результату

plaintext += bitsetToString(plainBlock);

}

// Удаляем дополнение (нули в конце)

size_t padPos = plaintext.find_last_not_of('\0');

if (padPos != string::npos) {

plaintext = plaintext.substr(0, padPos + 1);

}

else {

plaintext.clear();

}

return plaintext;

}

};

string enterText() {

string text;

cout << "Enter text: ";

getline(cin, text);

return text;

}

int main() {

setlocale(LC_ALL, "Russian");

cout << "DES in CFB mode implementation" << endl;

while (true) {

cout << "\nEnter 0 to exit, or any other key to continue: ";

string choice;

getline(cin, choice);

if (choice == "0") break;

// Get key from user

string key;

cout << "Enter key (up to 8 characters): ";

getline(cin, key);

if (key.empty()) {

cout << "Key cannot be empty!" << endl;

continue;

}

// Get IV from user

string iv;

cout << "Enter initialization vector (up to 8 characters, leave empty for default): ";

getline(cin, iv);

DES_CFB des(key, iv.empty() ? "defaultiv" : iv);

cout << "\n1. Encrypt\n2. Decrypt\nEnter choice: ";

string option;

getline(cin, option);

if (option == "1") {

string plaintext = enterText();

string ciphertext = des.encrypt(plaintext);

cout << "\nEncrypted text (hex): ";

for (char c : ciphertext) {

cout << hex << setw(2) << setfill('0') << (int)(unsigned char)c;

}

cout << endl;

}

else if (option == "2") {

string ciphertextHex;

cout << "Enter ciphertext in hex format: ";

getline(cin, ciphertextHex);

// Convert hex to string

string ciphertext;

for (size_t i = 0; i < ciphertextHex.length(); i += 2) {

string byteStr = ciphertextHex.substr(i, 2);

char byte = (char)stoi(byteStr, nullptr, 16);

ciphertext += byte;

}

string plaintext = des.decrypt(ciphertext);

cout << "\nDecrypted text: " << plaintext << endl;

}

else {

cout << "Invalid choice!" << endl;

}

}

return 0;

}

Вывод программы

Вывод:

В ходе лабораторной работы я работала с стандартом шифрования данных DES в режиме «Обратная связь по шифру». Научилась шифровать и расшифровывать текст данным методом.