Файл: Методы кодирования данных (позволяющие выполнять шифрование).pdf
Добавлен: 06.04.2023
Просмотров: 421
Скачиваний: 3
СОДЕРЖАНИЕ
Теоретические основы шифрования данных
Архивы и форматы архивных файлов
Теория циклических избыточных кодов
Алгоритмы вычисления циклических избыточных кодов
Практическая реализация алгоритмов
Выбор языка и среды разработки
Разработка программного кода для алгоритма CRC-32
Разработка программного кода для алгоритма RSA
Листинг 4. Исходный код методов шифрования и дешифрования
private string encrypt(int symbol, BigInteger keyE, BigInteger keyN)
{
return BigInteger.ModPow(symbol, keyE, keyN).ToString();
}
private int decrypt(int symbol, BigInteger keyD, BigInteger keyN)
{
return (int)(BigInteger.ModPow(symbol, keyD, keyN));
}
private string textEncrypt(string text, BigInteger e, BigInteger n)
{
string eText = "";
foreach (var symbol in text)
eText += encrypt(symbol, e, n) + this.blockSep;
return eText;
}
private string textDecrypt(string text, BigInteger d, BigInteger n)
{
string[] arr = text.Split(this.blockSep);
string dText = "";
foreach (var symbol in arr)
if (symbol != string.Empty)
dText += Convert.ToChar(decrypt(int.Parse(symbol), d, n));
return dText;
}
Для работы с длинными числами здесь используется тип данных BigInteger. Этот целочисленный тип данных отображается на тип System.Numerics.BigInteger библиотеки Microsoft .NET Framework, позволяющий записывать и обрабатывать целые числа практически неограниченной длины. Для данных типа BigInteger реализованы арифметические операции сложения, вычитания, умножения и деления. Операция деления, в отличие от других целочисленных типов данных, возвращает не вещественное значение, а результат целочисленного деления, имеющий тип BigInteger. Метод класса BigInteger.ModPow(p, q, k) возвращает остаток от целочисленного деления на k значения p в степени q.
Функция generatePQ генерирует значения
и
, а также вычисляет соответствующие значения функции Эйлера, открытого и закрытого ключей.
Простые числа выбираются из диапазона (10000, 20000) – генерируется пара чисел, каждое из которых проверяется на простоту при помощи алгоритма Миллера-Рабина с 10 раундами до тех пор, пока оба выбранных числа не окажутся простыми. Исходный код функции представлен в листинге 5.
Листинг 5. Исходный код функции генерации p и q
private void getPrimeNum(Random rnd, out int n1, out int n2)
{
int firstNumber;
int secondNumber;
do
{
firstNumber = rnd.Next(10000, 20000);
secondNumber = rnd.Next(10000, 20000);
}
while (!Utilities.MillerRabin(firstNumber, 10) || !Utilities.MillerRabin(secondNumber, 10));
n1 = firstNumber;
n2 = secondNumber;
}
Набор методов для алгоритма RSA получения открытого и закрытого ключей, описанного в разделе 1, приводится в листинге 6. Функция NOD вычисляет НОД (Наибольший Общий Делитель) для проверки взаимной простоты в методе нахождения числа e. Вызов методов осуществляется внутри функции generatePQ, которая инициализирует поля класса RSA значениями для открытого и закрытого ключей.
Листинг 6. Набор методов для получения открытого и закрытого ключей в соответствии с алгоритмом RSA
// 2. найти модуль
private BigInteger getN(int p, int q)
{
return p * q;
}
// 3. найти значение функции Эйлера fi
private BigInteger getFi(int p, int q)
{
return (p - 1) * (q - 1);
}
// 4. выбрать число е, взаимное простое с fi
private BigInteger getPrime(Random rnd, BigInteger fi)
{
BigInteger e = rnd.Next(1, Math.Abs((int)fi));
do
{
if (NOD(e, fi) == 1)
break;
else e++;
} while (true);
if (e >= fi)
{
e--;
do
{
if (NOD(e, fi) == 1)
break;
else e--;
} while (true);
}
return e;
}
// 5. найти d при помощи расширенного алгоритма Евклида
private BigInteger getD(BigInteger e, BigInteger fi)
{
BigInteger i = fi, v = 0, d = 1;
while (e > 0)
{
BigInteger t = i / e, x = e;
e = i % x;
i = x;
x = d;
d = v - t * x;
v = x;
}
v %= fi;
if (v < 0)
v = (v + fi) % fi;
return v;
}
Полный исходный код программы приведен в приложении 1.
Тестовый пример, приведенный в данном подразделе, можно рассматривать как руководство пользователя. Для запуска программы достаточно запустить файл RSAForm.exe. Программа корректно работает в MS Windows 7/8/10. Установка не требуется.
Пример шифрования при помощи ввода текста в верхнее текстовое и нажатия кнопки «Зашифровать» приведен на рисунке 4.
Рисунок 4 – Шифрование текста с генерацией p и q
При выборе ручного ввода значений
и
программа проверяет числа на простоту, и в случае ошибки выдает сообщение (рисунок 5).
Рисунок 5 – Сообщение об ошибке при попытке ручного ввода чисел
Функции приложения могут быть проверены без ввода секретного ключа. Для этого необходимо, не меняя результат шифрования текста в нижнем текстовом поле, нажать кнопку «Расшифровать» в левой верхней части окна (рисунок 6). Результат представлен на рисунке 7.
Рисунок 6 – Выбор дешифрования только что зашифрованного текста
Рисунок 7 – Результат дешифрования только что зашифрованного текста
На рисунке 8 приведен результат шифрования при помощи значений p и q, заданных вручную.
Рисунок 8 – Шифрование текста при помощи заданных вручную значений p и q
Для дешифрования этого текста необходимо использовать закрытый ключ. Результат такого дешифрования приведен на рисунке 9.
Рисунок 9 – Результат дешифрования при помощи закрытого ключа
ЗАКЛЮЧЕНИЕ
В работе были изучены методы кодирования данных, среди которых подробно рассмотрены сжатие данных и шифрование информации. Получено представление о теории циклических избыточных кодов.
Сжатие и архивация данных являются удобными способами использовать связанные между собой файлы вместе, позволяя при этом значительно сэкономить занимаемое пространство. Однако при работе с различными форматами архивов важно осознавать недостатки производительности и проблемы совместимости, которые могут встречаться в каждом из этих решений. Насколько большое внимание конечные пользователи должны уделять этим деталям, полностью зависит от устройств, на которых они работают.
Сжатие файлов экономит место для хранения и ускоряет передачу данных, но оно также может занять много времени. Сжатие данных требует значительных ресурсов процессора, а сжатие набора данных в несколько терабайт может потребовать огромных вычислительных мощностей.
В ходе выполнения работой было выполнено ознакомление с понятием шифрования с открытым ключом и подробно рассмотрены алгоритмы RSA и Диффи-Хеллмана. Также было выполнено ознакомление с ключевыми понятиями теории циклических избыточных кодов, подробно рассмотрен алгоритм CRC, сформулированы алгоритмы построения таблицы и вычисления контрольной суммы по этому алгоритму. Также было выполнено обоснование выбора языка программирования и среды разработки, итогом которого стала реализация алгоритмов RSA и CRC на языке высокого уровня C# в виде оконных приложений Windows.Forms в среде Visual Studio 2019.
Разработанные программы имеют понятный графический интерфейс, выводят все необходимые пояснения и подсказки, являются законченными и удобными для использования. Таким образом, цели и задачи курсовой работы выполнены в полном объеме.
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
- Аршинов М. Н. Коды и математика / М.: Наука, 1983. – 257 с.
- Буркатовская Ю. Б. Быстродействующие алгоритмы деления полиномов в арифметике по модулю два / Ю. Б. Буркатовская, А. Н. Мальчуков, А. Н. Осокин // Изв. Томск. политехн. ун-та. – 2006. – № 1 (309). – с. 19–24.
- Демидович, Е.М. Основы алгоритмизации и программирования. Учебное пособие / Е. М. Демидович. - 2-е изд., испр. и доп. - СПб. : БХВ - Петербург, 2008. - 440 с.
- Документация по семейству продуктов Visual Studio [Электронный ресурс]. – Режим доступа: https://docs.microsoft.com/ru-ru/visualstudio/?view=vs-2019 – (Дата обращения – 25.04.2020).
- Коробейников А. Г, Ю.А.Гатчин. Математические основы криптологии. Учебное пособие / СПб: СПб ГУ ИТМО, 2004. – 106 с.
- Коутинхо С. Введение в теорию чисел. Алгоритм RSA / М.: Постчаркет, 2001. – 328 с.
- Мыцко Е. А. Особенности программной реализации вычисления контрольной суммы CRC32 на примере PKZIP, WINZIP, ETHERNET / Е. А. Мыцко, А. Н. Мальчуков // Вестн. науки Сибири. – 2011. – № 1 (1). – с. 279–282.
- Олифер В. Г. Компьютерные сети. Принципы, технологии, протоколы / В. Г. Олифер, Н. А. Олифер. ‒ СПб.: Питер, 2008. ‒ 958 с.
- Темников Ф. Е. Теоретические основы информационной техники: учеб. пособие. – 2-е изд., испр. и доп. / Ф. Е. Темников, В. А. Афонин, В. И. Дмитриев. – М.: Энергия, 1979. – 512 с.
- Яковлев В. В. Оценка влияния помех на производительность протоколов канального уровня / В. В. Яковлев, Ф. И. Кушназаров // Изв. Петерб. гос. ун-та путей сообщения. – СПб.: ПГУПС, 2015. – Вып. 1 (42). – с. 133–138.
- Arthur-Durett K. The Weakness Of Winrar Encrypted Archives To Compression Side-channel Attack, Open Access Theses, Purdue University, 2014
- C# docs [Электронный ресурс]. – Режим доступа: https://docs.microsoft.com/ru-ru/dotnet/csharp/ – (Дата обращения – 19.04.2020).
- Halsall F. Data communications, computer networks and open systems / F. Halsall. – Addison-Wesley: Pearson Education, 1996. ‒ 907 р.
- Hamilton J. Creating ZIP Files with ODS, Division of Research, Kaiser Permanente, Oakland, California, Paper 131-2013, SAS Global Forum 2013
- Ross N. W. A Painless guide to CRC error detection algorithms / N. W. Ross. – 16 Lerwick Avenue, Hazelwood Park, 5066. – Australia, 1993. – URL: http://www.ross.net/crc/download/crc_v3.txt (дата обращения: 18.04.2020).
- Systems Engineering and Software Development Life Cycle Framework [Электронный ресурс]. – Режим доступа: http://opensdlc.org/mediawiki/index.php?title=Main_Page – (Дата обращения – 25.04.2020).
- Tar Vs Zip VsGz: Difference And Efficiency [Электронный ресурс] / URL: https://itsfoss.com/category/linux/ (Дата обращения: 22.04.2020)
- WinRAR Download and Support [Электронный ресурс] / URL: http://www.win-rar.com/rarproducts.html (Дата обращения: 24.04.2020)
- ZIP Format Specification [Электронный ресурс] / URL: http://www.pkware.com/documents/casestudies/APPNOTE.TXT (Дата обращения: 23.04.2020)
Приложение 1. Исходные коды программ
Листинг А1. RSA.cs
using System;
using System.Collections.Generic;
using System.Numerics;
namespace RSAForm
{
public class RSA
{
private char blockSep = '*';
private static Random rnd;
private BigInteger e;
private BigInteger d;
private BigInteger n;
public RSA()
{
this.initParams();
}
public RSA(char blockSep)
{
this.blockSep = blockSep;
this.initParams();
}
private void initParams()
{
rnd = new Random();
int p = 0, q = 0;
generatePQ(out p, out q);
}
private void getPrimeNum(Random rnd, out int n1, out int n2)
{
int firstNumber;
int secondNumber;
do
{
firstNumber = rnd.Next(10000, 20000);
secondNumber = rnd.Next(10000, 20000);
}
while (!Utilities.MillerRabin(firstNumber, 10) || !Utilities.MillerRabin(secondNumber, 10));
n1 = firstNumber;
n2 = secondNumber;
}
private BigInteger NOD(BigInteger a, BigInteger b)
{
while (a != 0 && b != 0)
{
if (a > b)
a %= b;
else
b %= a;
}
return a == 0 ? b : a;
}
// 2. найти модуль
private BigInteger getN(int p, int q)
{
return p * q;
}
// 3. найти значение функции Эйлера fi
private BigInteger getFi(int p, int q)
{
return (p - 1) * (q - 1);
}
// 4. выбрать число е, взаимное простое с fi
private BigInteger getPrime(Random rnd, BigInteger fi)
{
BigInteger e = rnd.Next(1, Math.Abs((int)fi));
do
{
if (NOD(e, fi) == 1)
break;
else e++;
} while (true);
if (e >= fi)
{
e--;
do
{
if (NOD(e, fi) == 1)
break;
else e--;
} while (true);
}
return e;
}
// 5. найти d при помощи расширенного алгоритма Евклида
private BigInteger getD(BigInteger e, BigInteger fi)
{
BigInteger i = fi, v = 0, d = 1;
while (e > 0)
{
BigInteger t = i / e, x = e;
e = i % x;
i = x;
x = d;
d = v - t * x;
v = x;
}
v %= fi;
if (v < 0)
v = (v + fi) % fi;
return v;
}
private string encrypt(int symbol, BigInteger keyE, BigInteger keyN)
{
return BigInteger.ModPow(symbol, keyE, keyN).ToString();
}
private int decrypt(int symbol, BigInteger keyD, BigInteger keyN)
{
return (int)(BigInteger.ModPow(symbol, keyD, keyN));
}
private string textEncrypt(string text, BigInteger e, BigInteger n)
{
string eText = "";
foreach (var symbol in text)
eText += encrypt(symbol, e, n) + this.blockSep;
return eText;
}
private string textDecrypt(string text, BigInteger d, BigInteger n)
{
string[] arr = text.Split(this.blockSep);
string dText = "";
foreach (var symbol in arr)
if (symbol != string.Empty)
dText += Convert.ToChar(decrypt(int.Parse(symbol), d, n));
return dText;
}
public string getEncryptedText(string originalText)
{
return textEncrypt(originalText, this.e, this.n);
}
public string getEncryptedText(string originalText, int p, int q)
{
BigInteger fi = getFi(p, q);
this.n = getN(p, q);
this.e = getPrime(rnd, fi);
this.d = getD(e, fi);
Console.WriteLine("d = {0}, n = {1}", this.d.ToString(), this.n.ToString());
return textEncrypt(originalText, this.e, this.n);
}
public string getDecryptedText(string encryptedText)
{
return textDecrypt(encryptedText, this.d, this.n);
}
public string getDecryptedText(string encryptedText, BigInteger d, BigInteger n)
{
this.d = d;
this.n = n;
return textDecrypt(encryptedText, this.d, this.n);
}
public void generatePQ(out int p, out int q)
{
getPrimeNum(rnd, out q, out p);
BigInteger fi = getFi(p, q);
this.n = getN(p, q);
this.e = getPrime(rnd, fi);
this.d = getD(e, fi);
}
}
}
Листинг А2. Utilities.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
namespace RSAForm
{
public class Utilities
{
public static bool MillerRabin(int n, int k)
{
for (int i = 0; i < k; i++) // цикл по количеству раундов
{
// проверка элементарных случаев:
if (n % 2 == 0)
return false;
if (n == 2)
return true;
if (n <= 1)
return false;
// представление n - 1 как 2 ^ s * m
int s = 0;
int m = n - 1;
while (m % 2 == 0)
{
s++;
m = m / 2;
}
// выбор случ. целого числа a в отрезке [2, n − 2]
Random r = new Random();
int a = r.Next(n - 1) + 1;
// поиск mod = a ^ m % n
int temp = m;
long mod = 1;
for (int j = 0; j < temp; j++)
mod = (mod * a) % n;
// вычислить в цикле mod как mod ^ 2 % n
while (temp != n - 1 && mod != 1 && mod != n - 1)
{
mod = (mod * mod) % n;
temp *= 2;
}
// если mod = 1, то составное
// если mod != n - 1, то составное
if (mod != n - 1 && temp % 2 == 0)
return false;
}
return true; // вернуть "вероятно простое"
}
}
}
Листинг А3. Form1.cs
using System;
using System.Windows.Forms;
namespace RSAForm
{
public partial class Form1 : Form
{
RSA rsa;
public Form1()
{
InitializeComponent();
rsa = new RSA();
}
private void TextBox_p_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
private void ButtonEncrypt_Click(object sender, EventArgs e)
{
string plaintext = textBox_plaintext.Text;
int p, q;
if (!generatePQ.Checked)
{
if (!int.TryParse(textBox_p.Text, out p) || !Utilities.MillerRabin(p, 10))
{
MessageBox.Show("Не удалось считать простое число p!", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (!int.TryParse(textBox_q.Text, out q) || !Utilities.MillerRabin(q, 10))
{
MessageBox.Show("Не удалось считать простое число q!", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
textBox_ciphertext.Text = rsa.getEncryptedText(plaintext, p, q);
}
else
{
rsa.generatePQ(out p, out q);
textBox_p.Text = p.ToString();
textBox_q.Text = q.ToString();
textBox_ciphertext.Text = rsa.getEncryptedText(plaintext);
}
sameDecipherButton.Enabled = true;
}
private void ButtonDecipher_Click(object sender, EventArgs e)
{
string cipherText = textBox_ciphertext.Text;
int d, n;
if (!int.TryParse(textBox_d.Text, out d))
{
MessageBox.Show("Не удалось считать число d!", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (!int.TryParse(textBox_n.Text, out n))
{
MessageBox.Show("Не удалось считать число n!", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
textBox_plaintext.Text = rsa.getDecryptedText(cipherText, d, n);
}
private void SameDecipherButton_Click(object sender, EventArgs e)
{
string cipherText = textBox_ciphertext.Text;
textBox_plaintext.Text = rsa.getDecryptedText(cipherText);
sameDecipherButton.Enabled = false;
}
private void TextBox_ciphertext_TextChanged(object sender, EventArgs e)
{
sameDecipherButton.Enabled = false;
}
}
}
Листинг B1. Form1.cs
using System;
using System.Collections.Generic;
using System.Drawing;