В данной статье рассмотрим шифр Виженера. Будет описан алгоритм и написана программа на языке C#, реализующая классический шифр Виженера и шифрование гаммированием.
Шифр Виженера. Описание алгоритма
Шифрование методом Виженера производится по формуле:
где ci – символ закодированного сообщения, pi – символ исходного сообщения, ki – символ ключа, N – мощность алфавита (количество символов в алфавите).
Символы ключа накладываются на шифруемое сообщение циклически. Например, пусть исходное сообщение: программирование на c#, а ключ = vscode, тогда на данное сообщение ключ наложиться следующим образом:
Расшифровка методом Виженера производится по формуле:
При шифровании гаммированием в качестве ключа используется последовательность символов сгенерированная с помощью генератора псевдослучайных чисел и по длине равная исходному сообщению. Псевдослучайные числа генерируются на основе заданного (всегда одинакового) начального параметра, поэтому последовательность во всех случаях получается идентичной.
Шифр Виженера. Реализация
Пусть алфавит задан в виде массива символов:
1 2 3 4 5 |
char[] characters = new char[] { 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ъ', 'Э', 'Ю', 'Я', ' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' }; |
Тогда мощность алфавита будет равна:
1 |
N = characters.Length; |
Приведем реализацию метода на языке C#, шифрующего строку методом Виженера.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
//зашифровать private string Encode(string input, string keyword) { input = input.ToUpper(); keyword = keyword.ToUpper(); string result = ""; int keyword_index = 0; foreach (char symbol in input) { int c = (Array.IndexOf(characters, symbol) + Array.IndexOf(characters, keyword[keyword_index])) % N; result += characters[c]; keyword_index++; if ((keyword_index + 1) == keyword.Length) keyword_index = 0; } return result; } |
На вход поступает строка, которую нужно зашифровать (input) и ключ (keyword).
Теперь приведем реализацию метода, расшифровывающего строку.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
//расшифровать private string Decode(string input, string keyword) { input = input.ToUpper(); keyword = keyword.ToUpper(); string result = ""; int keyword_index = 0; foreach (char symbol in input) { int p = (Array.IndexOf(characters, symbol) + N - Array.IndexOf(characters, keyword[keyword_index])) % N; result += characters[p]; keyword_index++; if ((keyword_index + 1) == keyword.Length) keyword_index = 0; } return result; } |
Кроме того, для гаммирования понадобится генерирование псевдослучайного ключа. Вот метод, который делает это:
1 2 3 4 5 6 7 8 9 10 11 |
private string Generate_Pseudorandom_KeyWord(int length, int startSeed) { Random rand = new Random(startSeed); string result = ""; for (int i = 0; i < length; i++) result += characters[rand.Next(0, characters.Length)]; return result; } |
length — нужная длина ключа. startSeed — число, которым инициализируется генератор случайных чисел. Это число должно быть всегда одинаковым, таким образом и ключ будет всегда один и тот же.
Программа имеет следующий интерфейс:
Код кнопки «Зашифровать» приведен ниже.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
//зашифровать private void buttonEncrypt_Click(object sender, EventArgs e) { if (radioButtonGamma.Checked) { string s; StreamReader sr = new StreamReader("in.txt"); StreamWriter sw = new StreamWriter("out.txt"); while (!sr.EndOfStream) { s = sr.ReadLine(); sw.WriteLine(Encode(s, Generate_Pseudorandom_KeyWord(s.Length, 100))); } sr.Close(); sw.Close(); } else { if (textBoxKeyWord.Text.Length > 0) { string s; StreamReader sr = new StreamReader("in.txt"); StreamWriter sw = new StreamWriter("out.txt"); while (!sr.EndOfStream) { s = sr.ReadLine(); sw.WriteLine(Encode(s, textBoxKeyWord.Text)); } sr.Close(); sw.Close(); } else MessageBox.Show("Введите ключевое слово!"); } } |
Происходит чтение данных из файла in.txt, выполняется шифрование (в зависимости от выбранного radioButton) и запись результата в файл out.txt.
Код кнопки «Расшифровать» приводится далее.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
//расшифровать private void buttonDecipher_Click(object sender, EventArgs e) { if (radioButtonGamma.Checked) { string s; StreamReader sr = new StreamReader("in.txt"); StreamWriter sw = new StreamWriter("out.txt"); while (!sr.EndOfStream) { s = sr.ReadLine(); sw.WriteLine(Decode(s, Generate_Pseudorandom_KeyWord(s.Length, 100))); } sr.Close(); sw.Close(); } else { if (textBoxKeyWord.Text.Length > 0) { string s; StreamReader sr = new StreamReader("in.txt"); StreamWriter sw = new StreamWriter("out.txt"); while (!sr.EndOfStream) { s = sr.ReadLine(); sw.WriteLine(Decode(s, textBoxKeyWord.Text)); } sr.Close(); sw.Close(); } else MessageBox.Show("Введите ключевое слово!"); } } |
Демонстрация работы программы (шифрование и расшифровка данных методом Виженера) приведена на скриншоте ниже.
Скачать исходник программы, рассмотренной в данной статье, можно, нажав на кнопку.
Скачать исходник
Поделиться в соц. сетях:
без кодировки вместо букв — нули
//зашифровать
private void buttonEncrypt_Click(object sender, EventArgs e)
{
if (radioButtonGamma.Checked)
{
string s;
StreamReader sr = new StreamReader(«in.txt»,Encoding.GetEncoding(1251));
StreamWriter sw = new StreamWriter («out.txt»);
далее по тексту.
Так происходит, когда входной файл «in.txt» создается в Блокноте. По умолчанию Блокнот записывает файл в кодировке ANSI, поэтому, при чтении файла, в StreamReader нужно её указать явно.
Если создать входной файл в кодировке UTF-8 без BOM (например, с помощью программы Notepad++), то указывать ничего не потребуется.
спасибо,понятно
Объясните пожалуйста как происходит действие шифрования. В строку ключа я ввожу слово, но ничего не происходит.
Исходный текст для шифрования должен быть в текстовом файле. Результат также заносится в текстовый файл.
Спасибо)
При шифровании с ключом алфавит в процессе шифрования сдвигается, как я понимаю, на 1 символ. А как сделать сдвиг на сколько я хочу?
Не на один, а на число равное номеру символа в алфавите из ключа, накладываемого на шифруемый символ.
а как можно сделать чтобы можно было выбирать файл для записи и считывания? т.е. вместо in и out выбрать свои файлы?
Посмотрите здесь и сделайте подобно: https://vscode.ru/prog-lessons/kak-zagruzit-kartinku-v-picturebox.html