Реализация алгоритма шифрования по ГОСТ 28147-89 - C#
Формулировка задачи:
Добрый день! Пытаюсь реализовать все тот же алгоритм шифрования ГОСТ-89. Уже целую неделю долблюсь, и никак не могу понять, в чем моя ошибка. Значит, вкратце о проекте:
- В основе данного алгоритма лежит основной шаг криптопреобразования. Он реализован в структуре
Механизм зашифровки 32-З реализован в классе
Для расшифровки (32-Р) реализован аналогичный класс при запуске шифрования на выходе получим исходный файл. Значит, все преобразования, помимо самого шифра работают корректно. Может, я что-то не так понял в самом алгоритме шифрования?
Надеюсь на вашу помощь)
З.Ы.: Весь проект в прикрепленном файле. В папке Debug есть два файла:
BasicSteep
:using System;
namespace Crypto
{
struct BasicStep
{
uint N1, N2, X;
public BasicStep(ulong dateFragment, uint keyFragment)
{
N1 = (uint)(dateFragment >> 32); //Младшая часть файла
N2 = (uint)((dateFragment << 32) >> 32); //Старшая часть файла
X = keyFragment;
}
public ulong BasicEncrypt()
{
return (FourthAndFifthStep(ThirdStep(SecondStep(FirstStep()))));
}
//Сложение по модулю 2^32 младшей части с фрагментом ключа
private uint FirstStep()
{
return (uint)((X + N1) % (Convert.ToUInt64(Math.Pow(2, 32))));
}
//Использование таблицы замены
private uint SecondStep(uint S)
{
uint newS, S0, S1, S2, S3, S4, S5, S6, S7;
//Разбиваем младшую часть файла на 8 4-х битовых чисел
S0 = S >> 28;
S1 = (S << 4) >> 28;
S2 = (S << 8) >> 28;
S3 = (S << 12) >> 28;
S4 = (S << 16) >> 28;
S5 = (S << 20) >> 28;
S6 = (S << 24) >> 28;
S7 = (S << 28) >> 28;
//Производим замену по таблице замен
S0 = ReplacementTab.Table0[S0];
S1 = ReplacementTab.Table0[0x10 + S1];
S2 = ReplacementTab.Table0[0x20 + S2];
S3 = ReplacementTab.Table0[0x30 + S3];
S4 = ReplacementTab.Table0[0x40 + S4];
S5 = ReplacementTab.Table0[0x50 + S5];
S6 = ReplacementTab.Table0[0x60 + S6];
S7 = ReplacementTab.Table0[0x70 + S7];
//Склеиваем 4-х битовые числа в одно 32-х битовое
newS = S7 + (S6 << 4) + (S5 << 8) + (S4 << 12) + (S3 << 16) +
(S2 << 20) + (S1 << 24) + (S0 << 28);
return newS;
}
//Циклический сдвиг на 11 бит влево
private uint ThirdStep(uint S)
{
return (uint) (S << 11) | (S >> 21);
}
private ulong FourthAndFifthStep(uint S)
{
ulong N;
S = (N2 ^ S); //Сложение по модулю 2 старшего фрагмента данных с полученным из....
//... ThirdStep() числом
//Сдвиг по цепочке
N2 = N1;
N1 = S;
//Склеиваем младший и старший фрагмент в один 64-х битовый блок данных
N = ((ulong)N2) | (((ulong)N1) << 32);
return N;
}
}
}E32
:using System;
namespace Crypto
{
class E32
{
static E32 e32 = null;
byte[] byteFile, byteKey, encrByteFile;
uint[] uintKey;
ulong[] ulongFile, ulNewFile;
private E32() { }
private E32(byte[] file, byte[] key)
{
byteFile = file;
byteKey = key;
//Создание массива из 32-х битовых фрагментов ключа
DatePartition part = new DatePartition(byteKey, DatePartition.FileType.Key);
uintKey = part.GetKey;
//Создание массива из 64-х битовых фрагментов данных
part = new DatePartition(byteFile, DatePartition.FileType.File);
ulongFile = part.GetFile;
ulNewFile = ulongFile;
//Получение зашифрованного фрагмента данных в виде байт-массива encrByteFile[]
ConvertToByte(EncryptFile());
}
//Публичное свойство для получения зашифрованного байт-массива
public byte[] GetEncryptFile
{
get { return encrByteFile; }
}
//Публичный метод для получения единственного экземпляра объекта класса
public static E32 StartE32(byte[] file, byte[] key)
{
if (e32 == null)
e32 = new E32(file, key);
return e32;
}
//Непосредственная реализация 32-З (3 раза К0-К7 и 1 раз К7-К0)
private ulong[] EncryptFile()
{
BasicStep[] K = new BasicStep[8];
ulNewFile[0] = ulongFile[0];
for (int j = 0; j < 3; j++)
{
for (int i = 0; i < K.Length; i++)
{
K[i] = new BasicStep(ulNewFile[0], uintKey[i]);
ulNewFile[0] = K[i].BasicEncrypt();
}
}
for (int i = K.Length - 1; i >= 0; i--)
{
K[i] = new BasicStep(ulNewFile[0], uintKey[i]);
ulNewFile[0] = K[i].BasicEncrypt();
}
return ulNewFile;
}
//Метод для конвертации массива ulong в байт-массив
private void ConvertToByte(ulong[] fl)
{
byte[] newFile = new byte[8];
uint part1, part2;
string str, str1, str2;
string[] arrStr = new string[8];
part1 = (uint)(fl[0] >> 32);
part2 = (uint)((fl[0] << 32) >> 32);
str1 = Convert.ToString(part1, 2);
while (str1.Length < 32)
str1 = "0" + str1;
str2 = Convert.ToString(part2, 2);
while (str2.Length < 32)
str2 = "0" + str2;
str = str1 + str2;
int count = 0;
for (int i = 0; i < str.Length; i++)
{
if ((i % 8 == 0) && (i != 0))
count++;
arrStr[count] += str[i];
}
for (int i = 0; i < arrStr.Length; i++)
{
newFile[i] = Convert.ToByte(arrStr[i], 2);
}
encrByteFile = newFile;
}
}
}D32
, отличается только порядком действий в методе DecryptFile() (1 раз К0-К7 и 3 раза К7-К0). Ошибка скорее всего заключена в самом алгоритме. Как я это понял: Если в методе EncryptFile() оставить только 2 строкиulNewFile[0] = ulongFile[0]; return ulNewFile;
1.txt
- 8-ми байтовый текстовый файл для зашифровки и файлkey
- 256-битовый файл ключа.Решение задачи: «Реализация алгоритма шифрования по ГОСТ 28147-89»
textual
Листинг программы
using System;
namespace Crypto
{
struct BasicStep
{
uint N1, N2, X;
public BasicStep(ulong dateFragment, uint keyFragment)
{
N1 = (uint)(dateFragment >> 32);
N2 = (uint)((dateFragment << 32) >> 32);
X = keyFragment;
}
public ulong BasicEncrypt(bool IsLastStep)
{
return (FourthAndFifthStep(IsLastStep, ThirdStep(SecondStep(FirstStep()))));
}
private uint FirstStep()
{
return (uint)((X + N1) % (Convert.ToUInt64(Math.Pow(2, 32))));
}
private uint SecondStep(uint S)
{
uint newS, S0, S1, S2, S3, S4, S5, S6, S7;
S0 = S >> 28;
S1 = (S << 4) >> 28;
S2 = (S << 8) >> 28;
S3 = (S << 12) >> 28;
S4 = (S << 16) >> 28;
S5 = (S << 20) >> 28;
S6 = (S << 24) >> 28;
S7 = (S << 28) >> 28;
S0 = ReplacementTab.Table0[S0];
S1 = ReplacementTab.Table0[0x10 + S1];
S2 = ReplacementTab.Table0[0x20 + S2];
S3 = ReplacementTab.Table0[0x30 + S3];
S4 = ReplacementTab.Table0[0x40 + S4];
S5 = ReplacementTab.Table0[0x50 + S5];
S6 = ReplacementTab.Table0[0x60 + S6];
S7 = ReplacementTab.Table0[0x70 + S7];
newS = S7 + (S6 << 4) + (S5 << 8) + (S4 << 12) + (S3 << 16) +
(S2 << 20) + (S1 << 24) + (S0 << 28);
return newS;
}
private uint ThirdStep(uint S)
{
return (uint)(S << 11) | (S >> 21);
}
//Теперь принимает в качестве параметра IsLastStep
private ulong FourthAndFifthStep(bool IsLastStep, uint S)
{
ulong N;
S = (S ^ N2);
//Если шаг последний - сдвиг по цепочке не производится
if (!IsLastStep)
{
N2 = N1;
N1 = S;
}
else
N2 = S;
N = ((ulong)N2) | (((ulong)N1) << 32);
return N;
}
}
}