Разработка Java-приложения для шифрования информации методами Цезаря и Виженера
Введение
Каждый день люди отправляют тонну информации друг другу, будь то текст, картинки, "кружочки" или голосовые сообщения. Но часто ли вы задумывались о том, каким образом эти данные остаются доступными только адресату? В современном мире защита информации становится не задачей, а необходимостью.
Представим такую ситуацию: вы снимаете видео вашей кошки, которая научилась открывать двери лапкой. Вы отправляете это видео своему другу, но по пути оно попадает в чужие руки. Казалось бы - ну, кошка и кошка, пусть все знают, какой у меня пушистик. Но что, если вместо кошки вы случайно отправите важный конфиденциальный документ?
Чтобы не попасть в неловкие ситуации и сохранить конфиденциальность, нужно знать, как защищаются данные. Сегодня мы рассмотрим не самые новые, но эффективные алгоритмы шифрования: метод Цезаря и метод Виженера. А также рассмотрим приложение, которое я написал на языке программирования Java в ходе выполнения лабораторных работ по предмету "Методы и средства защиты информации".
Немного истории (и теории)
Шифр Цезаря - один из старейших алгоритмов шифрования. Его использовал сам Гай Юлий Цезарь (удивлены?) для секретной переписки с полководцами перед предстоящими сражениями. Суть шифра до невозможности прост: каждый символ в исходном тексте заменяется на другой, стоящий от него в алфавите на несколько позиций слева/справа. Так, например, при сдвиге вправо на "3" буква "А" превращается в "Г", "Б" - в "Д" и так далее (см. Рисунок 1).

Рисунок 1 - Алгоритм шифрования методом Цезаря
Шифр Виженера появился значительно позже, в XVI веке и долгое время считался "невзламываемым". В свое время, метод являлся прорывом в области криптографии. В отличие от шифра Цезаря, в шифре Виженера каждая буква в исходном тексте сдвигается на переменное количество символов. Величина сдвига каждой буквы определяется ключом - любым словом или фразой, которую должен знать только абонент и адресат. Например, если зашифровать слово "Собака" с помощью ключа "Кошка", получится непонятное "эюъллл" (см. Рисунок 2).

