МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ "ЛЬВІВСЬКА ПОЛІТЕХНІКА"
/
Звіт
до Графічно - розрахункової роботи
на тему:
” Розроблення багатопоточної Windows Forms програми
для реалізації алгоритму шифрування RSA”
з курсу:
“Операційні системи”
Варіант 57
Прийняв:
Павельчак А.Г.
Львів – 2013
Мета роботи:
Вивчити принцип функціонування асиметричних криптосистем з відкритими ключами на прикладі RSA, дослідити числові алгоритми, що використовуються у криптографії та реалізувати алгоритмічною мовою С++ алгоритм шифрування RSA.
Завдання
1. Мовою С# розробити окремий клас реалізації алгоритму з відкритим ключем RSA та побудувати Windows Forms програму (рис. 1) для генерування ключів RSA та шифрування/дешифру-вання файлів. Функціонування програми умовно розбити на дві частини: Система RSA – передбачає генерування закритого/відкри-того ключів, шифрування відкритим ключем вибраного в діалого-вому вікні файла, дешифруваня файла, згідно закритого ключа; Злом RSA – передбачає підбір (відновлення) закритого ключа згідно відкритого ключа простим методом перебору та дешиф-рування вказаного файла.
2. Усю функціональну роботу (генерування ключів, шифрування та дешифрування файлів) виконувати в окремих потоках. При виконанні роботи у вторинному потоці передбачати блокування кнопок виклику ( button1.Enabled = false; ) та розблокуван-ня їх після закінчення. По завершенню шифрування чи роз-шифрування файла виводити відповідне інформаційне вікно ( MessageBox.Show ("Шифрування завершено"); ).
/
Теоретична частина
Бінарний алгоритм Евкліда.
Для комп’ютерів операції множення та додавання є набагато простішими, аніж операції ділення та обчислення залишку. Тому звичайна реалізація алгоритму Евкліда є не зовсім ефективною.
При обчисленнях НСД можна використати ряд таких еквівалентних перетворень
НСД (,) =. (2.26)
Зазначимо, що ділення на 2 є простою операцією, оскільки вона рівносильна простому зсуву розрядів у двійковій системі числення. Саме ця властивість і використовується у бінарному алгоритмі.
Бінарний алгоритм Евкліда обчислення НСД (,) для
Код програми:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Threading;
namespace Олег
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public ulong NSD(ulong a, ulong b)
{
ulong nsd;
ulong g = 1;
// якщо a та b парні числа відокремлення степеню двійки з НСД
while (a % 2 == 0 && b % 2 == 0)
{ a = a / 2; b = b / 2; g = 2 * g; }
// тепер a чи b непарне число
while (a != 0)
{
while (a % 2 == 0) a = a / 2;
while (b % 2 == 0) b = b / 2;
//тепер обидва числа a та b непарні
if (a >= b) a = (a - b) / 2;
else b = (b - a) / 2;
}
nsd =g * b;
return nsd;
}
public ulong StepMOD(ulong a, int x, ulong n)
{
int w = 3;
int worker, n_x;
int base1 = 1; // основа системи числення для вікна w
for (int i = 0; i < w; i++)
base1 *= 2;
ulong[] A = new ulong[base1];
A[0] = 1; // обчислення таблиці значень
for (int i = 1; i < base1; i++)
A[i] = (A[i - 1] * a) % n;
// визначення к-сті розрядів числа x за основою base
worker = x; n_x = 1;
while (worker > base1 - 1)
{ worker = worker / base1; n_x++; }
// перевід з 10 системи числення у систему з основою base
int[] x_base = new int[n_x];
for (int i = 0; i < n_x; i++)
{ x_base[i] = x % base1; x /= base1; }
// основний алгоритм
ulong m = 1;
for (int i = n_x - 1; i >= 0; i--)
{
for (int j = 0; j < w; j++)
m = (m * m) % n;
int f = x_base[i];
m = (m * A[f]) % n;
}
return m;
}
//public ulong StepMOD(ulong a, int x, ulong n)
// {
// ulong tmp;
// if (x == 1) return a % n;
// if ((x & 1) != 0)
// {
// tmp = StepMOD(a, x >> 1, n);
// tmp = (tmp * tmp) % n;
// return (tmp * a) % n;
// }
// else
// {
// tmp = StepMOD(a, x >> 1, n);
// return (tmp * tmp) % n;
// }
// }
public long Inverse(long a, long n)
{
long u, v, A, B, C, D, g, c, k, n1, nsd;
g = 1; n1 = (long)n;
// якщо a та b парні числа -> відокремлення степеню двійки з НСД
while ((a & 1) == 0 && (n & 1) == 0)
{ a = a >> 1; n = n >> 1; g = g << 1; }
// тепер лише a чи b непарне число
u = (long)a; v = (long)n; A = 1; B = 0; C = 0; D = 1;
do
{
while ((u & 1) == 0) // поки u парне
{
u = u >> 1;
if ((A & 1) == 0 && (B & 1) == 0) { A = A >> 1; B = B >> 1; }
else { A = (A + (long)n) >> 1; B = (B - (long)a) >> 1; }
}
while ((v & 1) == 0) // поки v парне
{
v = v >> 1;
if ((C & 1) == 0 && (D & 1) == 0) { C = C >> 1; D = D >> 1; }
else { C = (C + (long)n) >> 1; D = (D - (long)a) >> 1; }
}
if (u >= v) { u = u - v; A = A - C; B = B - D; }
else { v = v - u; C = C - A; D = D - B; }
}
while (u > 0);
nsd = g * v; c = C; k = D;
if (c < 0) c += n1;
return c;
// вихід: числа nsd, c, k
// с – обернене значення за модулем n
}
public ulong generator(Random autoRand)
{
ulong p , mask; // генероване просте число
int t = 110; // t – кількість повторів тесту на простоту
bool BOOL;
//Random autoRand = new Random(); // генератор випадкових чисел
do
{
BOOL = false;
p = (ulong)autoRand.Next(1, 65535); // генерування наступного випадк.числа
mask = 1; p = p | 1; p = p | (mask << 15); // встановл. ст. та мол. бітів в "1"
for (int i = 3; i < 2000; i += 2) //перевірка діленням на прості числа
if ((int)p % i == 0) { BOOL = true; break; }
if (!BOOL) BOOL = Test(p, t); // ф-ція Test – тест на простоту числа p
}
while (BOOL);
return p;
}
public bool Test(ulong p, int t) // p – вхідне число, t – к-сть тестів
{
Random autoRand = new Random(); // ств. генер-ра випадк. чисел
ulong a, c;
for (int i = 0; i < t; i++)
{
a = (ulong)autoRand.Next(2, (int)(p - 1));
if (NSD(a, p) != 1) return true; // true -- число p складене
// NSD (a, p) – ф-ція знаходження НСД ( , )
c = StepMOD(a, (int)(p - 1) / 2, p); // ф-ція підн-ня до степеню за mod
if (c != 1 && c != (p - 1)) { return true; } // true -- число p складене
}
return false;
}
private delegate void new_delegat();
void butt()
{
button2.Enabled = true;
}
void butt1()
{
button3.Enabled = true;
}
void butt2()
{
button5.Enabled = true;
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
ulong p, q, n, E;
ulong D;
Random autoRand = new Random(); // ств. генератора випадкових чисел
p = generator(autoRand); // генерування простого числа p
q = generator(autoRand); // генерування простого числа q
n = p * q;
do
{
E = (ulong)autoRand.Next(int.MaxValue); // генерування числа E
}
while (NSD(E, (p - 1) *(q - 1)) != 1); // NSD () – ф-ція знаходження НСД
D = ((ulong)Inverse((long)E, (long)((p - 1) * (q - 1)))); // ф-ція обчислення оберненого за mod
// далі виконуємо вивід чисел p, q, n, E, D
// у відповідні їм елементи керування textBox
textBox1.Text = p.ToString();
textBox2.Text = q.ToString();
textBox3.Text = n.ToString();
textBox4.Text = E.ToString();
textBox5.Text = D.ToString();
MessageBox.Show("Генерація ключів завершена");
button1.Enabled = true;
}
private void button2_Click(object sender, EventArgs e)
{
String filename;
byte p;
uint m;
ulong m1, c, n, E;
n = Convert.ToUInt64(textBox3.Text);
E = Convert.ToUInt64(textBox4.Text);
openFileDialog1.ShowDialog(); //викликаємо діалогове вікно вибору файлу
filename = openFileDialog1.FileName; //зчитуємо шлях до файлу
BinaryReader binReader = new BinaryReader(File.Open(filename,
FileMode.Open)); // створюємо об’єкт для бінарного читання з файлу
BinaryWriter binWriter = new BinaryWriter(File.Open(filename + ".rsa",
FileMode.Create)); // створюємо об’єкт для бінарного запису у файл
ThreadPool.QueueUserWorkItem(new WaitCallback(Method1), button2.Enabled = false);
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
try
{
do
{
p = binReader.ReadByte(); // зчитуємо 8-бітний блок даних
m1 = (ulong)(p);
c = StepMOD(m1, (int)E, n); // обчислюємо
m = (uint)(c);
binWriter.Write(m); // запис 32-бітн. зашифр.блоку даних
}
while (1 > 0);
}
catch (Exception ex) { Console.WriteLine(ex); }
binReader.Close(); //закриваємо файл з вх.даними
binWriter.Close();
BeginInvoke(new new_delegat(butt), null);
MessageBox.Show("Шифрування завершене!");
}));
}
private void button3_Click(object sender, EventArgs e)
{
String filename;
byte p;
uint c1;
ulong m, c, n, D;
n = Convert.ToUInt64(textBox3.Text);
D = Convert.ToUInt64(textBox5.Text);
openFileDialog1.ShowDialog();
filename = openFileDialog1.FileName;
BinaryReader binReader = new BinaryReader(File.Open(filename,
FileMode.Open));
BinaryWriter binWriter = new BinaryWriter(File.Open(filename.Replace(".rsa", ""), FileMode.Create));
ThreadPool.QueueUserWorkItem(new WaitCallback(Method1), button3.Enabled = false);
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
try
{
do
{
c1 = binReader.ReadUInt32(); // зчит. 32-бітн.блок шифр. даних
c = (ulong)(c1);
m = StepMOD(c, (int)D, n); // обчислюємо
p = (byte)(m);
binWriter.Write(p); // запис 8-бітного блоку розшифр.даних
}
while (1 > 0);
}
catch (Exception ex) { Console.WriteLine(ex); }
binReader.Close();
binWriter.Close();
BeginInvoke(new new_delegat(butt1), null);
MessageBox.Show("Розшифрування завершене!");
}));
}
private void button4_Click(object sender, EventArgs e)
{
button4.Enabled = false;
ulong E1, n1;
ulong p1, q1, i = 3;
ulong D1;
E1 = Convert.ToUInt64(textBox6.Text);
n1 = Convert.ToUInt64(textBox7.Text);
while (i <= n1)
{
if (n1 % i == 0) break;
i += 2;
}
p1 = i; q1 = n1 / p1;
D1 = (ulong)Inverse((long)E1, (long)(p1 - 1) * (long)(q1 - 1));// ф-ція обчислення оберненого за mod
// далі виконуємо вивід чисел p, q, D
// у відповідні їм елементи керування textBox
textBox8.Text = p1.ToString();
textBox9.Text = q1.ToString();
textBox10.Text = D1.ToString();
MessageBox.Show("Відновлення ключів завершена");
button4.Enabled = true;
}
private void button5_Click(object sender, EventArgs e)
{
String filename;
byte p1;
uint c1;
ulong m1, c, n1, D1;
n1 = Convert.ToUInt64(textBox7.Text);
D1 = Convert.ToUInt64(textBox10.Text);
openFileDialog1.ShowDialog();
filename = openFileDialog1.FileName;
BinaryReader binReader = new BinaryReader(File.Open(filename,
FileMode.Open));
BinaryWriter binWriter = new BinaryWriter(File.Open(filename.Replace(".rsa", ""), FileMode.Create));
//button5.Enabled = false;
ThreadPool.QueueUserWorkItem(new WaitCallback(Method1), button5.Enabled = false);
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
try
{
do
{
c1 = binReader.ReadUInt32(); // зчит. 32-бітн.блок шифр. даних
c = (ulong)(c1);
m1 = StepMOD(c, (int)D1, n1); // обчислюємо
p1 = (byte)(m1);
binWriter.Write(p1); // запис 8-бітного блоку розшифр.даних
}
while (1 > 0);
}
catch (Exception ex) { Console.WriteLine(ex); }
binReader.Close();
binWriter.Close();
BeginInvoke(new new_delegat(butt2), null);
MessageBox.Show("Розшифрування завершене!");
}));
}
static void Method(object ob)
{
Thread.Sleep(1000);
MessageBox.Show("Генерація ключів завершена");
}
static void Method1(object ob)
{
Thread.Sleep(1000);
}
static void Method3(object ob)
{
Thread.Sleep(1000);
MessageBox.Show("Відновлення ключа завершено");
}
}
}
Результат програми:
/
/
Висновок
В даній розрахунковій роботі я розробив програму мовою C# для шифрування та розшифрування файлів з використанням асиметричних криптосистем з відкритими ключами на прикладі RSA. Алгоритми шифрування та розшифрування реалізував з використанням багатопоточності Windows Forms.