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

Головоломка: Секретные сообщения ✉️

Сегодняшняя проблема, выпуск 22 Адвент-календаря разработчиков 🎅 снова о паролях, кодах и способах их расшифровки. И переходим к классике: шифру Цезаря:

В криптографии шифр Цезаря, также известный как шифр Цезаря, шифр сдвига, код Цезаря или сдвиг Цезаря, является одним из самых простых и широко известных методов шифрования. Это тип шифра замены, в котором каждая буква в открытом тексте заменяется буквой на некоторое фиксированное количество позиций в алфавите.

Проще говоря, мы заменяем каждую букву той, которая следует за ней в x позициях. Например, с shift = 1 буква A становится B. С shift = 2 буква A становится C. С shift = 3 буква A становится D. И так далее.

В Интернете есть несколько решений, но почти все они включают в себя явное написание алфавита плюс некоторые if условия в сочетании с for циклами. Мое решение задачи отличается и начинается с формулы

f(x) = x + k(mod. m)

С m = number of letters of the alphabet и k = shift.

Исходя из этой формулы, я могу получить функцию JavaScript, подобную этой:

Проблема в том, чтобы понять, как передать буквы. Наиболее распространенный метод включает преобразование символа в соответствующий числовой код. Затем мы добавляем сдвиг и конвертируем его обратно в символы.

Я решил сделать что-то другое. Ведь шифр Цезаря — это не что иное, как словарь, в котором каждая буква соответствует другой. Затем я могу создать объект JavaScript с различными буквами в качестве ключей.

Сначала я создаю два массива, один для прописных букв, другой для строчных:

Затем мне нужна функция для вычисления модуля числа:

Наконец-то что-то, что создает соответствие между ключом и решением.

Эта функция принимает на вход массив, содержащий алфавит, и возвращает объект с кодом шифрования.

Для каждого элемента массива, для каждой буквы алфавита вычисляется соответствующая зашифрованная буква. Длина алфавита определяется количеством элементов в массиве.

Чтобы упростить разрешение, я создаю вспомогательную функцию для обработки словаря как прописных, так и строчных букв.

Таким образом, я получаю такой объект:

Получив шифр, я могу перевести каждую букву:

Мы также можем игнорировать все неалфавитные символы очень простым способом: если соответствующий ключ не существует в шифре, то символ не преобразуется:

После создания всех различных функций поддержки решение короткое и простое:

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

Это полный код:

Решение Прашанта Ядава

Как я уже сказал в начале, в Интернете есть много решений этой проблемы. Прашант Ядав предлагает одни из самых распространенных.

Какие проблемы с этим подходом?

  • этот код шифрует только с предопределенным сдвигом (в данном случае 13)
  • работает только для строчных букв
  • работает только со строками, которые не содержат пробелов или других символов, не содержащихся в переменной decoded
  • не расшифровывает сообщение

Его вторая идея более интересна:

Эта функция преобразует все буквы в верхний регистр, а затем заменяет их. Остается проблема обработки строчных букв. Для этого нужно изменить функцию:

Управление неалфавитными символами, включая пробелы, остается проблематичным.

Решение Мариана Ветеану

В Блоге Мариана Ветяну много интересных постов. Есть решение, как создать шифр Цезаря

Это решение работает, но мне не нравится иметь так много жестко запрограммированных значений. Но у него есть то преимущество, что не используются массивы или другие объекты. Как следующее решение.

Решение Эвана Хана

Эван Хан предлагает рабочее решение:

Однако это решение создает некоторые проблемы. Или, скорее, некоторые вещи, которые мне не нравятся. Во-первых, это наличие нескольких if условий и for цикла. Я все больше убеждаюсь, что они затрудняют чтение кода и затрудняют его сопровождение.

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

Но код работает.

Ну вот и все на сегодня. Очевидно, я предпочитаю решение, которое я предложил. Но самое замечательное в JavaScript и в программировании в целом то, что может быть несколько способов найти правильное решение. Часть удовольствия заключается в том, чтобы выяснить, какие пути возможны.

Спасибо за прочтение! Оставайтесь с нами, чтобы узнать больше.

Не пропустите мою следующую статью — подпишитесь на мой Список адресов электронной почты среднего уровня



Первоначально опубликовано на https://blog.stranianelli.com 23 декабря 2021 г.

Больше контента на plainenglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку здесь.