Рисунок 2 - Алгоритм шифрования методом Виженера
Идея
Всю эту полезную информацию я узнал в ходе изучения предмета "Методы и средства защиты информации" в моем ВУЗе. Неподдельным интересом стало то, что способы шифрования информации с самых древних лет практически не изменились, и всё сводится к простому "текст - кодирование - декодирование". Естественно, современные алгоритмы (например, RSA-256) на основе компьютерных вычислений и генерации псевдослучайных чисел и рядом не стоят с шифрами Цезаря и Виженера. Древние римляне не умели генерировать случайные числа на ПК, знаете ли. Но для погружения в области криптографии и шифрования необходимо знать, любить и уважать древнейшие алгоритмы.
Открывая лабораторную работу, увидел заветное "Разработать алгоритм шифрования с применением полученных знаний по теме Тайнопись". Тут-то и пригодились теоретические знания, и начался брейншторм (по-русски - "шевеление мозгами"). Первоначально, думал над консольным интерфейсом, но захотелось навести суеты красоты и сделать полноценный интерфейс с возможностью ввода пользователем всей необходимой информации для шифрования. Ну и куда же без ввода-вывода из файла!
Выбор языка программирования
Начал думать, какой язык выбрать. В итоге, остановился на Java - модный, стильный, молодёжный, так еще и объектно-ориентированный (для справки - создан в 1995 году компанией Sun Microsystems под руководством Джеймса Гослинга. Не того Гослинга, о котором вы подумали).
Язык Java представлен обширной библиотекой классов, и тут по-настоящему можно разгуляться: тут сразу и работа со строками, и файловый ввод-вывод, и графическое взаимодействие. А еще, у Java есть замечательная вещь под названием кроссплатформенность. То есть, приложение сможет запустить кто угодно и на чём угодно, главное иметь на ПК предустановленный JVM (прим. Java Virtual Machine, Виртуальная машина Java). Насчет JVM переживать не стоит - каждый, кто хоть раз играл в Майнкрафт, уже имеет на компьютере JVM. Не благодарите.
С языком определился, осталось определиться с графическим интерфейсом. И тут на помощь пришла встроенная библиотека Swing. В данной библиотеке представлен широкий спектр возможностей: создание форм, переключателей, кнопок, полей ввода. Особенно заманчивым является то, что в процессе написания логики обращается минимум внимания на установку сторонних зависимостей.
План действий
Театр начинается с вешалки, а разработка приложения - с плана:
- Необходимо создать алфавит, по которому будет шифроваться исходное сообщение. Такой алфавит должны иметь отправитель и адресат, чтобы правильно расшифровать данные.
- Создать графический интерфейс, понятный для пользователя.
- Создать методы для шифрования, расшифровки, записи в файл/из файла сообщений.
Алфавит приложения
Алфавит не ограничивается только русскими буквами. Если мы говорим про электронное письмо, то пробел, переход на следующую строку, кавычки и знаки препинания тоже являются символами. Я принял решение ограничиться русскими буквами вместе со знаками препинания и специальными операторами. Алфавит был сделан в виде массива символов и представлен ниже. Всего 115 символов.
public static char[] createAlphabet()
{
char[] alphabet = new char[115];
alphabet[0] = 'а';
alphabet[1] = 'б';
alphabet[2] = 'в';
alphabet[3] = 'г';
alphabet[4] = 'д';
alphabet[5] = 'е';
alphabet[6] = 'ё';
alphabet[7] = 'ж';
alphabet[8] = 'з';
alphabet[9] = 'и';
alphabet[10] = 'й';
alphabet[11] = 'к';
alphabet[12] = 'л';
alphabet[13] = 'м';
alphabet[14] = 'н';
alphabet[15] = 'о';
alphabet[16] = 'п';
alphabet[17] = 'р';
alphabet[18] = 'с';
alphabet[19] = 'т';
alphabet[20] = 'у';
alphabet[21] = 'ф';
alphabet[22] = 'х';
alphabet[23] = 'ц';
alphabet[24] = 'ч';
alphabet[25] = 'ш';
alphabet[26] = 'щ';
alphabet[27] = 'ъ';
alphabet[28] = 'ы';
alphabet[29] = 'ь';
alphabet[30] = 'э';
alphabet[31] = 'ю';
alphabet[32] = 'я';
alphabet[33] = 'А';
alphabet[34] = 'Б';
alphabet[35] = 'В';
alphabet[36] = 'Г';
alphabet[37] = 'Д';
alphabet[38] = 'Е';
alphabet[39] = 'Ё';
alphabet[40] = 'Ж';
alphabet[41] = 'З';
alphabet[42] = 'И';
alphabet[43] = 'Й';
alphabet[44] = 'К';
alphabet[45] = 'Л';
alphabet[46] = 'М';
alphabet[47] = 'Н';
alphabet[48] = 'О';
alphabet[49] = 'П';
alphabet[50] = 'Р';
alphabet[51] = 'С';
alphabet[52] = 'Т';
alphabet[53] = 'У';
alphabet[54] = 'Ф';
alphabet[55] = 'Х';
alphabet[56] = 'Ц';
alphabet[57] = 'Ч';
alphabet[58] = 'Ш';
alphabet[59] = 'Щ';
alphabet[60] = 'Ъ';
alphabet[61] = 'Ы';
alphabet[62] = 'Ь';
alphabet[63] = 'Э';
alphabet[64] = 'Ю';
alphabet[65] = 'Я';
alphabet[66] = '0';
alphabet[67] = '1';
alphabet[68] = '2';
alphabet[69] = '3';
alphabet[70] = '4';
alphabet[71] = '5';
alphabet[72] = '6';
alphabet[73] = '7';
alphabet[74] = '8';
alphabet[75] = '9';
alphabet[76] = ' ';
alphabet[77] = '!';
alphabet[78] = '"';
alphabet[79] = '#';
alphabet[80] = '$';
alphabet[81] = '%';
alphabet[82] = '&';
alphabet[83] = '\'';
alphabet[84] = '(';
alphabet[85] = ')';
alphabet[86] = '*';
alphabet[87] = '+';
alphabet[88] = ',';
alphabet[89] = '-';
alphabet[90] = '.';
alphabet[91] = '/';
alphabet[92] = ':';
alphabet[93] = ';';
alphabet[94] = '<';
alphabet[95] = '=';
alphabet[96] = '>';
alphabet[97] = '?';
alphabet[98] = '@';
alphabet[99] = '[';
alphabet[100] = '\\';
alphabet[101] = ']';
alphabet[102] = '^';
alphabet[103] = '_';
alphabet[104] = '`';
alphabet[105] = '{';
alphabet[106] = '|';
alphabet[107] = '}';
alphabet[108] = '~';
alphabet[109] = '№';
alphabet[110] = '\n';
alphabet[111] = '«';
alphabet[112] = '»';
alphabet[113] = '—';
alphabet[114] = '…';
return alphabet;
}
Графический интерфейс
Главное окно приложения построено на основе класса JFrame. С помощью менеджера компоновки BorderLayout окно было разделено на три области:
- Верхняя (North) - область с выбором шифра и полями для ввода ключей;
- Центральная (Center) - область с двумя окнами для исходного текста и результата;
- Нижняя (South) - область с кнопками управления.
Главное окно представлено на Рисунке 3.

