Разработка Java-приложения для шифрования информации методами Цезаря и Виженера
Виженер, Цезарь и студент, который задумался о создании приложения..

Разработка Java-приложения для шифрования информации методами Цезаря и Виженера


Введение

Каждый день люди отправляют тонну информации друг другу, будь то текст, картинки, "кружочки" или голосовые сообщения. Но часто ли вы задумывались о том, каким образом эти данные остаются доступными только адресату? В современном мире защита информации становится не задачей, а необходимостью.

Представим такую ситуацию: вы снимаете видео вашей кошки, которая научилась открывать двери лапкой. Вы отправляете это видео своему другу, но по пути оно попадает в чужие руки. Казалось бы - ну, кошка и кошка, пусть все знают, какой у меня пушистик. Но что, если вместо кошки вы случайно отправите важный конфиденциальный документ?

Чтобы не попасть в неловкие ситуации и сохранить конфиденциальность, нужно знать, как защищаются данные. Сегодня мы рассмотрим не самые новые, но эффективные алгоритмы шифрования: метод Цезаря и метод Виженера. А также рассмотрим приложение, которое я написал на языке программирования Java в ходе выполнения лабораторных работ по предмету "Методы и средства защиты информации".

Немного истории (и теории)

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

Рисунок 1 - Алгоритм шифрования методом Цезаря

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

Рисунок 2 - Алгоритм шифрования методом Виженера

Идея

Всю эту полезную информацию я узнал в ходе изучения предмета "Методы и средства защиты информации" в моем ВУЗе. Неподдельным интересом стало то, что способы шифрования информации с самых древних лет практически не изменились, и всё сводится к простому "текст - кодирование - декодирование". Естественно, современные алгоритмы (например, RSA-256) на основе компьютерных вычислений и генерации псевдослучайных чисел и рядом не стоят с шифрами Цезаря и Виженера. Древние римляне не умели генерировать случайные числа на ПК, знаете ли. Но для погружения в области криптографии и шифрования необходимо знать, любить и уважать древнейшие алгоритмы.

Открывая лабораторную работу, увидел заветное "Разработать алгоритм шифрования с применением полученных знаний по теме Тайнопись". Тут-то и пригодились теоретические знания, и начался брейншторм (по-русски - "шевеление мозгами"). Первоначально, думал над консольным интерфейсом, но захотелось навести суеты красоты и сделать полноценный интерфейс с возможностью ввода пользователем всей необходимой информации для шифрования. Ну и куда же без ввода-вывода из файла!

Выбор языка программирования

Начал думать, какой язык выбрать. В итоге, остановился на Java - модный, стильный, молодёжный, так еще и объектно-ориентированный (для справки - создан в 1995 году компанией Sun Microsystems под руководством Джеймса Гослинга. Не того Гослинга, о котором вы подумали). 

Язык Java представлен обширной библиотекой классов, и тут по-настоящему можно разгуляться: тут сразу и работа со строками, и файловый ввод-вывод, и графическое взаимодействие. А еще, у Java есть замечательная вещь под названием кроссплатформенность. То есть, приложение сможет запустить кто угодно и на чём угодно, главное иметь на ПК предустановленный JVM (прим. Java Virtual Machine, Виртуальная машина Java). Насчет JVM переживать не стоит - каждый, кто хоть раз играл в Майнкрафт, уже имеет на компьютере JVM. Не благодарите.

С языком определился, осталось определиться с графическим интерфейсом. И тут на помощь пришла встроенная библиотека Swing. В данной библиотеке представлен широкий спектр возможностей: создание форм, переключателей, кнопок, полей ввода. Особенно заманчивым является то, что в процессе написания логики обращается минимум внимания на установку сторонних зависимостей.

План действий

Театр начинается с вешалки, а разработка приложения - с плана:

  1. Необходимо создать алфавит, по которому будет шифроваться исходное сообщение. Такой алфавит должны иметь отправитель и адресат, чтобы правильно расшифровать данные.
  2. Создать графический интерфейс, понятный для пользователя.
  3. Создать методы для шифрования, расшифровки, записи в файл/из файла сообщений.

Алфавит приложения

Алфавит не ограничивается только русскими буквами. Если мы говорим про электронное письмо, то пробел, переход на следующую строку, кавычки и знаки препинания тоже являются символами. Я принял решение ограничиться русскими буквами вместе со знаками препинания и специальными операторами. Алфавит был сделан в виде массива символов и представлен ниже. Всего 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. Ниже - примеры шифрования, которые были описаны в начале статьи. Наши любимые кошки и собаки!

Оценить публикацию