Минимальная реализация алгоритма RSA на C++

Описание программы

Алгоритм асимметричного шифрования RSA основан на практической сложности факторизации больших чисел, что делает его на сегодняшний день одним из самых популярных криптографических алгоритмов.
Однако он имеет свои отрицательные стороны, например среди них достаточно низкая скорость шифрования, поэтому зачастую используют смешанную криптосистему, в которой сначала две стороны передают симметричный ключ с помощью RSA, а затем шифруют сообщение с помощью какого-либо симметрического алгоритма, например AES.
О самом алгоритме можно почитать например тут.
RSA может шифровать числа до так называемого модуля, который является частью ключа. В настоящее время используются модули длиной в 1024, 2048 и даже 4096 бит. В нашей реализации без длинной арифметики получится иметь дело максимум с 64-битными ключами, однако для наглядности этого хватит. Для того, чтобы сообщение при шифровании многократно не увеличивалось в размере, шифровать его надо блоками по $k — 1$ бит, где $k$ — битность ключа. При этом каждый блок перейдет в $k$-битное число, то есть на больших файлах прирост размера составит всего лишь $\frac{k}{k-1}$ раз, и чем больше ключ — тем меньше этот прирост.
В программе делением массива чисел одной битности на числа другой битности занимается функция resize, дополняя недостающие биты нулями.
Шифрованием и одновременно дешифрованием занимается функция process_bytes, так как в RSA оба этих процесса имеют идентичные алгоритмы, отличающиеся только размером блока входа и выхода. Для этого используется алгоритм быстрого возведения в степень.
Также программа может генерировать ключи на основании предустановленных простых чисел (в будущем случайных), или на основании простых чисел, введенных пользователем. Для этого используется нахождении обратного в кольце по модулю расширенным алгоритмом Евклида.
Программа реализована в интерактивном виде, список команд можно вызвать командой h.

Continue reading

Related Images:

Proggy-Buggy 2018: Задача A. Шифр Цезаря

Задание

Багги мнит себя Гаем Юлием Цезарем и любит громогласно его цитировать при каждом удобном случае, выдавая мысли Цезаря за свои. Проги пошутил над Багги и зашифровал в стиле Цезаря список цитат, которыми пользуется Багги. Багги в панике. Если хотите, помогите ему расшифровать известную цитату :

UDMHUHCHUHBH

Напишите программу, которая для вышеприведенного шифртекста выводит соответствующий открытый текст.

Код

Решение

Шифр Цезаря так же известен как шифр сдвига. Каждая буква сдвигается в алфавите на константу влево или вправо по модулю длины алфавита . В нашем случае зашифрованное и расшифрованное сообщение будет состоять только из букв (в условии не сказано ничего про сам алфавит).

Ниже пример шифрования методом сдвига (в данном случае на 3 единицы вправо)

A заменяется на D
B заменяется на E
и так далее
Z заменяется на C

Нам остается только подобрать ключ. Простым перебором получаем что зашифрованное сообщение было получено сдвигом всех букв исходного сообщения на единицу влево.
Ну что еще сказать?
Пришёл, увидел, победил!
Veni, vidi, vici!

Related Images:

MS9. Шифрование символов

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

Входные данные
Последовательность символов.

Выходные данные
Зашифрованная последовательность символов, напечатанная через пробел.

Тесты

входные данные выходные данные
pack my box with five dozen liquor jugs

p 11 2 8 4b 4d 14 59 42 d 17 58 57 1e 1d 1c 48 46 f 1f 13 45 44 b 15 1f b 4e 4c 5 18 4 1a 1d 52 4a 1f 12 14

Код программы

Решение задачи
Объявляем 2 символьные переменные. Считываем первый символ и выводим его. Остальные символы будут считываться в цикле, пока не произойдет переход на следующую строку.По мере ввода запоминаем старый символ во 2 переменной и складываем их по модулю 2 и выводим результат в шестнадцатеричной системе.

Ссылки

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

Входные данный
Код полученный из выполнения основной задачи.

Выходные данные
Изначальный текст.

Тесты

входные данные выходные данные
p 11 2 8 4b 4d 14 59 42 d 17 58 57 1e 1d 1c 48 46 f 1f 13 45 44 b 15 1f b 4e 4c 5 18 4 1a 1d 52 4a 1f 12 14 pack my box with five dozen liquor jugs

