01.09.2026

Закрытый .NET крипто-шлюз → Java в Kubernetes за 11 часов

Реверс вендорского крипто-шлюза без документации и замена его на свою Java-реализацию силами ИИ-агентов: байт-в-байт совместимая подпись, реплей боевого трафика 48/48, независимое ревью и боевое переключение с готовым откатом.

  • ИИ-агенты
  • реверс
  • ГОСТ-крипто
  • Java
  • Kubernetes

Задача

В проде финтех-компании жил один компонент, который держал всю инфраструктуру на Windows-сервере: вендорский крипто-шлюз SSLGateNet — закрытое .NET-приложение, работающее только через Windows CAPI. Через него приложение КРЕ ходит во внешние системы: шлюз поднимает ГОСТ-TLS и подписывает запросы ГОСТ-подписью. Пока жив этот .exe — жив и Windows-сервер.

Задача: написать свой шлюз на Java, который слушает тот же порт, говорит тем же бинарным протоколом и делает то же самое — но на Linux. От постановки задачи до боевого переключения прошло ~11 часов активной работы; доводка продолжалась ещё несколько дней после.

Почему нельзя было «просто»

  • Протокол нигде не документирован. Его пришлось восстанавливать по бинарям: декомпиляция серверного .NET-кода и разбор байткода клиентской части из вендорского приложения.
  • Клиента не перепишешь. В КРЕ режима «без шлюза» физически нет, патчить вендорское приложение — тупик. Единственный путь — свой сервер, который клиент не отличит от родного.
  • Крипто должно совпадать байт-в-байт. Подпись — не «похожая», а такая, которую принимает принимающая сторона. Формат оказался сложнее, чем выглядел: подпись считается над подписанными атрибутами, и совместимость упёрлась в детали DER-кодирования, которые не описаны нигде.

Реализовано 6 опкодов протокола — ровно те, которыми пользуется живой контур. Остальные осознанно отвечают ошибкой: вызывающих их систем в контуре нет.

Как работали агенты

Работа шла не одним агентом, а несколькими — с разными правами и, что важнее, разными источниками истины:

  • Протокол-археолог отвечает на вопрос «как это устроено в оригинале» по декомпиляции и байткоду — и не имеет права переписать код под свой ответ.
  • Крипто-инженер пишет код: подпись, ГОСТ-TLS, контейнеры ключей.
  • Тестер совместимости гоняет настоящий вендорский клиент против обеих реализаций — старой и новой — и сравнивает поведение. Меряет чужим клиентом, а не нашими ожиданиями.
  • Ревьюер ищет ошибки корректности и безопасности — и не имеет права чинить то, что нашёл.

Разделение — не про «разные модели умеют разное». Оно про то, чтобы ни один агент не проверял сам себя.

Система доказательств

Ключевое в этом кейсе: почти на каждом шаге был способ узнать правду, не спрашивая агента. Три внешних источника истины:

  • Чужой клиент. Вендорский клиентский класс запускается как есть и натравливается на наш сервер. Тест писал не я — тест уже был написан вендором и работал годами. Это самый строгий из возможных тестов: ровно тот код, который пойдёт в прод.
  • Чужой сервер. Боевой шлюз умеет проверять подписи. Нашу подпись можно отдать на проверку тому, кого мы заменяем, — и вендорский verify её принял. Именно так подтвердилась байт-в-байт совместимость.
  • Боевой трафик. Пассивный захват трафика в проде дал 48 записанных пар «настоящий запрос → настоящий ответ». Реплей всех 48 против новой реализации — главный регрессионный тест: 48/48. Синтетические тесты проверяют то, что ты придумал; записанный трафик проверяет то, что бывает.

Отсюда главный вывод кейса: агентская разработка едет ровно настолько, насколько удаётся построить внешний автоматический критерий правоты — оракул. Реверс протокола с живым эталоном рядом — идеальный для этого случай, и этим объясняется, почему «месяцы» сжались в часы.

Независимое ревью

Перед боевым переключением весь код прошёл отдельное ревью — другим агентом, с явной установкой искать плохое. Результат: 0 critical, 2 high — обе исправлены до переключения (лимиты на входные данные против DoS и корректный выбор подписанта при проверке подписи).

Честная оговорка, без которой это была бы реклама: обе high-находки не были найдены тестами — все тесты были зелёными. Их нашло чтение кода, потому что ошибки жили в том, чего в записанном трафике не оказалось. Оракул отвечает на вопрос «совпадаю ли я с эталоном на наблюдавшихся входах» — на вопрос «что будет на входе, которого я не видел» он не отвечает. Скорость дал оракул; безопасность выхода в прод дало ревью.

Переключение с откатом

Новый шлюз развёрнут отдельным деплойментом в Kubernetes. Переключение — смена одного адреса в настройках КРЕ; старый маршрут остался жив как мгновенный откат. Финальная проверка перед переключением — настоящим вендорским клиентом по сети, изнутри кластера. После переключения боевой трафик пошёл через новую реализацию.

Если у вас в контуре сидит похожий компонент — закрытый, без документации, держащий на себе платформу, с которой давно пора уехать, — напишите: расскажу, как мы это делали и с чего начать у вас.