обзор
Ваша цель - внедрить шифрование RC4. Шифрование RC4, изобретенное Роном Ривестом (из известности RSA), было разработано, чтобы быть безопасным, но достаточно простым, чтобы быть реализованным из памяти военными на поле боя. Сегодня существует несколько атак на RC4, но он все еще используется во многих местах сегодня.
Ваша программа должна принимать одну строку с ключом и некоторыми данными. Он будет представлен в этом формате.
\x0Dthis is a keythis is some data to encrypt
Первый байт представляет длину ключа. Можно предположить, что длина ключа не будет превышать 255 байтов и не будет меньше 1 байта. Данные могут быть произвольно длинными.
Ваша программа должна обработать ключ, а затем вернуть зашифрованные данные. Шифрование и дешифрование RC4 идентичны, поэтому использование одного и того же ключа для «шифрования» зашифрованного текста должно возвращать исходный открытый текст.
Как работает RC4
инициализация
Инициализация RC4 довольно проста. Массив состояния 256 байтов инициализируется для всех байтов от 0 до 255.
S = [0, 1, 2, 3, ..., 253, 254, 255]
Обработка ключей
Значения в состоянии меняются местами в зависимости от ключа.
j = 0
for i from 0 to 255
j = (j + S[i] + key[i mod keylength]) mod 256
swap S[i] and S[j]
шифрование
Шифрование выполняется с помощью состояния для генерации псевдослучайных байтов, которые затем передаются в XOR. Ценности в государстве постоянно меняются местами.
i = j = 0
for each byte B in data
i = (i + 1) mod 256
j = (j + S[i]) mod 256
swap S[i] and S[j]
K = S[(S[i] + S[j]) mod 256]
output K XOR B
Ожидаемые входы и выходы
Непечатные символы будут показаны в \xAB
формате.
Вход: \x01\x00\x00\x00\x00\x00\x00
Выход: \xde\x18\x89A\xa3
Выход (шестнадцатеричный):de188941a3
Вход: \x0Dthis is a keythis is some data to encrypt
Выход: \xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
Выход (шестнадцатеричный):b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
Вход: \x0dthis is a key\xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
Вход (шестнадцатеричный): 0d746869732069732061206b6579b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
Выход:this is some data to encrypt
Вход: Sthis is a rather long key because the value of S is 83 so the key length must matchand this is the data to be encrypted
Выход: \x96\x1f,\x8f\xa3%\x9b\xa3f[mk\xdf\xbc\xac\x8b\x8e\xfa\xfe\x96B=!\xfc;\x13`c\x16q\x04\x11\xd8\x86\xee\x07
Выход (шестнадцатеричный):961f2c8fa3259ba3665b6d6bdfbcac8b8efafe96423d21fc3b13606316710411d886ee07
источник
\xde
, то она должна быть длиной 1 байт, и преобразование ее в число (через pythonord()
или javascript.charCodeAt(0)
) должно вернуть 222 (0xDE).Ответы:
JavaScript (ES6),
169168 байтПринимает ввод как массив байтов. Возвращает другой массив байтов.
Как?
По сути, это буквальная реализация спецификации.
Сначала мы разбиваем входной массив на l (длина ключа) и s (данные полезной нагрузки: ключ + сообщение). Затем в порядке исполнения:
Мы инициализируем массив состояний S и определяем m = 255, который позже используется как битовая маска.
Мы перетасовываем массив состояний. Индексы I и J, которые здесь инициализируются, фактически используются на следующем шаге.
Мы применяем шифрование.
Контрольные примеры
Показать фрагмент кода
источник
138 байт, машинный код (16-битный x86)
Запуск: сохранить на codegolf.com, dosbox:
codegolf.com < input.bin
Я не знаю, будет ли это считаться записью, но я решил сделать это вручную, используя шестнадцатеричные редакторы. Для этого не использовались компиляторы .
В ht-редакторе действительно есть ассемблер, но, честно говоря, я не знал об этом, пока не закончил ¯ \ _ (ツ) _ / ¯
Почему как
Почему: в основном потому, что я хотел проверить, могу ли я это сделать.
Как: я начал с создания байта, заполненного символом
NOP
s, и последующей простой части: попытка написать первый цикл, который заполняетS
tate значениями 0..255. Я переключился на Python и быстро написал версию Python, просто чтобы иметь что-то для тестирования. Затем я упростил код Python до псевдо-кода / псевдо-сборки. Тогда я пытался писать маленькие кусочки. Я решил, что будет проще читать со стандартного ввода, поэтому я начал с чего-то маленького, который будет читать один байт, затем добавил чтение пароля и инициализацию ключа. Выяснение того, какие регистры выбрать, заняло у меня некоторое время.Хотя добавить петлю де / шифрования будет легко, но сначала я получил однобайтовое декодирование и впоследствии добавил целый цикл.
Последним шагом было избавление от дополнительного,
nops
который я оставил между инструкциями при написании (ofc, который также требовал исправления прыжков).Вы можете увидеть небольшую галерею, которую я пытался сделать, прогрессируя здесь .
рассечение
Программа полагается на некоторые начальные значения после запуска (см. Ресурсы ниже).
заполнить состояние (в 0x200)
прочитайте длину, прочитайте пароль, сохраните пароль на ds: 0x300
инициализировать состояние ключом (
BP
используется для обхода ключа,SI
используется для обхода состояния)генерировать псевдослучайное значение (в
DL
,DH
0 ТНХ к XOR на 0x140)SI
целые числа не будут касаться этогоBX
)DX
)PS Это, вероятно, может быть даже короче, но это заняло 4 вечера, поэтому не уверен, если я хочу провести еще один ...
Инструменты и ресурсы
источник
C (gcc) ,
193 188 182 178 171172 байтаПопробуйте онлайн!
Редактировать: теперь работает с ключами длиннее 127 байт.
Edit2: добавлен тестовый пример с 129-байтовым ключом для ссылки TIO.
Чуть менее гольф-версия
источник
Набор инструкций CPU x86, 133 байта
A7D-9F8 = 85h = 133 байта, но я не знаю, в порядке ли вычисление, потому что предварительное число байтов одной и той же функции приводит к 130 байтам ... Первым аргументом функции, которую я называю "cript", является строка, второй аргумент - длина строки (первый байт + длина ключа + длина сообщения). Ниже приведен файл на языке ассемблера для получения таких подпрограмм:
ниже файла C для результатов проверки:
результаты:
источник
JavaScript (ES6), 262 байта
Я подумал об использовании только связанных функций, но решил использовать алгоритм, приведенный здесь: https://gist.github.com/farhadi/2185197 .
Меньше гольфа
Показать фрагмент кода
источник
Python 2 , 203 байта
Попробуйте онлайн!
f
является генератором (повторяемым) строк.Ungolfed:
источник
Рубин, 234 байта
Непроверенные.
источник
C 181 байт
спасибо floorcat за меньше байтов:
f (a, n) в "a" будет массив символов 1Byte len + key + message; в n есть размер всего массива "a", не считая последнего '\ 0'. код для теста и результата будет как код, используемый для функции сборки.
источник
APL (NARS), 329 символов, 658 байтов
как всегда, проверка ошибок потребовалась бы кому-то другому ... Это нормально для ввода и вывода, test:
Да, все может быть уменьшено ... но, например, сделайте больше, функция xor может сделать ее менее общей ...
источник
Ржавчина 348
Это очень ужасно большое, я надеюсь, что кто-то может дать некоторые предложения.
без игры: на игровой площадке play.rust-lang.org
источник
k
вместоkey
иm
вместоmsg
иfoo&255
вместо(foo)%256