МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”
Лабораторна робота №5
з дисципліни " Захист інформації в комп’ютерних системах "
Львів – 2012
Тема: Симетричні блокові шифри на основі мережі Фейстеля
Мета: ознайомитися з методом побудови алгоритмів симетричного блокового шифрування на прикладі мережі Фейстеля.
Теоретичні відомості
Мережа Фе́йстеля (конструкція Фейстеля) — один з методів побудови блокових шифрів. Мережа представляє із себе певну ітеровану структуру, що називається коміркою Фейстеля. При переході від однієї комірки до іншої міняється ключ, причому вибір ключа залежить від конкретного алгоритму. Операції шифрування та дешифрування на кожному етапі дуже прості, і при певній доробці збігаються, вимагаючи тільки зворотного порядку використовуваних ключів. Шифрування за допомогою даної конструкції легко реалізуються як на програмному рівні, так і на апаратному, що забезпечує широкі можливості застосування. Більшість сучасних блокових шифрів використовують мережу Фейстеля як основу. Альтернативою мережі Фейстеля є підстановочно-перестановочна мережа
Конструкція блокового шифру на основі мереж Фейстеля
Розглянемо випадок, коли ми хочемо зашифрувати деяку інформацію, представлену у двійковому вигляді в комп'ютерній пам'яті (наприклад, файл) або електроніці, як послідовність нулів й одиниць.
Вся інформація розбивається на блоки фіксованої довжини. У випадку, якщо довжина вхідного блоку менше, ніж розмір, що шифрується заданим алгоритмом, то блок подовжується яким-небудь способом. Як правило довжина блоку є ступенем двійки, наприклад: 64 біта, 128 біт. Далі будемо розглядати операції, що відбуваються тільки з одним блоком, тому що з іншими в процесі шифрування виконуються ті ж самі операції.
Обраний блок ділиться на два рівних подблока — «лівий» (L0) і «правий» (R0).
«Лівий подблок» L0 видозмінюється функцією f(L0,K0) залежно від раундового ключа K0, після чого він додається по модулі 2 з «правим підблоком» R0.
Результат додавання присвоюється новому лівому підблоку L1, що буде половиною вхідних даних для наступного раунду, а «лівий подблок» L0 присвоюється без змін новому правому підблоку1 (див. схему), що буде іншою половиною.
Після чого операція повторюється N-1 раз, при цьому при переході від одного етапу до іншого міняються раундові ключі (K0 на K1 і т.д.) за яким-небудь математичним правилом, де N — кількість раундів у заданому алгоритмі. Розшифрування інформації відбувається так само, як і шифрування, з тією лише відмінністю, що ключі йдуть у зворотному порядку, тобто не від першого до N-ному, а від N-го до першого.
Шифрування
Розшифрування
Виконання роботи
Рис. 1. Вікно програми.
Потрібно вибрати файл і ввести розмір блоку, кількість раундів і ключ (рис. 2).
Рис. 2. Шифрування повідомлення.
Для розшифрування потрібно ввести ті ж самі дані і натиснути розшифрувати
Рис. 2. Розшифрування повідомлення.
Текст програми
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using System.Diagnostics;
namespace lab5_ZI
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
StreamReader reader = new StreamReader(textBox1.Text);
string file = reader.ReadToEnd();
byte[] b_file = Encoding.Default.GetBytes(file);
reader.Close();
int block_size=0;
try
{
block_size = int.Parse(textBox3.Text);
}
catch {
MessageBox.Show("Неправельно заданий розмір блоку");
return;
}
CBlocks blocks = new CBlocks(block_size, b_file.Length * 8);
blocks.Partition(b_file);
CFeistel feistel = new CFeistel();
byte[] Key = null;
switch (textBox3.Text)
{
case "8":
try
{
byte temp = byte.Parse(textBox7.Text);
Key = new[] { temp };
}
catch {
MessageBox.Show("Введений завеликий ключ.");
return;
}
break;
case "16":
Key = BitConverter.GetBytes(short.Parse(textBox7.Text));
break;
case "32":
Key = BitConverter.GetBytes(int.Parse(textBox7.Text));
break;
case "64":
Key = BitConverter.GetBytes(Int64.Parse(textBox7.Text));
break;
}
BitArray b_key = new BitArray(Key);
int Repeat = int.Parse(textBox5.Text);
for (int i = 0; i < blocks.Count_Blocks; i++)
{
BitArray[] result = feistel.Crypt(blocks.Left(i), blocks.Right(i), b_key, Repeat);
blocks.SetPairBlocks(i, result);
}
textBox2.Text = textBox1.Text.Insert(textBox1.Text.LastIndexOf('.'),"_crypt");
StreamWriter writer = new StreamWriter(textBox2.Text);
writer.Write(blocks.BlocksToString());
writer.Flush();
writer.Close();
}
private void button1_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog();
}
private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
{
textBox1.Text = openFileDialog1.FileName;
}
private void openFileDialog2_FileOk(object sender, CancelEventArgs e)
{
textBox2.Text = openFileDialog2.FileName;
}
private void button4_Click(object sender, EventArgs e)
{
openFileDialog2.ShowDialog();
}
private void button5_Click(object sender, EventArgs e)
{
Process.Start(textBox1.Text);
}
private void button6_Click(object sender, EventArgs e)
{
Process.Start(textBox2.Text);
}
private void button3_Click(object sender, EventArgs e)
{
StreamReader reader = new StreamReader(textBox2.Text);
string file = reader.ReadToEnd();
byte[] b_file = Encoding.Default.GetBytes(file);
reader.Close();
int block_size = 0;
try
{
block_size = int.Parse(textBox4.Text);
}
catch
{
MessageBox.Show("Неправельно заданий розмір блоку");
return;
}
CBlocks blocks = new CBlocks(block_size, b_file.Length * 8);
blocks.Partition(b_file);
CFeistel feistel = new CFeistel();
byte[] Key = null;
switch (textBox4.Text)
{
case "8":
try
{
byte temp = byte.Parse(textBox8.Text);
Key = new[] { temp };
}
catch
{
MessageBox.Show("Введений завеликий ключ.");
return;
}
break;
case "16":
Key = BitConverter.GetBytes(short.Parse(textBox8.Text));
break;
case "32":
Key = BitConverter.GetBytes(int.Parse(textBox8.Text));
break;
case "64":
Key = BitConverter.GetBytes(Int64.Parse(textBox8.Text));
break;
}
BitArray b_key = new BitArray(Key);
int Repeat = int.Parse(textBox6.Text);
for (int i = 0; i < blocks.Count_Blocks; i++)
{
BitArray[] result = feistel.EnCrypt(blocks.Left(i), blocks.Right(i), b_key, Repeat);
blocks.SetPairBlocks(i, result);
}
textBox1.Text = textBox2.Text.Insert(textBox2.Text.LastIndexOf('.'), "_enCrypt");
StreamWriter writer = new StreamWriter(textBox1.Text);
StreamReader r = new StreamReader(textBox2.Text.Remove(textBox2.Text.LastIndexOf("_")) + ".txt");
writer.Write(r.ReadToEnd());
writer.Flush();
writer.Close();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Windows.Forms;
namespace lab5_ZI
{
class CFeistel
{
BitArray Left;
BitArray Right;
public BitArray[] Crypt(BitArray left, BitArray right, BitArray key, int Repeat)
{
Left = left;
Right = right;
for (int i = 0; i < Repeat; i++)
{
BitArray temp = new BitArray(Left);
Left = f(Left, key).Xor(Right);
Right = temp;
//MessageBox.Show(BlocksToString(key));
key = Change_key(key);
}
BitArray[] result = new BitArray[2];
result[0] = Left;
result[1] = Right;
return result;
}
BitArray f(BitArray left, BitArray key)
{
int k = left.Count / 8;
BitArray temp = new BitArray(left.Count);
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < k; j++)
{
switch (i)
{
case 0:
temp[5 + j * 8] = left[i + j * 8];
break;
case 1:
temp[2 + j * 8] = left[i + j * 8];
break;
case 2:
temp[7 + j * 8] = left[i + j * 8];
break;
case 3:
temp[1 + j * 8] = left[i + j * 8];
break;
case 4:
temp[6 + j * 8] = left[i + j * 8];
break;
case 5:
temp[0 + j * 8] = left[i + j * 8];
break;
case 6:
temp[4 + j * 8] = left[i + j * 8];
break;
case 7:
temp[3 + j * 8] = left[i + j * 8];
break;
}
}
}
for (int i = 0; i < left.Count; i++)
{
left[i] = temp[i];
}
left = left.Xor(key);
return left;
}
BitArray Change_key(BitArray key)
{
int Step = 5;
BitArray temp = new BitArray(key.Count);
for (int i = 0; i < key.Count; i++)
{
temp[i] = key[(i - Step) < 0 ? key.Count + (i - Step) : (i - Step)];
}
return temp;
}
BitArray Change_key_(BitArray key)
{
int Step = 5;
BitArray temp = new BitArray(key.Count);
for (int i = 0; i < key.Count; i++)
{
temp[i] = key[(i + Step) % key.Length];
}
return temp;
}
public BitArray[] EnCrypt(BitArray left, BitArray right, BitArray key, int Repeat)
{
Left = left;
Right = right;
for (int i = 0; i < Repeat-1; i++)
{
key = Change_key(key);
}
for (int i = 0; i < Repeat; i++)
{
BitArray temp = new BitArray(Left);
Left = f(Left, key).Xor(Right);
Right = temp;
key = Change_key_(key);
}
BitArray[] result = new BitArray[2];
result[0] = Left;
result[1] = Right;
return result;
}
public string BlocksToString(BitArray bits)
{
string result = "";
byte[] b = new byte[bits.Count / 8];
bits.CopyTo(b, 0);
result += Encoding.Default.GetString(b);
return result;
}
public byte[] BitToInt(BitArray bits)
{
byte[] b = new byte[bits.Count / 8];
bits.CopyTo(b, 0);
return b;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Windows.Forms;
namespace lab5_ZI
{
class CBlocks
{
int BLOCK_SIZE;
int N_BLOCKS;
BitArray[] lefts;
BitArray[] rights;
public CBlocks(int block_size, int f_size)
{
BLOCK_SIZE = block_size;
N_BLOCKS = (f_size % (block_size * 2) == 0) ? f_size / (block_size * 2) : f_size / (block_size * 2) + 1;
lefts = new BitArray[N_BLOCKS];
rights = new BitArray[N_BLOCKS];
}
public void Partition(byte[] file)
{
int j = 0;
int k = BLOCK_SIZE / 8;
byte[] temp = new byte[k];
for (int i = 0; i < file.Length; )
{
for (int l = 0; l < k; l++)
{
if (i < file.Length)
temp[l] = file[i++];
}
lefts[j] = new BitArray(temp);
for (int l = 0; l < k; l++)
{
if (i<file.Length)
temp[l] = file[i++];
}
rights[j] = new BitArray(temp);
j++;
}
}
public BitArray Left(int index)
{
if (index < lefts.Length)
{
return lefts[index];
}
else
{
return null;
}
}
public BitArray Right(int index)
{
if (index < rights.Length)
{
return rights[index];
}
else
{
return null;
}
}
public int Count_Blocks
{
get { return N_BLOCKS; }
}
public void SetPairBlocks(int index, BitArray[] blocks)
{
lefts[index] = blocks[0];
rights[index] = blocks[1];
}
byte[] BitArrayToBytes(BitArray bitArray)
{
byte[] b = new byte[BLOCK_SIZE/8];
bitArray.CopyTo(b, 0);
return b;
}
public string BlocksToString()
{
string result = "";
for (int i = 0; i < lefts.Length; i++)
{
byte[] b = new byte[BLOCK_SIZE / 8];
lefts[i].CopyTo(b, 0);
result += Encoding.Default.GetString(b);
rights[i].CopyTo(b, 0);
result += Encoding.Default.GetString(b);
}
return result;
}
}
}
Висновок: я ознайомився з методом побудови алгоритмів симетричного блокового шифрування на прикладі мережі Фейстеля.