Код задачи

Решение задачи
Так как сложение по модулю 2 обратно само себе, то нам нужно считать символы в том же порядке и применить тот же алгоритм при шифровании.

Related Images:

MS10. Зашифровка текста

Задача

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

Входные данные

Символьная последовательность.

Выходные данные

Зашифрованная символьная последовательность.

Тесты

Входные данные Выходные данные
Where is the table? a8 c0 a5 d7 b2 92 fb 88 a8 dc b4 d1 f1 85 e4 86 ea 8f b0
What a nice day! a8 c0 a1 d5 f5 94 b4 da b3 d0 b5 95 f1 90 e9 c8

Код программы

Решение

Выделяем участки памяти для символьных переменных, считываем первый символ и его инвертируем, затем выводим в шестнадцатеричной системе счисления с пробелом.
Используем цикл «while»: пока считываются данные в переменную x2, XORим предыдущий и новый символы, выводим новый символ и запоминаем новый зашифрованный символ, который становится предыдущим.

Ссылки

Условие задачи
Решение задачи на сайте Ideone.com

Related Images:

MS15. Зашифровка и расшифровка текста

Для решения задания MS15 необходимо, чтобы предыдущее уже было сделанным, однако на момент публикации оно таковым не является, потому данная запись содержит и его решение тоже.

Условие задачи MS14.
Зашифруйте текст из входного потока заменяя каждый символ по формуле [latex]c=at+b \mod 256[/latex], где [latex]t[/latex] — символ открытого текста, [latex]c[/latex] — символ зашифрованного текста, [latex]a[/latex], [latex]b[/latex] — произвольные ключи (параметры) шифрования.

Входные данные:
Два ключа через пробел и, через ещё один пробел, текст.

Выходные данные:
Зашифрованный текст.

Тесты.

