Перейти к содержимому

Iso 9797-1 Mac: как читать стандарт и не ошибиться в padding и финальной итерации

ISO 9797-1: "поросячья латынь" криптографа поневоле

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

И всё же бывают задачи, которые не закрыть ни промптом, ни поверхностным пересказом. Нужно понять, как именно стандарт собирает MAC, где у него тонкие места, как соотносятся методы дополнения данных и "варианты" финального шага. Ниже - аккуратно пересобранное объяснение базовой логики ISO 9797-1: от общей схемы до финальной итерации, без попыток изображать академический учебник. Если хочется сверять формулировки и обозначения, удобно держать под рукой разбор ISO 9797-1 MAC реализации - так легче сопоставлять шаги и термины.

---

Общий "каркас" алгоритмов MAC в ISO 9797-1

В ISO 9797-1 семейство алгоритмов выработки имитовставки (MAC) построено по одному шаблону. Детали меняются (ключи, финальная итерация, пост-обработка), но скелет почти всегда одинаковый и удобно мыслить им как конвейером из нескольких стадий:

1) Деривация ключей (key derivation) - из исходного секретного материала получаются ключи K1/K2 (иногда дополнительно K3).
2) Дополнение сообщения (padding) - приведение длины входных данных к кратности размеру блока.
3) Разбиение (splitting) - сообщение режется на блоки D1...Dq одинаковой длины.
4) Итеративное поблочное шифрование - по сути, цепочка, очень похожая на CBC.
5) Финальная итерация (final iteration) - отдельное правило обработки последнего блока.
6) Выходное преобразование (output transformation) - дополнительная функция над результатом.
7) Усечение (truncation) - MAC при необходимости сокращается до нужного размера.

В практическом контексте нередко подразумевается блочный шифр DES (исторически он часто фигурирует в совместимых профилях). У DES блок 8 байт - значит, вход должен быть кратен 8. Если пришло 24 байта, они превращаются в три блока по 8: D1, D2, D3. Дальше - классическая цепочка: первый блок XOR'ится с нулевым IV (вектором из 8 нулей), шифруется ключом, результат становится "IV" для следующего блока и так далее. Это узнаваемая механика CBC и именно она обычно помогает не утонуть в обозначениях при разработке.

---

Padding: четыре способа запутаться и один способ не ошибиться

Самая частая боль - не "криптография", а выравнивание данных. Вроде бы мелочь: где ставить 0x80, когда добавлять нули, что делать, если сообщение и так кратно блоку. В ISO 9797-1 определены четыре метода дополнения:

Метод 1. Нулевое дополнение справа (0x00...0x00).
Добавляем справа столько нулей, сколько нужно, чтобы длина стала кратной размеру блока. Если длина уже кратна - не добавляется ничего.

Метод 2. 0x80 и затем нули.
Справа всегда добавляется байт 0x80, а затем - нули до кратности блоку. Ключевой момент: 0x80 вставляется даже тогда, когда исходные данные уже выровнены.
Пример логики:
- было 7 байт → дополняем одним байтом 0x80 и получаем 8;
- было 8 байт → всё равно добавляем 0x80 и добиваем нулями до следующих 8 байт (то есть до 16).

Метод 3. Счётчик бит слева + нули справа.
Здесь появляется "неожиданность": слева добавляется отдельный 8-байтовый блок, в котором записано количество бит исходного сообщения, а справа - нули до кратности.
Если сообщение 7 байт, это 56 бит (0x38). Тогда слева будет блок `00 00 00 00 00 00 00 38`, а справа - нулевое дополнение, чтобы всё сложилось по 8 байт.

Метод 4. Почти как метод 2, но с оговоркой.
Он повторяет идею "0x80 + нули", однако если данные уже выровнены по блоку, то этот метод фактически не применяется (то есть дополнительный блок не появляется). Именно эта оговорка часто становится причиной несовпадения MAC при переносе реализации между библиотеками.

---

Шаги 3-4: разбиение и "почти CBC"

После padding сообщение режется на блоки D1...Dq. Дальше запускается итеративная часть: каждый блок смешивается XOR'ом с предыдущим состоянием (Hq-1), а затем прогоняется через блочный шифр `e`. Если держать в голове CBC, становится проще: "состояние" - это по сути цепочка, которая копится от блока к блоку.

---

Финальная итерация: где различаются варианты и ключи

Финальный шаг выполняется над последним блоком Dq и даёт выходной блок Hq. В ISO 9797-1 предусмотрены типовые варианты:

