Добавлен: 08.11.2023
Просмотров: 15
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
ОТЧЕТ
О ВЫПЛНЕНИИ ЛАБОРАТОРНОЙ РАБОТЫ № 2
Задание.
№Варианта | Название алгоритма | Режим шифрования |
10 | ГОСТ 28147-89 | OFB |
Общие сведения.
Алгоритм шифрования ГОСТ 28147-89 является симметричным, блочным алгоритмом. Преобразование осуществляется над блоком размером 64 бита, размер секретного ключа 256 бит, в алгоритме 32 раунда преобразований.
Необходимые определения и обозначения:
– блок открытого текста размером 64 бита;
– блок зашифрованного текста размером 64 бита;
– секретный ключ (256 бит);
– раундовый ключ.
В алгоритме ГОСТ используются следующие операции:
S-блок или S-box – табличная подстановка, при которой группа бит отображается в другую группу бит;
– операция сложения по модулю 232;
или XOR – операция сложения по модулю 2 (или побитовое «исключающее или»);
11 – циклический сдвиг влево на 11 бит.
Эти операции циклически повторяются в алгоритме, образуя так называемые раунды. Входом каждого раунда является выход предыдущего раунда и раундовый подключ , который получен из секретного ключа шифрования следующим образом. Рассмотрим секретный ключ (256 бит), состоящий из восьми слов по 32 бита:
. На их основе строим раундовый ключ: Основная схема алгоритма ГОСТ представлена на рисунке 1
.
Рис. 1. Основная схема алгоритма ГОСТ
Для шифрования блок открытого текста сначала разбивается на две одинаковые части, правую R (младшее слово) и левую L (старшее слово) рисунок 2.
Рис. 2. Схема одного раунда алгоритма ГОСТ
На i-м раунде используется подключ . Правая часть складывается по модулю 232 с раундовым подключом . Над получившимся результатом выполняется операция табличной подстановки рисунок 3.
Рис. 3. Подстановка S-блоками
Для этого результат разбивается на восемь 4-битовых кусочков, каждый из которых подается на вход своего S-блока: первые четыре бита в S0-блок, вторые – в S1-блок и так далее. Каждый S-блок содержит 16 четырехбитовых элементов, нумеруемых с 0 по 15. ГОСТ рекомендует заполнять каждую из восьми таблиц различными числами множества {0, 1, 2, …, 15}, переставленными случайным образом.
S0-блок | ||||||||||||||||
№ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Элемент | 4 | 10 | 9 | 2 | 13 | 8 | 0 | 14 | 6 | 11 | 1 | 12 | 7 | 15 | 5 | 3 |
S1-блок | ||||||||||||||||
№ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Элемент | 14 | 11 | 4 | 12 | 6 | 13 | 15 | 10 | 2 | 3 | 8 | 1 | 0 | 7 | 5 | 9 |
S2-блок | ||||||||||||||||
№ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Элемент | 5 | 8 | 1 | 13 | 10 | 3 | 4 | 2 | 14 | 15 | 12 | 7 | 6 | 0 | 9 | 11 |
S3-блок | ||||||||||||||||
№ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Элемент | 7 | 13 | 10 | 1 | 0 | 8 | 9 | 15 | 14 | 4 | 6 | 12 | 11 | 2 | 5 | 3 |
S4-блок | ||||||||||||||||
№ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Элемент | 6 | 12 | 7 | 1 | 5 | 15 | 13 | 8 | 4 | 10 | 9 | 14 | 0 | 3 | 11 | 2 |
S5-блок | ||||||||||||||||
№ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Элемент | 4 | 11 | 10 | 0 | 7 | 2 | 1 | 13 | 3 | 6 | 8 | 5 | 9 | 12 | 15 | 14 |
S6-блок | ||||||||||||||||
№ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Элемент | 13 | 11 | 4 | 1 | 3 | 15 | 5 | 9 | 0 | 10 | 14 | 7 | 6 | 8 | 2 | 12 |
S7-блок | ||||||||||||||||
№ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Элемент | 1 | 15 | 13 | 0 | 5 | 7 | 10 | 4 | 9 | 2 | 3 | 14 | 6 | 11 | 8 | 12 |
Рис. 4. Набор S-блоков Центрального банка РФ
По входным четырем битам определяется номер элемента в S-блоке, который поступает на выход. Выходы всех восьми S-блоков объединяются в 32-битовое слово, затем все слово циклически сдвигается влево на 11 бит. Наконец, результат объединяется с помощью XOR с левой половиной, и получается новая правая половина, а правая половина становится левой половиной. Эти операции выполняются 32 раза. После этого левая и правая части меняются местами.
Запишем базовый цикл алгоритма ГОСТ.
Вход: Блок , , раундовый ключ .
Выход: Преобразованный блок , .
FOR TO 31 DO
;
FOR TO 7 DO
RETURN
Для шифрования и дешифрования сообщения используется один алгоритм. Единственным различием является генерация раундового ключа. Чтобы дешифровать блок, строим раундовый ключ
,
подаем на вход и на выходе получаем .
ЛИСТИНГ ПРОГРАММЫ
#include "stdafx.h"
#include
#define OPENFILE "D:\\opentext.txt"
#define CRYPTEDFILE "D:\\cryptedtext.txt"
#define DECRYPTEDFILE "D:\\decryptedtext.txt"
#define SEKRETKEY "98765432109876543210987654321098"
#define CRYPT false
#define DECRYPT true
using namespace std;
int reverse_bit(int X)
{
return
X = // Реверсирование битов
((X & 0x1) <<31)+((X & 0x2) <<29)+((X & 0x4) <<27)+((X & 0x8) <<25)+
((X & 0x10) <<23)+((X & 0x20) <<21)+((X & 0x40) <<19)+((X & 0x80) <<17)+
((X & 0x100) <<15)+((X & 0x200) <<13)+((X & 0x400) <<11)+((X & 0x800) << 9)+
((X & 0x1000) << 7)+((X & 0x2000) << 5)+((X & 0x4000) << 3)+((X & 0x8000) << 1)+
((X & 0x10000) >> 1)+((X & 0x20000) >> 3)+((X & 0x40000) >> 5)+((X & 0x80000) >> 7)+
((X & 0x100000) >> 9)+((X & 0x200000) >>11)+((X & 0x400000) >>13)+((X & 0x800000) >>15)+
((X & 0x1000000) >>17)+((X & 0x2000000) >>19)+((X & 0x4000000) >>21)+((X & 0x8000000) >>23)+
((X & 0x10000000) >>25)+((X & 0x20000000) >>27)+((X & 0x40000000) >>29)+((X & 0x80000000) >>31);
}
int reverse_block(int X)
{
return
X = // Реверсирование 8-битных блоков + реверс битов результата
((X & 0x1) << 7)+((X & 0x2) << 5)+((X & 0x4) << 3)+((X & 0x8) << 1)+
((X & 0x10) >> 1)+((X & 0x20) >> 3)+((X & 0x40) >> 5)+((X & 0x80) >> 7)+
((X & 0x100) << 7)+((X & 0x200) << 5)+((X & 0x400) << 3)+((X & 0x800) << 1)+
((X & 0x1000) >> 1)+((X & 0x2000) >> 3)+((X & 0x4000) >> 5)+((X & 0x8000) >> 7)+
((X & 0x10000) << 7)+((X & 0x20000) << 5)+((X & 0x40000) << 3)+((X & 0x80000) << 1)+
((X & 0x100000) >> 1)+((X & 0x200000) >> 3)+((X & 0x400000) >> 5)+((X & 0x800000) >> 7)+
((X & 0x1000000) << 7)+((X & 0x2000000) << 5)+((X & 0x4000000) << 3)+((X & 0x8000000) << 1)+
((X & 0x10000000) >> 1)+((X & 0x20000000) >> 3)+((X & 0x40000000) >> 5)+((X & 0x80000000) >> 7);
}
void GOST(bool mode)
{
//--8 S-box'ов----------------------------------------
unsigned int Sbox[8][16] =
{
{4,10,9,2,13,8,0,14,6,11,1,12,7,15,5,3},
{14,11,4,12,6,13,15,10,2,3,8,1,0,7,5,9},
{5,8,1,13,10,3,4,2,14,15,12,7,6,0,9,11},
{7,13,10,1,0,8,9,15,14,4,6,12,11,2,5,3},
{6,12,7,1,5,15,13,8,4,10,9,14,0,3,11,2},
{4,11,10,0,7,2,1,13,3,6,8,5,9,12,15,14},
{13,11,4,1,3,15,5,9,0,10,14,7,6,8,2,12},
{1,15,13,0,5,7,10,4,9,2,3,14,6,11,8,12}
};
//--Ключ шифрования и его разбиение--------------------
char s[33] = SEKRETKEY;
unsigned int key[8];
for(int i = 0; i<8; i++)
{
key[i] = (s[4*i]<<24) + (s[1+4*i]<<16) + (s[2+4*i]<<8) + s[3+4*i]; // Складывание каждых 4-х символов ключа в одно число
key[i] = reverse_bit(key[i]); // Реверсирование битов
}
//--Открытие файла-------------------------------------
FILE* f; // Входной файл
FILE* g; // Выходной файл
int fsize; // Размер входного файла
if(mode == CRYPT)
{
f = fopen(OPENFILE, "r");
fseek (f, 0, SEEK_END); // Вычисление размера файла
fsize = ftell(f);
fseek (f, 0, SEEK_SET);
g = fopen(CRYPTEDFILE, "w");
}
if(mode == DECRYPT)
{
f = fopen(CRYPTEDFILE, "r");
fseek (f, 0, SEEK_END); // Вычисление размера файла
fsize = ftell(f);
fseek (f, 0, SEEK_SET);
g = fopen(DECRYPTEDFILE, "w");
}
//--Основной цикл шифрования---------------------------
while(fsize)
{
unsigned int A = 0; // Страший 32-битный блок
unsigned int B = 0; // Младший 32-битный блок
//------------------------------------
if(fsize>=4) // Заполнение старшего блока...
{
fread(&A, 4, 1, f); // ...символами...
fsize -= 4;
}
else
{
fread(&A, fsize, 1, f);
for(int i = 0; i<(4-fsize); i++)
{
A += (32<<(24-(i*8))); // ... или пробелами, если символы кончились,
fsize = 0; // а 64 бита еще не набралось
}
}
//------------------------------------
if(fsize>=4) // Заполнение младшего блока...
{
fread(&B, 4, 1, f); // ...символами...
fsize -= 4;
}
else
{
fread(&B, fsize, 1, f);
for(int i = 0; i<(4-fsize); i++)
{
B += (32<<(24-(i*8))); // ... или пробелами, если символы кончились,
fsize = 0; // а 64 бита еще не набралось
}
}
//------------------------------------
A = reverse_block(A); // Реверсирование блоков с последующим реверсом бит
B = reverse_block(B); // Реверсирование блоков с последующим реверсом бит
unsigned int T; // Для промежуточных вычислений
//--32 раунда--------------------------------------
for(int i = 0; i<32; i++)
{
T = 0;
if(mode == CRYPT)
{
if(i<24) T = (A+key[i%8]) % 0x100000000; // суммирование с ключом в зависимости от раунда
else T = (A+key[7-(i%8)]) % 0x100000000;
}
if(mode == DECRYPT)
{
if(i<8) T = (A+key[i%8]) % 0x100000000; // суммирование с ключом в зависимости от раунда
else T = (A+key[7-(i%8)]) % 0x100000000;
}
unsigned int Fragments[8] = // Разбиение на 4-битные фрагменты
{
(T & 0xF0000000)>>28,
(T & 0xF000000)>>24,
(T & 0xF00000)>>20,
(T & 0xF0000)>>16,
(T & 0xF000)>>12,
(T & 0xF00)>> 8,
(T & 0xF0)>> 4,
(T & 0xF)
};
for(int j = 0; j<8; j++)
{
Fragments[j] = Sbox[j][Fragments[j]-1]; // Пропуск фрагментов через Sbox'ы
}
T = (Fragments[0]<<28) + // Сборка фрагментов обратно в 32-битный подблок
(Fragments[1]<<24) +
(Fragments[2]<<20) +
(Fragments[3]<<16) +
(Fragments[4]<<12) +
(Fragments[5]<< 8) +
(Fragments[6]<< 4) +
Fragments[7];
T = (T<<11)|(T>>21); // Циклическое смещение влево на 11 бит
T ^= B; // XOR с B
if(i != 31)
{
B = A; // Перестановка подблоков 1-31 и 32 циклов
A = T;
}
else
{
B = T;
}
} //--Коненц 32 раундов---------------------------
A = reverse_block(A); // Реверсирование блоков с последующим реверсом бит
B = reverse_block(B); // Реверсирование блоков с последующим реверсом бит
//--Вывод A и B в файл--------------------------
fwrite(&A, 4, 1, g);
fwrite(&B, 4, 1, g);
} // Конец файла
fclose(f);
fclose(g);
}
int _tmain(int argc, _TCHAR* argv[])
{
GOST(CRYPT);
GOST(DECRYPT);
return 0;
}
for(int j=0;j<8;j++) //Заполняем блок битами символов (число символов N=8)
{
if(n/Pow(2,7-j)>=1)
{
T[8*i+j]=1;
n=n-Pow(2,7-j);
}
else
T[8*i+j]=0;
}
}
}
//Вывод блока Т
fprintf(log,"Tnach ");
for(int i=0;i<64;i++)
fprintf(log,"%d",T[i]);
}
void ZapolnB() //Заполнение блока B
{
//Заполнение и вывод блока В1
fprintf(log,"\nB1 ");
for(int i=0;i<32;i++)
{
B[i]=T[i];
fprintf(log,"%d",B[i]);
}
}
void ZapolnA() //Заполнение блока A
{
//Заполнение и вывод блока A1
fprintf(log,"\nA1 ");
for(int i=0;i<32;i++)
{
A[i]=T[32+i];
fprintf(log,"%d",A[i]);
}
}
void ZapolnK(int *t) //Заполнение и вывод подключа K
{
fprintf(log,"\nK%-5d",*t);
unsigned long x=0;
if (rejim==1) //Если режим шифрования, то
{ //последовательность подключей имеет следующий вид:
if((*t>=25)&&(*t<=32))
x=KEY[7-(*t-1)%8];
else
x=KEY[(*t-1)%8];
}
if (rejim==2) //Если режим шифрования, то
{ //последовательность подключей имеет следующий вид:
if((*t>=1)&&(*t<=8))
x=KEY[(*t-1)%8];
else
x=KEY[7-(*t-1)%8];
}
for(int i=0;i<32;i++) //Переводим значение подключа в массив битов
{
if(x/Pow(2,31-i)>=1)
{
K[i]=1;
x=x-Pow(2,31-i);
}
else
K[i]=0;
fprintf(log,"%d",K[i]); //Вывод подключа
}
}
void Sum232() //Заполнение блока K
{
fprintf(log,"\nSUM32 ");
for(int c=0,i=31;i>=0;i--) //Поразрядное сложение блоков
{
if ((A[i]+K[i]+c)>=2) //Если переполнение, то:
{
SUM32[i]=A[i]+K[i]+c-2;
c=1;
}
else //Иначе:
{
SUM32[i]=A[i]+K[i]+c;
c=0;
}
}
for(int i=0;i<32;i++) //вывод сумматора
fprintf(log,"%d",SUM32[i]);
}
void ZapolnN() //Заполнение накопителя
{
fprintf(log,"\nN ");
for(int i=0;i<8;i++) //В накопителе 8 чисел
{
for(int j=0;j<4;j++) //Преобразуем 4 бита сумматора (начиная с конца, т.е. 4 посл бита, 4 предпосл бита и т.д.) в 10-чное число
if(SUM32[31-4*i-j]==1)
N[i]=N[i]+Pow(2,j);
fprintf(log,"%d ",N[i]); //Выводим накопитель
}
}
void UzliZamen() //Прохождение заполнителя через узлы замен
{
fprintf(log,"%\nN ");
for(int i=0,k;i<8;i++)
{
k=N[i];
N[i]=TABLE[i][k]; //Выход из i-ого узла
fprintf(log,"%d ",N[i]);
}
}
void ZapolnN1() //Преобразование результатов функции UzliZamen() в накопитель N1
{
for(int i=0;i<8;i++) //Все 8 чисел накопителя N
for(int j=0;j<4;j++) //переводим в двоичный вид
{
if(N[i]/Pow(2,3-j)>=1)
{
N1[4*i+j]=1;
N[i]=N[i]-Pow(2,3-j);
}
else
N1[4*i+j]=0;
}
fprintf(log,"%\nN1 ");
for(int i=0;i<32;i++) //вывод выходного накопителя
fprintf(log,"%d",N1[i]);
}
void Sdvig11() //Сдвиг на 11 бит влево. Результат сдвига - результа функции Фейстеля F(Ai,Ki)
{
fprintf(log,"\nF ");
for(int i=0;i<21;i++)
{
F[i]=N1[i+11]; //Сохраняем биты с 12 по 32
fprintf(log,"%d",F[i]);
}
for(int i=0;i<11;i++)
{
F[i+21]=N1[i]; //Сохраняем биты с 1 по 11
fprintf(log,"%d",F[i+21]);
}
}
void XOR(int *t) //Ai+1 = Bi XOR F(Ai,Ki)
{
fprintf(log,"\nA%-5d",*t+1);
for(int i=0;i<32;i++)
{
A[i]=F[i]^B[i]; //Двоичное исключающее "ИЛИ"
fprintf(log,"%d",A[i]);
}
}
void SohrBnext(int *t) //Bi+1 = Ai
{
fprintf(log,"\nB%-5d",*t+1);
for(int i=0;i<32;i++)
{
B[i]=C[i];
fprintf(log,"%d",B[i]);
}
}
void SkleivanieAB() //Склеивание блоков. T=AB
{
fprintf(log,"\nTkon ");
for(int i=0;i<32;i++)
T[i]=A[i];
for(int i=32;i<64;i++)
T[i]=B[i-32];
for(int i=0;i<64;i++)
fprintf(log,"%d",T[i]);
}
void ViviodTexta(int *x) //Преобразование блока T в символы и вывод этих символов в выходной файл (fo)
{
int d;
fprintf(log,"\n\nRezultat: ");
if((*x==blokN-1)&&(nekratno==1)&&(rejim==2)) //Если последний блок, "..." - некратно и режим расшифрования, то
d=FileSize(fi)%8; //выводим первые d=FileSize(fi)%8 символов.
else //Иначе
d=8; //выводим 8 символов
for(int i=0;i
{
n=0;
for(int j=0;j<8;j++) //Преобразование из 8 бит в соответствующий символ
if (T[8*i+j]==1)
n=n+Pow(2,7-j);
ch=n;
fprintf(log,"%c",ch);
fprintf(fo,"%c",ch);
}
fprintf(log,"\n");
}
ПРИЛОЖЕНИЕ
Структурная схема алгоритма
Схема основного шага криптопреобразования алгоритма ГОСТ 28147-89.
Схема цикла шифрования 32-З.
Схема цикла дешифрования 32-Р.
Главное окно программы
UML-диаграмма
. Диаграмма деятельности алгоритма ГОСТ28147-89