AES-GCM: аутентифицированное шифрование, тег аутентификации, nonce

AES-GCM относится к режимам аутентифицированного шифрования (AEAD — Authenticated Encryption with Associated Data), в которых одновременно обеспечивается конфиденциальность данных и их целостность. В контексте Web Crypto API этот режим реализуется через алгоритм AES с режимом Galois/Counter Mode, доступный через интерфейс SubtleCrypto.

Классическое шифрование решает задачу сокрытия содержимого, но не защищает от незаметной модификации зашифрованного текста. AES-GCM устраняет этот недостаток за счёт встроенного механизма аутентификации:

  • шифрование выполняется в режиме счётчика (CTR-подобная схема);
  • параллельно вычисляется аутентификационный тег (authentication tag);
  • при расшифровке проверяется целостность данных и дополнительных параметров.

Если данные были изменены, расшифровка завершится ошибкой ещё до получения результата.

Базовый интерфейс Web Crypto API

Работа с AES-GCM в браузере осуществляется через объект:

crypto.subtle

Основные методы:

  • generateKey
  • encrypt
  • decrypt
  • importKey
  • exportKey

Генерация ключа AES-GCM

Ключ создаётся через generateKey:

const key = await crypto.subtle.generateKey(
  {
    name: "AES-GCM",
    length: 256
  },
  true,
  ["encrypt", "decrypt"]
);

Параметры:

  • name: всегда "AES-GCM"
  • length: 128, 192 или 256 бит
  • extractable: возможность извлечения ключа
  • keyUsages: операции с ключом

Роль nonce (IV)

Nonce (Number used once), он же IV (Initialization Vector), является критически важным элементом AES-GCM.

В Web Crypto API он передаётся как iv:

const iv = crypto.getRandomValues(new Uint8Array(12));

Свойства nonce в AES-GCM:

  • должен быть уникальным для каждого шифрования с одним ключом
  • обычно имеет длину 12 байт (96 бит)
  • повторное использование с тем же ключом полностью компрометирует безопасность
  • не обязан быть секретным

Почему 12 байт

AES-GCM оптимизирован под 96-битный nonce, что позволяет:

  • упростить вычисления внутреннего счётчика
  • повысить производительность
  • минимизировать вероятность коллизий

Шифрование данных

Шифрование выполняется через encrypt:

const encoded = new TextEncoder().encode("секретное сообщение");

const ciphertext = await crypto.subtle.encrypt(
  {
    name: "AES-GCM",
    iv: iv
  },
  key,
  encoded
);

Результат ciphertext — это ArrayBuffer, содержащий:

  • зашифрованные данные
  • аутентификационный тег (встроенный в конец результата)

Аутентификационный тег

Аутентификационный тег обеспечивает проверку целостности и подлинности данных.

В AES-GCM:

  • тег генерируется автоматически
  • обычно имеет длину 128 бит (16 байт)
  • хранится совместно с ciphertext
  • проверяется при расшифровке

Если хотя бы один бит данных изменён, проверка тега проваливается.

Дополнительные аутентифицированные данные (AAD)

AES-GCM поддерживает механизм AAD (Additional Authenticated Data). Эти данные:

  • не шифруются
  • участвуют в расчёте аутентификационного тега
  • защищены от изменения

Пример использования:

const additionalData = new TextEncoder().encode("header-info");

Шифрование с AAD:

const ciphertext = await crypto.subtle.encrypt(
  {
    name: "AES-GCM",
    iv: iv,
    additionalData: additionalData
  },
  key,
  encoded
);

AAD часто используется для:

  • заголовков протоколов
  • метаданных сообщений
  • идентификаторов сессий

Длина тега (tagLength)

В Web Crypto API можно задать длину тега:

{
  name: "AES-GCM",
  iv: iv,
  tagLength: 128
}

Особенности:

  • значение задаётся в битах
  • допустимые значения: 32, 64, 96, 104, 112, 120, 128
  • на практике почти всегда используется 128 бит

Расшифровка данных

Расшифровка выполняется через decrypt:

const decrypted = await crypto.subtle.decrypt(
  {
    name: "AES-GCM",
    iv: iv
  },
  key,
  ciphertext
);

const decoded = new TextDecoder().decode(decrypted);

Ключевые моменты:

  • необходимо использовать тот же IV
  • используется тот же ключ
  • если тег не проходит проверку, возникает исключение OperationError

Структура данных AES-GCM в Web Crypto API

В отличие от некоторых низкоуровневых реализаций, Web Crypto API:

  • не разделяет ciphertext и tag вручную
  • возвращает единый буфер
  • выполняет проверку целостности автоматически

Внутренне структура выглядит как:

[ciphertext || authentication tag]

Критические требования безопасности

Уникальность nonce

Повторное использование nonce с тем же ключом приводит к:

  • раскрытию XOR зависимости между сообщениями
  • возможности восстановления исходного текста
  • полной компрометации ключа в некоторых сценариях

Длина ключа

Рекомендуется использовать:

  • 256-битные ключи для максимальной стойкости

Защита AAD

AAD не скрывается, но:

  • любое изменение приводит к ошибке расшифровки
  • позволяет привязывать контекст к зашифрованным данным

Особенности реализации в браузере

Web Crypto API накладывает ряд ограничений:

  • ключи не могут быть извлечены, если extractable: false
  • операции выполняются асинхронно
  • доступ к API возможен только в безопасных контекстах (HTTPS)

Типичные ошибки при использовании AES-GCM

Повтор nonce

Самая критическая ошибка:

const iv = new Uint8Array(12); // ПЛОХО: фиксированный IV

Игнорирование ошибок decrypt

try {
  await crypto.subtle.decrypt(...);
} catch (e) {
  // ошибка целостности или неверный ключ
}

Несовпадение параметров

Любое несоответствие:

  • IV
  • AAD
  • tagLength
  • ключа

приводит к невозможности расшифровки.

Практическая модель работы AES-GCM

  1. Генерация ключа AES
  2. Создание уникального nonce
  3. Подготовка данных и AAD
  4. Шифрование (encrypt)
  5. Передача ciphertext + IV + (опционально AAD)
  6. Расшифровка (decrypt)
  7. Проверка целостности через authentication tag

AES-GCM в Web Crypto API объединяет криптографическую стойкость AES и механизм аутентификации Galois Field, обеспечивая защищённый обмен данными без необходимости отдельно реализовывать контроль целостности.