Рисунок 3 - Главное окно приложения
Верхняя панель topPanel разбита с помощью GridLayout на три строчки:
- Выбор шифра - выпадающий список JComboBox с соответственно шифрами Цезаря и Виженера. При выборе шифра Виженера поле для ввода ключа сдвига становится недоступным для пользователя, и наоборот - при выборе шифра Цезаря поле для ввода ключевого слова становится недоступным.
- Ключ сдвига - поле ввода числа для шифра Цезаря. Значение по умолчанию - "0".
- Ключевое слово - поле ввода текста для шифра Виженера. Значение по умолчанию - "ключ".
На средней области был использован компонент JTextArea с целью ввода и вывода текста. Результат выводится в поле справа только для чтения, чтобы предотвратить случайное или умышленное изменение шифрованного текста.
На нижней области расположены пять кнопок:
- Зашифровать - преобразование исходного текста в зашифрованный методом Цезаря или Виженера;
- Расшифровать - преобразование зашифрованного текста в исходный;
- Загрузить файл - открытие диалогового окна для выбора файла и экспорт содержимого в окно исходного текста;
- Сохранить результат - сохранение содержимого окна исходного текста в файл;
- Очистить - очистка обоих окон.
Логическая часть
После того, как был создан интерфейс, впереди самое интересное - наш скелет приложения!
Как было описано выше, метод CreateAlphabet() возвращает массив символов char[]. Для работы с алфавитом был реализован метод findCharIndex(char c). Он принимает на входе символ и в случае если он не найден в алфавите оставляет его без изменений.
private int findCharIndex(char c)
{
for (int i = 0; i < alphabet.length; i++) {
if (alphabet[i] == c) {
return i;
}
}
return -1;
}
Шифр Цезаря представлен двумя методами - shifrovanieText() и deshifrovanieText(). Уже догадались? Первый отвечает за шифрование, второй - за расшифровку методом Цезаря.
При шифровании каждый символ сообщения ищется в алфавите. Если символ найден, то его индекс увеличивается на значение ключа сдвига, который задал пользователь. Далее, берется символ из алфавита по уже новому индексу. Если индекс вышел за предел массива - используется остаток от деления, обеспечивающий цикличность алгоритма.
int newIndex = (index + key) % alphabet.length;
При дешифровании порядок обратный: от индекса отнимается ключ. Если индекс становится отрицательным - после вычисления добавляется длина алфавита для корректирования.
int newIndex = (index - key) % alphabet.length;
if (newIndex < 0)
{
newIndex += alphabet.length;
}
Само собой, значение в поле для ввода ключа сдвига проверяется на целое число и допустимый диапазон значений (от 0 до 115 символов).
Шифр Виженера представляет собой более сложный алгоритм, где величина сдвига динамическая и зависит от ключевого слова. Реализован с помощью методов vigenereEncrypt() и vigenereDescript().
Перед шифрованием текста программа проверяет, что пользователь что-нибудь ввёл в поле ключевого слова. Также есть проверка на наличие символов в алфавите. Далее, начинается процесс кодирования:
- Для каждого символа определяется его индекс в алфавите;
- Берётся следующий символ из ключа (если ключ короче - он циклически повторяется);
- Индекс символа ключа находится в алфавите;
- При шифровании индексы складываются, при дешифровании - вычитаются;
- Результат приводится к диапазону с помощью взятия остатка от деления.
// Шифрование:
int newIndex = (charIndex + keyCharIndex) % alphabet.length;
// Дешифрование:
int newIndex = (charIndex - keyCharIndex + alphabet.length) % alphabet.length;
Как вы могли заметить, дорогие читатели, ключевое слово может содержать как строчные, так и заглавные буквы - регистр учитывается при поиске индекса.
Подводя итог
Результатом разработки стало полноценное приложение на Java, с помощью которого студенты (и преподаватели!) имеют возможность на практике зашифровать и расшифровать текст друг у друга. За целую пару вполне возможно познакомиться с алгоритмами Цезаря и Виженера. Ну и естественно поиграть в "Разведчиков" на перерыве :)
Полный код разработанного приложения размещен на GitHub для скачивания и улучшения.
Спасибо за уделенное время на прочтение!
P.S. Ниже - примеры шифрования, которые были описаны в начале статьи. Наши любимые кошки и собаки!



Daniil