Салют! Всех с наступающим 2023 годом! =)
или с уже наступившим, в зависимости когда вы это читаете)
Предисловие
Специально для xss.pro <3Этот материал я решил написать по нескольким причинам: во-первых это будет мой первый опыт в написании статей, во-вторых челендж the last dance хоть и очень простой, но я надеюсь, что эта статья будет кому-то полезной. В основном новичкам, те кто немного разбираются в криптографии вряд-ли откроют для себя что-то новое, тут всё довольно просто. Ещё инфы по этому челенджу довольно мало (хотя вполне достаточно, чтобы решить задачу), и она вся на английском языке. Поэтому решил написать... Если понравится такой формат, то продолжу разбирать всякие задачки, но уже более сложные. Теперь приступим.
Теория
И начнём с теории. Об операции xor я думаю ничего говорить не надо, если что всё есть в гугле. Я лучше просто отправлю смешных картинок.
Потоковый шифр (stream cipher) - это симметричный шифр, в котором каждый символ открытого текста преобразуется в символ шифрованного текста в зависимости не только от используемого ключа, но и от его расположения в потоке открытого текста. Поточный шифр реализует другой подход к симметричному шифрованию, нежели блочные шифры (взял из википедии). То есть зависит ещё от того, в каком месте открытого текста расположен этот символ, который нужно зашифровать.
Алгоритм chacha20, что используется в данном челлендже потоковый. А ещё он является вариантом семейства salsa20.
Атаки на потоковые шифры
Потоковые шифры, в которых биты открытого текста (дальше обозначим как A или B) объединяются с потоком битов шифрования (дальше в статье обозначим как C) с помощью операции xor, могут быть очень безопасными при правильном использовании. Однако они уязвимы для атак, если не соблюдаются определенные меры предосторожности, поэтому:
1. НИКОГДА, ЗАПОМНИ, НИКОГДА БЛИН НЕ ИСПОЛЬЗУЙ КЛЮЧ ДВАЖДЫ. ПОВТОРЯЮ, НЕ ШИФРУЙ НИЧЕГО ОДНИМ И ТЕМ ЖЕ КЛЮЧОМ ДВА И БОЛЕЕ РАЗ.
2. Правильная расшифровка данных не должна указывать на подлинность. (здесь нам это не пригодится)
Атака на чела, переиспользовавшего ключ.
Итак, мы поняли, что потоковые шифры уязвимы, если какой-то нерадивый человек использовал один и тот же ключ дважды.
E() - так обозначим функцию шифрования, которая принимает в качестве аргумента сообщение и шифрует его.
C() - так обозначим функцию потокового шифра, которая генерирует строку битов. Принимает ключ, как аргумент.
Допустим лох хочет отправить два сообщения A и B одинаковой длины. В таком случае потоковый шифр создаст строку битов C(K) той же длины, что и сообщения. Сразу скажу, что чтобы ксорнуть сообщения разной длины мы просто обрезаем длинное сообщение до размеров меньшего. Ну и так как потоковый шифр создаст одинаковую строку, потому что мамонт использовал один и тот же ключ, мы делаем вывод:
E(A) = A xor C
E(B) = B xor C
Если мы перехватим E(A) и E(B), то сможем узнать E(A) xor E(B).
xor коммутативен и обладает таким свойством, что С xor С = 0 (это называется самоинверсия). Поэтому
E(A) xor E(B) = (A xor C) xor (B xor C) = A xor B xor C xor C = A xor B xor 0 = A xor B
То есть ксор двух зашифрованных сообщений это то же самое, что и ксор двух незашифрованных сообщений. Панятненько? Это всё, что нам нужно знать, чтобы решить задачку.
the last dance
А вот теперь я настоятельно рекомендую самому пройти это, подумать и получить удовольствие от прохождения. Я, когда решал, честно говоря тупил первое время, потому чтоне знал того, что написано сверху. Потом просто начал гуглить, думать и у меня всё получилось. Ну а если ты тоже решил, то продолжение в спойлере:
Качаем архив с заданием и видим два файла: source.py и out.txt. В source.py мы видим, что ключ переиспользуется, а сообщение открыто. В out.txt есть iv (он нам нафиг ненужон), зашифрованное сообщение в формате hex и зашифрованный флаг тоже в формате hex. Зашифрованный флаг и зашифрованное сообщение мы дехексим, а дальше ксорим. Ну и т.к. E(M) xor E(F) = M xor F, то мы можем получить флаг путём (E(M) xor E(F)) xor M. Всё действительно очень просто, если знать теорию. Ну и сам декриптор:
Python:
import codecs
message = b"Our counter agencies have intercepted your messages and a lot days all of them will be captured"
encrypted_message = codecs.decode("7aa34395a258f5893e3db1822139b8c1f04cfab9d757b9b9cca57e1df33d093f07c7f06e06bb6293676f9060a838ea138b6bc9f20b08afeb73120506e2ce7b9b9dcd9e4a421584cfaba2481132dfbdf4216e98e3facec9ba199ca3a97641e9ca9782868d0222a1d7c0d3119b867edaf2e72e2a6f7d344df39a14edc39cb6f960944ddac2aaef324827c36cba67dcb76b22119b43881a3f1262752990", "hex")
encrypted_flag = codecs.decode("7d8273ceb459e4d4386df4e32e1aecc1aa7aaafda50cb982f6c62623cf6b29693d86b15457aa76ac7e2eef6cf814ae3a8d39c7", "hex")
em_xor_ef = []
for i in range(len(encrypted_flag)):
em_xor_ef.append(encrypted_message[i] ^ encrypted_flag[i])
flag = []
for i in range(len(em_xor_ef)):
flag.append(em_xor_ef[i] ^ message[i])
print("".join([chr(i) for i in flag]))
Конец
Вот такой получилась моя первая статья. Надеюсь, что всё было понятно. Всех с наступающим!!!)))