using System; using System.Linq; // Используется для Concat, но не в этом файле напрямую // ПЕРЕИМЕНОВАЛИ ПРОСТРАНСТВО ИМЕН! Теперь это LabRab1 namespace LabRab1 { // Имя класса BlockCipher - подходящее public class BlockCipher { const int ROUNDS_COUNT = 12; // Количество раундов сети Фейстеля private readonly byte[] conversionTable = new byte[256]; // Таблица замен S-блока // Конструктор инициализирует таблицу при создании объекта public BlockCipher() { InitializeConversionTable(); } // Инициализация таблицы замен (без изменений) private void InitializeConversionTable() { Console.WriteLine("Initializing BlockCipher conversion table (LabRab1)..."); for (int i = 0; i < 256; i++) { // Формула остается прежней conversionTable[i] = (byte)(((long)i * (i + 1) >> 1) % 256); } Console.WriteLine("Conversion table initialized."); } // Разделение 64-битного блока на L и R (32 бита) (без изменений) private uint[] SplittingInput(ulong input) { uint[] uints = new uint[2]; uints[0] = (uint)(input & 0xFFFFFFFFUL); // r (младшие) uints[1] = (uint)(input >> 32); // l (старшие) return uints; } // Сборка L и R обратно в 64 бита (без изменений) private ulong CombineOutput(uint r, uint l) { return ((ulong)l << 32) | r; // l - старшие, r - младшие } // Метод шифрования блока (без изменений) public ulong Encrypt(ulong input, uint key) { uint[] parts = SplittingInput(input); uint r = parts[0]; uint l = parts[1]; for (int round = 0; round < ROUNDS_COUNT; round++) { uint fResult = F(l, key); // F(L_i-1, K_i) uint r_next = l; // R_i = L_i-1 uint l_next = r ^ fResult;// L_i = R_i-1 ^ F(L_i-1, K_i) r = r_next; l = l_next; } // После цикла l = L_n, r = R_n return CombineOutput(r, l); // Собираем L_n (старшие) и R_n (младшие) } // Метод расшифрования блока (без изменений) public ulong Decrypt(ulong input, uint key) { uint[] parts = SplittingInput(input); uint r = parts[0]; // R_n uint l = parts[1]; // L_n for (int round = 0; round < ROUNDS_COUNT; round++) { // Применяем F к R (т.е. к L_{i-1}) uint fResult = F(r, key); // F(R_i, K_i) -> F(L_{i-1}, K_i) uint l_prev = r; // L_{i-1} = R_i uint r_prev = l ^ fResult;// R_{i-1} = L_i ^ F(R_i, K_i) = L_i ^ F(L_{i-1}, K_i) r = r_prev; l = l_prev; } // После цикла l = L_0, r = R_0 return CombineOutput(r, l); // Собираем L_0 (старшие) и R_0 (младшие) } // Раундовая функция F (без изменений, используем циклический сдвиг влево) private uint F(uint x, uint key) { uint temp = x; temp = SBlock(temp); // Подстановка temp += key; // Сложение с ключом (по модулю 2^32) temp = (temp << 3) | (temp >> (32 - 3)); // Циклический сдвиг влево на 3 temp = SBlock(temp); // Еще подстановка return temp; } // S-блок для раундовой функции (без изменений) private uint SBlock(uint x) { byte[] bytes = BitConverter.GetBytes(x); for (int i = 0; i < bytes.Length; i++) { bytes[i] = conversionTable[bytes[i]]; // Замена каждого байта по таблице } return BitConverter.ToUInt32(bytes, 0); // Сборка обратно в uint } } }