- Вариант A: `Hq = eK1(Dq XOR Hq-1)` - последний блок шифруется тем же ключом.
- Вариант B: `Hq = eK2(Dq XOR Hq-1)` - в финале используется другой ключ.
- Вариант C (с маскированием): `Hq = eK1(Dq XOR Hq-1 XOR K2)` - перед шифрованием добавляется маскирующий ключ.

Есть и особое правило: если выбран padding method 4 и при этом исходная строка не кратна блоку, тогда вместо K2 в маскировании используется K3:
`Hq = eK1(Dq XOR Hq-1 XOR K3)`.

На практике именно этот "угол" и ломает совместимость: разработчик честно делает 0x80, честно считает CBC, но не учитывает, что для конкретного сочетания padding и длины сообщения стандарт переключает маскирующий ключ.

---

Выходное преобразование и усечение: почему MAC "не обязан" быть длиной блока

После финальной итерации стандарт допускает дополнительную функцию `g` (output transformation). В одних профилях это просто тождественное преобразование, в других - ещё один прогон шифра или перестановка/комбинация, зависящая от выбранного MAC algorithm (в ISO 9797-1 описаны MAC algorithm 1-4, и они как раз отличаются тем, что делают вокруг финала и выхода).

Затем применяется усечение `trunc`: имитовставка может быть короче блока (например, 4 или 8 байт), и это нормальная практика для протоколов, где экономят место. Но тут важно помнить: сокращение снижает стойкость к перебору, поэтому длину MAC выбирают осознанно, а не "как в примере попалось".

---

Что важно для реализации: "мелочи", которые решают всё

Первое правило имплементации - фиксировать договорённости: padding-метод, вариант финальной итерации, размер усечения, порядок байт в счётчике бит (для метода 3), а также то, как именно получаются K1/K2/K3. В разных экосистемах (карточные протоколы, банковские HSM, легаси на DES/3DES) эти параметры могут быть "по умолчанию", но в коде лучше не оставлять место догадкам.

Второе правило - тестовые векторы. Если их нет, их нужно сделать самим: взять несколько сообщений (0 байт, 1 байт, 7 байт, ровно 8 байт, 9 байт), прогнать через реализацию и зафиксировать результаты. В дальнейшем это спасает при миграции на другую библиотеку или при переносе на другой язык.

---

Почему стандарт до сих пор всплывает в индустрии

Хотя многие современные системы уходят в сторону CMAC/GMAC и новых режимов, внедрение ISO 9797-1 в платежных системах по-прежнему встречается из‑за наследуемости: терминалы, процессинги, интеграции с HSM и старые профили протоколов десятилетиями опирались на семейство MAC по ISO 9797-1. В таких местах "правильно" часто означает "совместимо с тем, что уже стоит и сертифицировано".

Отсюда же вытекает отдельная дисциплина - аудит и сертификация криптографии ISO 9797-1. Проверяют не только корректность формул, но и то, как устроено управление ключами, где выполняются операции (внутри защищённого модуля или в приложении), как логируются ошибки, нет ли утечек через тайминги и различимые коды возврата.

---

Практический вопрос: где взять документ и как не утонуть в нюансах

Если в проекте нужен официальный текст, иногда приходится решать приземлённую задачу: ISO 9797-1 купить стандарт в легальном виде, чтобы команда работала с точными формулировками, а не с пересказами и фрагментами. Это особенно актуально, когда реализация идёт под комплаенс и дальнейшие проверки.

А если сроки горят и нужна внятная дорожная карта (какой padding выбрать, как согласовать параметры с другой стороной, как сверить результаты с HSM), обычно помогает консультация по ISO 9797-1 и MAC алгоритмам: в таких задачах цена ошибки - неделя отладки "почему MAC не сходится на одном байте". В качестве ориентира по терминологии и шагам удобно также держать в поле зрения практический разбор ISO 9797-1 MAC реализации - он дисциплинирует и не даёт перепутать методы дополнения и условия применения K2/K3.

---

Итог: "поросячья латынь" становится схемой

ISO 9797-1 пугает не математикой, а плотностью деталей: четыре padding-метода, разные ключи на финале, маскирование, опциональная пост-обработка и усечение. Но если разложить стандарт на конвейер из шагов и отдельно зафиксировать "развилки" (padding и финальная итерация), текст перестаёт быть магией и превращается в инженерную спецификацию, которую реально реализовать и - что важнее - проверить на совместимость.

Scroll to Top