CryptoLab: как я превратил лабораторную по криптографическим протоколам в стенд с Alice, Bob и Mallory

В этом учебном году мне потребовалось подготовить лабораторные работы по дисциплине «Криптографические протоколы». Самый очевидный вариант практической работы – дать студентам Python и предложить что-нибудь зашифровать: сгенерировать ключ, вызвать AES-GCM из библиотеки, получить ciphertext, затем расшифровать его обратно.
Полезно, но мне хотелось немного другого. Когда мы изучаем криптографический протокол, гораздо интереснее не просто увидеть:
encrypt() → decrypt()
а поставить между отправителем и получателем активного нарушителя и посмотреть, что произойдёт.
Что видит атакующий в зашифрованном пакете? Что будет, если изменить ciphertext? Можно ли повторить старый, но совершенно корректный пакет? Что произойдёт при повторном использовании nonce? Как поведёт себя система после отзыва ключа?
Из этих вопросов постепенно появился CryptoLab – учебный стенд, который я сейчас развиваю параллельно с преподаванием курса.
В этой статье расскажу о том, как устроена первая лабораторная работа, какие задачи я пытался решить при её разработке и покажу два наиболее характерных эксперимента.
Базовая модель: Alice → Mallory → Bob
Основой первой лабораторной стала классическая модель:
Alice → Mallory → Bob
Здесь:
Alice – клиент;
Bob – сервер;
Mallory – активный атакующий, контролирующий канал связи.
Но в CryptoLab это уже не просто персонажи на слайде. Каждый участник – отдельный режим приложения. Идея заключается в том, чтобы запустить их одновременно и получить реальный обмен сообщениями через Mallory:
Alice ──────→ Mallory ──────→ Bob
│
├── INSPECT
├── MODIFY
├── DROP
└── REPLAYВ нормальном режиме Alice формирует защищённый пакет, Mallory пропускает его дальше, а Bob проверяет и принимает.

Затем студент становится Mallory и начинает вмешиваться в протокол. Именно это стало для меня главным принципом первой лабораторной:
Не просто рассказать, что определённое правило нельзя нарушать, а дать возможность нарушить его и посмотреть на результат.
Что сейчас умеет первая лабораторная
В текущей версии первой лабораторной я собрал эксперименты, связанные с:
AES-GCM;
ciphertext и authentication tag;
AAD;
nonce;
replay attack и replay protection;
повторным использованием
(Key, Nonce);CSPRNG и слабым RNG;
salt;
ротацией и отзывом ключей;
утечкой информации через метаданные.
При этом есть два типа работы со стендом.
Первый — интерактивный. Alice, Mallory и Bob запускаются одновременно, а пользователь непосредственно управляет действиями атакующего.
Второй — готовые автоматические сценарии. Например:
./CryptoLab scenario --lab 1 --name 08_weak_rngзапускает эксперимент со слабым генератором случайных чисел.
Автоматические сценарии оказались полезны не только для обучения. Для меня они одновременно стали набором проверок самого CryptoLab: после изменения приложения можно снова прогнать лабораторную и проверить, что ожидаемое поведение сохранилось. Но покажу подробнее два эксперимента из первой работы.
Эксперимент №1. Что произойдёт, если Mallory изменит ciphertext
Начнём с одной из самых очевидных атак. Alice отправляет Bob зашифрованное сообщение с использованием AES-GCM. Mallory перехватывает пакет. Сам plaintext ей неизвестен, но ciphertext доступен. Попробуем изменить его.
Если AEAD используется корректно, Bob не должен получить «немного испорченный plaintext» и продолжить работу. Изменение ciphertext должно привести к ошибке проверки authentication tag.
Логика получается примерно такой:
ciphertext modified
↓
authentication failed
↓
REJECTДля студента здесь важен не только сам факт того, что сообщение было отклонено. Эксперимент позволяет перейти к более общему правилу:
AEAD decrypt → plaintext OR FAILДанные не должны передаваться прикладной логике до успешной аутентификации.

То есть мы на конкретном эксперименте приходим к принципу fail closed: если проверка безопасности не пройдена, система должна отказаться от обработки сообщения, а не попытаться «как-нибудь продолжить».
При этом хорошо видно и различие между шифрованием и аутентифицированным шифрованием. Задача состоит не только в том, чтобы Mallory не могла прочитать plaintext. Bob должен также определить, что полученный ciphertext не был изменён по пути. Для меня это один из важных моментов всего стенда: некоторые понятия гораздо проще объяснять не через ещё один слайд, а через поведение работающего протокола.
Эксперимент №2. Replay: правильный tag ещё не означает, что сообщение нужно выполнить
Другой показательный эксперимент — Replay Attack. Alice отправляет Bob совершенно корректное сообщение. Bob получает его, проверяет authentication tag и выполняет операцию. Mallory при этом сохраняет весь пакет. После этого она повторно отправляет Bob тот же самый пакет.
И здесь возникает интересная ситуация. Ciphertext правильный. Nonce тот же самый, что был в исходном пакете. AAD не изменялись. Authentication tag настоящий. Более того, пакет действительно был создан Alice и после этого вообще не модифицировался. Поэтому AES-GCM вполне может успешно подтвердить его аутентичность. Но означает ли это, что операцию нужно выполнить второй раз?
Не обязательно. Представим, например, что защищённое сообщение означает выполнение некоторой операции:
TRANSFER 100Mallory не умеет превратить её в:
TRANSFER 1000Authentication tag этого не позволит. Но если протокол не защищён от повторов, атакующему может быть достаточно отправить исходную корректную команду ещё раз.

