Два способа зашифровать запись

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

Шифр , такой как -, AES- или ChaCha20-Poly1305, выполняет обе задачи в одном примитиве. Вы даёте ему открытый текст и некоторые сопутствующие данные, а он возвращает шифртекст плюс тег аутентификации. Расшифровка проверяет тег и данные вместе и завершается неудачей как единая операция, если что-то было изменено.

Шифр выполняет только шифрование. Для целостности набор сочетает его с отдельным , обозначаемым завершающим хешем набора (например, SHA в TLS_RSA_WITH_AES_128_CBC_SHA). Протокол скрепляет две операции вместе, и порядок, в котором они происходят, оказывается чрезвычайно важным.

Почему MAC-then-encrypt пошёл не так

TLS изначально использовал MAC-then-encrypt: вычислить HMAC по открытому тексту, добавить его, дополнить результат до границы блока, а затем зашифровать всё с помощью CBC. Проблема в том, что получатель должен расшифровать и удалить дополнение, прежде чем сможет проверить MAC, поэтому неправильное дополнение и неверный MAC обнаруживаются на разных этапах. Злоумышленник, который видит, на чём запись провалилась — на дополнении или на MAC, через сообщение об ошибке или просто по времени отклика, — узнаёт один бит об открытом тексте за попытку. Повторяясь, этот бит превращается во всё сообщение.

Это padding oracle, и он не теоретический. Череда атак на протяжении лет, включая , Lucky13 и , использовала защиту записей CBC в TLS. Каждую латали всё более деликатным кодом с постоянным временем, но лежащая в основе конструкция продолжала порождать новые варианты. Урок, который извлекла отрасль, — перестать её использовать.

Почему AEAD теперь по умолчанию

AEAD устраняет весь класс проблемы. Нет отдельного этапа дополнения для зондирования и нет отдельного этапа MAC для измерения времени, потому что проверка и расшифровка — это одна операция, которая либо удаётся, либо нет. TLS 1.3 доводит это до завершения и допускает только шифры AEAD; наборы CBC попросту не входят в TLS 1.3. В TLS 1.2 есть оба, и поэтому декодер помечает набор CBC-с-HMAC-SHA1 как слабый, даже когда шифр — AES.

Когда вы видите GCM, CCM или POLY1305 в имени набора, вы смотрите на AEAD. Когда вы видите CBC, вы смотрите на более старую конструкцию, и в современном сервисе это должно быть в лучшем случае запасным вариантом.

Компромисс, которого AEAD всё ещё требует

AEAD не лишён острых углов; он лишь смещает их. Каждому шифрованию AEAD нужен nonce — число, используемое один раз, и безопасность GCM в особенности рушится, если один и тот же nonce когда-либо повторно используется с тем же ключом. TLS управляет nonce за вас счётчиком на каждое соединение, поэтому это скорее опасность для систем, строящих собственное кадрирование, чем для самого TLS, но именно поэтому проекты AEAD так заботятся о построении nonce.

Другой компромисс — длина тега аутентификации. Стандартные наборы GCM и Poly1305 используют 16-байтовый тег. Наборы CCM_8 усекают его до 8 байт, чтобы сэкономить накладные расходы на ограниченных каналах, что измеримо ослабляет целостность. Поэтому TLS_AES_128_CCM_8_SHA256 — настоящий набор AEAD TLS 1.3, который всё же отказывается помечать как рекомендуемый: режим современный, но короткий тег — это компромисс, на который общему интернету идти не нужно.