Криптография
HMAC и MAC
API-ключ в заголовке запроса - как сервер знает, что запрос не подделан? HMAC-SHA256 подписывает запрос секретным ключом: Amazon AWS Signature V4, Stripe webhooks, GitHub webhooks - все используют HMAC. Без MAC атакующий, перехвативший трафик, может модифицировать запросы.
- **AWS Signature V4**: HMAC-SHA256 подписывает каждый API-запрос. Подпись покрывает URL, заголовки, тело и timestamp. Без знания AWS Secret Key невозможно создать валидную подпись.
- **TLS 1.2 MAC**: HMAC-SHA256 защищает каждый TLS-record от модификации. TLS 1.3 перешёл на AEAD (GCM, Poly1305), где MAC встроен в шифр.
- **JWT HS256**: JSON Web Token с HMAC-SHA256. Подписанный токен нельзя модифицировать без знания secret. Проблема: один secret на всех клиентов.
- **5G NAS**: AES-CMAC аутентифицирует сигнальные сообщения между телефоном и сетью. Без MAC атакующий мог бы отправить поддельные команды от имени сети.
MAC vs хэш: в чём разница
Хэш-функция детерминирована и публична - любой может вычислить SHA-256(M). MAC (Message Authentication Code) требует секретного ключа. Только владелец ключа может сгенерировать и проверить тег. MAC обеспечивает аутентификацию - кто прислал сообщение знает ключ.
Наивная конструкция MAC(K, M) = H(K || M) уязвима к length extension атаке: зная H(K || M) можно вычислить H(K || M || extension) без знания K. Поэтому стандартом является HMAC с двумя применениями хэша.
Почему нельзя использовать H(K || M) как MAC вместо HMAC?
HMAC: правильная конструкция MAC
HMAC (RFC 2104, 1996) разработан Беллaре, Канетти и Кравчиком. Два применения хэша с XOR-маскированным ключом устраняют length extension и обеспечивают доказуемую безопасность при случайности хэша.
HMAC используется везде: TLS Record Protocol (integrity), JWT HS256/HS384/HS512, AWS Signature Version 4, SSH MAC, IPsec. В TLS 1.3 HMAC заменён на AEAD (GCM или Poly1305), но HKDF внутри использует HMAC-SHA256.
Почему для проверки HMAC нужно использовать hmac.compare_digest вместо оператора ==?
CMAC: MAC на основе блочного шифра
CMAC (Cipher-based MAC, NIST SP 800-38B) строит MAC из блочного шифра (AES) вместо хэш-функции. Это удобно в аппаратуре, где AES аппаратно ускорен, но нет SHA-NI. CMAC = CBC-MAC с финальным XOR специального подключа.
AES-CMAC используется в LTE и 5G для аутентификации NAS (Non-Access Stratum) сообщений между телефоном и сетевым ядром. IPsec поддерживает AES-CMAC-96 как MAC для ESP пакетов. Это позволяет использовать единственный аппаратный AES-движок для шифрования и аутентификации.
В каком сценарии CMAC предпочтительнее HMAC?
Poly1305: MAC для высокоскоростных систем
Poly1305 разработан Бернштейном в 2005 году. Вычисляет MAC как полином над полем GF(2^130-5): тег = (a1*r^k + a2*r^(k-1) + ... + ak*r + s) mod (2^130-5), где r и s - части одноразового ключа, ai - 16-байтные блоки сообщения.
Poly1305 катастрофически небезопасен при повторном использовании пары (r, s). Если два сообщения использовали одинаковый r, атакующий решает систему линейных уравнений и восстанавливает r. Это фатально. Поэтому r,s всегда генерируются из ChaCha20 с уникальным nonce.
ChaCha20-Poly1305 (RFC 8439) - AEAD из TLS 1.3. Cloudflare, Google, WireGuard используют его как основной шифр. Poly1305 реализуется в несколько умножений на 130-битных числах - в 2-3 раза быстрее HMAC-SHA256 на ARM без SHA-NI.
Почему повторное использование ключа в Poly1305 катастрофично?
Ключевые идеи
- **MAC требует ключ**: в отличие от хэша, MAC невозможно создать или проверить без секретного ключа. H(K||M) наивно - уязвимо к length extension.
- **HMAC**: двойное применение хэша с XOR-маскированным ключом. Доказуемо безопасен. Стандарт для API-подписей, JWT, TLS HKDF.
- **CMAC**: MAC на AES. Идеален для аппаратуры с AES-NI. Используется в 5G и IPsec.
- **Poly1305**: полиномиальный MAC, быстрее HMAC на ARM. Ключ строго одноразовый - повтор раскрывает ключ. Всегда в паре с ChaCha20.
Связанные темы
MAC - строительный блок протоколов и AEAD-схем:
- Хэш-функции — HMAC строится на хэш-функции. Безопасность HMAC зависит от свойств базовой хэш-функции (SHA-256, SHA-384).
- Потоковые шифры — ChaCha20-Poly1305 - AEAD: ChaCha20 шифрует, Poly1305 аутентифицирует. Один из двух обязательных шифров TLS 1.3.
- TLS 1.3 — TLS 1.3 использует HMAC внутри HKDF для key schedule. Для record layer - AEAD (Poly1305 или GCM встроены).
Вопросы для размышления
- JWT по умолчанию использует HS256 (HMAC-SHA256). Какие риски возникают если один секретный ключ используется для всех пользователей?
- WireGuard не использует HMAC - только ChaCha20-Poly1305. Чем это отличается от отдельного MAC и лучше ли это?
- Если сервер использует HMAC для подписи cookie, но проверяет его оператором == (не constant-time), как работает timing-атака?