Получаем очень важное различие: authentication ≠ freshness
Криптография подтверждает, что пакет настоящий и не был модифицирован. Но протокол дополнительно должен определить, является ли он новым. В CryptoLab можно провести этот эксперимент в двух вариантах. Сначала отключить replay protection и повторить перехваченный пакет. Затем включить защиту и провести ту же атаку ещё раз.
Во втором случае состояние протокола позволяет определить, что сообщение уже обрабатывалось, и отклонить его. Так из практического эксперимента появляются понятия sequence numbers, replay cache и состояние протокола. И становится хорошо видно, что проблема находится уже не внутри AES-GCM. AES-GCM выполнил свою работу правильно.
Replay protection — это дополнительное свойство протокола, построенного вокруг криптографического примитива. Именно такие границы ответственности между отдельными механизмами я и хотел сделать более заметными с помощью CryptoLab.
Интерактивный режим и автоматические сценарии
В итоге в первой лабораторной я оставил два взаимодополняющих способа работы. Для изучения самого взаимодействия удобнее запустить три компонента:
Alice → Mallory → Bobи вручную управлять действиями атакующего. Можно посмотреть пакет, пропустить его дальше, изменить или повторить. Это позволяет наблюдать непосредственно механику протокола. Для отдельных свойств удобнее автономные сценарии:
./CryptoLab scenario --lab 1 --name <scenario>Каждый такой сценарий фиксирует определённое свойство и автоматически сравнивает фактическое поведение с ожидаемым.
Например:
[PASS] ...
[PASS] ...
[PASS] ...
PASSED 3/3Для студента это воспроизводимый эксперимент. Для меня как разработчика – ещё и своеобразный набор regression checks.
Это оказалось особенно полезно после первых серьёзных изменений приложения. Полный повторный прогон первой лабораторной позволил обнаружить ряд моментов, которые хотелось изменить, и в результате сам CryptoLab был довольно существенно переработан. То есть лабораторный стенд постепенно начал тестировать сам себя.
А что с программированием?
Отказываться от программирования я при этом не собирался. CryptoLab позволяет исследовать уже работающий протокол, но это не отменяет полезности самостоятельной реализации отдельных механизмов. Поэтому лабораторные дополнительно содержат задания на Python 3.10.
При этом я не ставлю перед студентами задачу написать собственную реализацию AES или другого современного криптографического алгоритма. Наоборот, здесь мне кажется более важным другой навык:
уметь правильно использовать готовые криптографические примитивы при построении программ и протоколов.
Для непосредственно криптографических операций используются специализированные библиотеки, а студент реализует окружающую логику.
Это могут быть:
подготовка и преобразование данных;
работа с ключами и параметрами криптографической операции;
формирование сообщений протокола;
проверки полученных данных;
хранение состояния;
обработка ошибок;
реализация отдельных элементов логики протокола.
Таким образом, практическая часть получается двухуровневой. На первом уровне есть готовый CryptoLab. Здесь основная задача – исследовать протокол, провести атаки и понять наблюдаемое поведение системы. На втором уровне студент получает отдельные задачи на Python и уже самостоятельно реализует часть изучаемой логики.
При этом программирование является вариативной частью лабораторной. Основная идея CryptoLab всё-таки заключается именно в экспериментальном исследовании криптографических протоколов.
Что получилось к текущему моменту
На данный момент первая лабораторная уже прошла несколько итераций разработки и дополнительное тестирование. CryptoLab собирается как готовое приложение для: Windows x64 и macOS Apple Silicon. Для работы с самим стендом пользователю не требуется отдельно устанавливать Python, Docker или набор зависимостей. Именно первая лабораторная стала фундаментом всего проекта. На ней появились Alice, Mallory и Bob, интерактивный обмен, автоматические сценарии, модель атакующего и общая логика проведения экспериментов. Поверх этой основы уже можно постепенно строить более сложные лабораторные.
Что дальше
Сейчас готова и вторая лабораторная: «Симметричное шифрование: AES, режимы работы и AEAD». В ней тот же стенд развивается дальше: появляются ECB, CBC, CTR и GCM, PKCS#7 padding, Padding Oracle, nonce reuse, bit flipping и сравнение обычного шифрования с AEAD. Но это уже тема для отдельного материала.
В дальнейшем я планирую постепенно переходить к асимметричной криптографии, обмену ключами, электронной подписи, handshake, TLS и PKI. Общая идея заключается в том, чтобы не делать набор совершенно независимых программ под каждую тему, а постепенно развивать один учебный стенд вместе с усложнением изучаемых протоколов.
Вместо заключения
CryptoLab начинался довольно утилитарно: мне понадобились лабораторные работы для университетской дисциплины. Но по мере разработки мне всё больше нравится сама идея экспериментального подхода к изучению криптографии.
Одно дело прочитать:
изменение ciphertext должно обнаруживаться.
Другое — самостоятельно изменить его в Mallory и увидеть:
AUTHENTICATION FAILED
REJECTОдно дело прочитать:
AEAD не обеспечивает freshness.
Другое – перехватить настоящий корректный пакет, выполнить REPLAY и увидеть, что без дополнительной защиты он может быть принят повторно. Поэтому основную идею проекта я сейчас формулирую так:
Если существует важное правило безопасного использования криптографии, хорошо бы иметь эксперимент, в котором его можно намеренно нарушить и посмотреть, что именно произойдёт.
Проект продолжаю развивать параллельно с курсом.
Видео с демонстрацией отдельных возможностей CryptoLab постепенно выкладываю на YouTube. Более подробное описание проекта, текущие сборки для Windows и macOS и новые версии лабораторных по мере готовности публикую на Boosty.
Буду рад и обратной связи от сообщества.
Особенно интересно мнение тех, кто занимается криптографией, информационной безопасностью или её преподаванием: какие эксперименты вы бы добавили в такой учебный стенд?
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.