Входные данные Выходные данные
[latex]a[/latex] [latex]b[/latex] Исходный текст Зашифрованный текст
1 f n Kittens P▲D*ж.ж.м(B,@.
2 4 j Hello, world! ◙☼ю¶z▬z▬ў▬z○ъ♠ц↑ў▬т↨z▬║¶▲•
3 ? . 0123456789 ■♂=♀|♀╗♀·♀9♪x♪╖♪ў♪5♫

Код на С++

Код на Java

Условие задачи MS15.
Найдите способ и напишите программу расшифровки текста зашифрованного в предыдущем задании по известным [latex]a[/latex] и [latex]b[/latex].

Входные данные:
Два ключа через пробел и, через ещё один пробел, зашифрованный текст.

Выходные данные:
Расшифрованный текст.

Тесты.

Входные данные Выходные данные
[latex]a[/latex] [latex]b[/latex] Зашифрованный текст Расшифрованный текст
1 f n P▲D*ж.ж.м(B,@. Kittens
2 4 j ◙☼ю¶z▬z▬ў▬z○ъ♠ц↑ў▬т↨z▬║¶▲• Hello, world!
3 ? . ■♂=♀|♀╗♀·♀9♪x♪╖♪ў♪5♫ 0123456789

Код на C++

Код на Java

Решение.
Основной трудностью при решении задачи является тот момент, что при шифровке символов строго по формуле, указанной в условии MS14, а именно [latex]c=at+b \mod 256[/latex], символы зашифрованного текста могут расшифровываться неоднозначно. К примеру, при [latex]a=8[/latex] и [latex]b=1[/latex] после зашифровки символов [latex]@[/latex] и [latex]`[/latex] в обоих случаях получим символ с кодом [latex]1[/latex]. Это часто лишает расшифрованный текст какого-либо смысла. Так происходит, поскольку в переменных типа [latex]unsigned[/latex] [latex]char[/latex] могут храниться элементы с кодом от [latex]0[/latex] до [latex]255[/latex], и при попытке присвоить переменной большее значение совершается своеобразный «круг». Так, если ей присвоить значение [latex]257[/latex], при выводе получим символ с кодом [latex]1[/latex]. Сначала в ходе работы обеих программ вводятся два ключа, а лишние пробелы читаются в одну из переменных для хранения символов. Программа для зашифровки принимает символ, зашифровывает его по указанной формуле, и выводит, а сразу за ним — элемент с кодом, который высчитывается по другой формуле: [latex]c=(at+b) / 256[/latex]. Этот код совпадает с числом совершённых «кругов». Программа для расшифровки же на каждом цикле принимает эти два символа, и выводит символ исходного текста, код которого вычисляется округлением до целых значения выражения [latex]\frac { c1-b+256\cdot c2 }{ a } [/latex], где [latex]c1[/latex] — первый символ, а [latex]c2[/latex] — второй.

Условия задач.
Код MS14 на ideone.com(C++)
Код MS15 на ideone.com(C++)
Код MS14 на ideone.com(Java)
Код MS15 на ideone.com(Java)

Related Images:

MS17. Самосинхронизирующийся скремблер

Задача

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

Примечание: разобьём данную нам задачу на две подзадачи. В первой будет рассмотрено скремблирование входных данных, а во второй будет проведено дескремблирование исходных данных первой подзадачи.

Подзадача 1

Рассматривая входной поток как последовательность бит, зашифруйте его при помощи восьмибитового самосинхронизирующегося скремблера.

Входные данные

Некая символьная последовательность.

Выходные данные

Зашифрованная символьная последовательность.

Тесты

Входные данные Выходные данные
Dogs eat meat. ea 27 33 77 25 11 66 75 5 3b e0 89 6b fa
Scramble it! fc 5a 80 ef 75 43 1e 92 9b 46 57 6
Base, base, it’s cheeseburger 1. Can you hear me? ec 49 a0 c9 72 75 43 13 55 66 28 80 e7 ed d2 75 b7 bf 69 93 c7 df 4e d0 be 3f b1 de 5c f6 ea 6c 94 f5 8d 1f 86 80 aa 74 5e c7 9e 17 2 47 41 76 7c d4 a1

Код программы

Решение задачи

Для зашифровки будем использовать стандартный алгоритм скремблирования. Скремблером будет переменная key, которая изначально равна [latex]5[/latex]. Выбирать из скремблера будем нулевой и четвёртый биты. Входные данные будут поступать в переменную input, после чего на них и на скремблере будет применяться функция scram.
Так как входные данные имеют формат unsigned char, считывание не прекратится никогда вплоть до принудительной остановки программы, ведь любые входные данные могут быть восприняты как символы. Для предотвращения этого, необходим символ, который будет служить «сигналом» для остановки программы. В нашем случае, это будет символ перехода на следующую строку.
Основная проблема задачи заключается в выводе зашифрованных данных, так как в результате скремблирования некоторые символы могут оказаться не отображаемыми. Дабы избежать подобной ситуации, зашифрованные данные будем выводить в шестнадцатеричном (для кода на Java — в десятичном) числовом формате.

Подзадача 2

Расшифровать входные данные из предыдущей подзадачи.

Входные данные

Некие зашифрованные данные, записанные в виде последовательности чисел шестнадцатеричного (для кода на Java — десятичного) формата.

Выходные данные

Расшифрованные данные.

Тесты

Входные данные Выходные данные
ea 27 33 77 25 11 66 75 5 3b e0 89 6b fa Dogs eat meat.
fc 5a 80 ef 75 43 1e 92 9b 46 57 6 Scramble it!
ec 49 a0 c9 72 75 43 13 55 66 28 80 e7 ed d2 75 b7 bf 69 93 c7 df 4e d0 be 3f b1 de 5c f6 ea 6c 94 f5 8d 1f 86 80 aa 74 5e c7 9e 17 2 47 41 76 7c d4 a1 Base, base, it’s cheeseburger 1. Can you hear me?

Код программы

Решение задачи

Для расшифровки будем применять обратный алгоритм к использованному в предыдущей задаче. Значение необходимого для расшифровки дескремблера нам известно из предыдущей задачи (а именно — [latex]5[/latex]), поэтому его мы и используем.
Входные данные будут считываться методом cin (для C++), где параметр hex будет указывать на то, что данные поданы в шестнадцатеричном формате. После считывания на входных данных будет применяться алгоритм дескремблирования, и итоговые данные будут выведены на экран.

Ссылки

Related Images: