Ужасный курс, ужасные лабораторные и бездарный приём лаб - в общем, ЗИ достойный преемник традиций Тассова и Курова! Сдал все лабы паком в начале декабря, потому что очередь дошла только в декабре. Код в целом рабочий, хоть и написано плохо. Часть функций вообще написано было только для того, чтобы защитник не задавал вопросы, хотя в лабе фактически не используется.
Ну и ещё стоит понимать, что знания самого защитника не выходят за пределы википедии и курса ЗИ 20-летней давности.
P.S. Григорьев норм мужик - это база
У структуры rotor два поля: массив байтов и количество вращений. Когда на вход подается символ, у символа есть какое-то число от 0 до 255, и оно используется как индекс. По массиву с индексом получается следующее значение, которое подаётся на следующий вход.
Ротор вращается так: происходит сдвиг на 1 значений по индексам, последний элемент становится первым, и всё сдвигается на один элемент влево. Если провернулся ровно N раз, то счетчик обнуляется.
Роторы вращаются по очереди. Как только первый ротор закончил полный круг, то следующий ротор повернется на один элемент.
По коду: заполняем сначала значение = index, а затем вызываю функцию shuffle из пакета random
Рефлектор симметричен: если при подаче символа A рефлектор выдаёт B, то если подать символ B, то рефлектор выдаст символ A.
Также рефлектор не вращается в ходе работы программы.
Рефлектор был заполнен следующим образом: символу с номером i ставился в соответствии символ с номером 255-i. Алфавит должен быть чётным!
Ничем. Для дешифровки нужно роторы и рефлектор привести к тому же виду, в каком они были изначально при шифровке. Через энигму нужно пропустить зашифрованный текст, чтобы получить исходный.
Нет, байт в байт.
Первый ротор повернется M раз, второй ротор повернется M // 256 раз, а третий ротор повернется M // (256^2) раз.
В целом ничем, но во время прямого хода ищется значение в массиве по индексу, а во время обратного хода ищется индекс определенного значения в массиве.
Больше всего его интересует функция Фейстеля (в коде прям стоит функцию показать).
Процессы внутри выполняются одинаковые, но во время раундов во время шифрования вычисляется функция Фейстеля для правой половины, а во время расшифровки для левой половины.
Не меняются. Во-первых, они обратные друг к другу, а во-вторых, табличные.
После расширяющей перестановки в функции Фейстеля сообщение составляет 48 бит. 48 бит делится на 8 составляющих, по 6 бит.
Пусть сообщение abcdef, тогда x это af - число из двух бит, а y - bcde - число из четырех бит. Тогда если взять координаты из таблицы, и получается, что каждое число из таблицы составляет 4 бита. Таким образом, сообщение снова сжимается до 32 бит.
На вход функции Фейстеля приходит сообщение длиной 32 бита. Сначала функция Фейстеля делает расширяющую перестановку, после чего выполняет XOR результата с текущим раундовым ключом. Дальше происходит манипуляция с S-блоками: сообщение длиной 48 байт делится на 8 частей по 6 бит, из 1 и 6 бита координата x, из 2,3,4,5 битов - координата y. Происходит подстановка и итоговый результат дополняется для каждого сообщения до 4 бит.
В этом случае нужно дополнить размер файла нулевыми байтами до такого состояния, чтобы он был кратен 8 байт. Это нужно сделать, так как алгоритм принимает на вход сообщение длиной 64 бита.
Если размер файла дополнялся до кратности 8 байт, тогда будет различие (расшифрованный будет чуть больше), но если дополнения не было изначально, то они будут совпадать байт в байт. Я в коде убирал лишние байты, убирая байты 0 с конца.
Если было дополнение до кратности 8 байт, то отличаются на размер дополнения, иначе разницы нет, байт в байт.
На вход подается сам ключ, который длиной дополняется до 64 бит. Сначала происходит сжатие до 56 бит сжимающей перестановкой. Затем ключ делится на две части по 28 бит. Затем в цикле к каждой половине применяется сдвиг, затем обе половины заново соединяются, снова происходит сжимающая перестановка, и на выходе получается очередной раундовый ключ,.
На вход функции подстановки входит сообщение 48 бит. Оно делится на 8 равных частей по 6 бит.
Затем проходим циклом по всем этим частям. Пусть сообщение abcdef, тогда x это af - число из двух бит, а y - bcde - число из четырех бит. Тогда если взять координаты из таблицы Table[i][x][y], получается новая подстановка вместо этих 6 бит. Также нужно ещё дополнить значение из таблицы до того, чтобы оно было 4 байта.
Он есть только в английской википедии, в то время как в схемах защитника его нет, и в русской Вики тоже. Короче, коллективная шиза по поводу swap, его не должно быть. Но если его нет, то и не спрашивает.
В таблице находится список того, какие байты сообщения в каком порядке нужно взять, чтобы получить расширенное сообщение. Если там 32 1 2 3 …, то первым байтом в получившейся последовательности будет значение 32 байта в исходной последовательности, и так далее.
- Цикл от 0 до 15 при шифровке, и от 15 до 0 при дешифровке.
- При шифровке в функцию Фейстеля передаётся правая часть, а при дешифровке - левая.
Нужно прям разобраться в генерациях ключей и расширенном алгоритме Евклида.
Для генерации используется решето Эратосфена: проходим циклом от 2 до N, если число делится на i, то оно уже не простое. Результаты заносим в bool массив, а затем уже проходим по bool-массиву и сохраняем в итоговый результат индексы значений.
В качестве открытого ключа используют любое число, которое взаимно простое с функцией Эйлера от двух случайно выбранных простых чисел.
Закрытый ключ выбирается так, чтобы он был обратным к открытому ключу по модулю функции Эйлера. открытый ключ * закрытый ключ mod Эйлер = 1
Расширенный алгоритм Евклида - расширение алгоритма Евклида, которое вычисляет кроме НОД ещё и коэффициенты соотношения Безу, то есть целые X и Y, что aX + bY = НОД(a, b).
Решетом Эратосфена, а затем выбираем либо два случайных числа, либо два последних случайных числа.
Либо через расширенный алгоритм Евклида, либо используем тест Миллера-Рабина, но я использовал первый вариант.
Часто использует именно такое E, так как оно простое -> взаимно простое с остальными числами, при этом в алгоритме быстрого умножения будет меньше действий, так как в битовом представлении всего две единицы.
Запустить расширенный алгоритм Евклида, который подсчитает также коэффициенты Безу, один из которых будет обратным к первому числу.
Максимальная длина одного символа зависит от мощности алфавита, фактически это параметр N - длина алфавита. Сколько байт занимает N - такой максимальный размер одного символа в памяти.
Самая лёгкая лаба для сдачи вместе с Энигмой, даже код не смотрит.
В первую очередь требуется сгенерировать ключи: для алгоритма подписи требуется приватный ключ. После этого читается содержимое файла, под который нужно поставить подпись, это содержимое хэшируется. С помощью приватного ключа и содержимого файла создаётся подпись, которая записывается в специальный файл
Для верификации требуется файл, под который поставлена подпись, сама подпись и публичный ключ. Файл хэшируется, затем функция проверяет корректность поставленной подписи.
Требуется дерево для восстановления данных. Пусть есть последовательность бит. Тогда делаем цикл по всем данным и параллельно шагаем по дереву: если бит = 0, то влево, если = 1, то вправо. Когда окажется, что справа и слева у листа нет элементов, то значит, что мы дошли до очередного символа, он добавляется в запись, и со следующей итерацией идем заново с корня дерева.
Для расшифровки нужно дерево, поэтому либо нужно хранить и передавать дерево, либо передавать таблицу частот и строить дерево заново.
Дерево строится от листьев к корню, при расчете кода символа же поиск проиходит от корня к листьям.
Когда переводим 0 и 1 в байты, то получается, что для последнего байта может не хватать 8 бит, и придётся решить проблему, как интерпретировать последний байт.
За счет наличия дополнительной информации о данных: во-первых, знание того, какие символы использовались, а во-вторых, частоту появления этих символов. Чем чаще встречается символ, тем короче у него получается код.
Строится от листьев к корню. Сначала берутся две записи из таблицы с наименьшим весом, на их основе создается лист дерева, у которого указатели на лево и право – уже взятые записи. Получившая запись добавляется в таблицу, и так до тех пор, пока размер таблицы не станет равным 1.
Так как используется бинарное дерево, то каждый раз, когда идем по дереву влево, подписываем к коду символа 0, а когда вправо – 1. Когда найдем нужный символ, то берем получившийся из пути код. Код можно хранить в стеке.