Работа с дополнительными аутентифицированными данными (AAD)

Дополнительные аутентифицированные данные (AAD) — это часть входных данных в схемах аутентифицированного шифрования, которая не подвергается шифрованию, но включается в вычисление тега целостности (authentication tag).

Ключевое свойство AAD:

  • данные остаются в открытом виде
  • любые изменения AAD приводят к ошибке проверки целостности
  • AAD защищает структуру и контекст сообщения, но не его содержимое

В схемах AEAD (Authenticated Encryption with Associated Data) AAD играет роль связующего контекста между шифротекстом и внешними параметрами системы: заголовками сообщений, метаданными, идентификаторами сессий.


Роль AAD в AEAD-шифровании

AEAD объединяет две операции:

  • шифрование (confidentiality)
  • аутентификация (integrity + authenticity)

AAD участвует только во второй части.

Формально модель выглядит так:

  • вход: plaintext + key + nonce + AAD
  • выход: ciphertext + authTag

AAD входит в вычисление authTag, но не влияет на ciphertext.

Это означает:

  • изменение AAD → тег становится невалидным
  • изменение ciphertext → тег также становится невалидным
  • AAD можно хранить/передавать отдельно

AAD в контексте SJCL

Stanford Javascript Crypto Library реализует аутентифицированное шифрование через режимы, в первую очередь CCM (Counter with CBC-MAC).

В SJCL AAD задаётся через параметр:

  • adata (associated data)

Он используется как часть входа в MAC (Message Authentication Code), но не шифруется.


Использование AAD в SJCL API

Основной API шифрования:

sjcl.encrypt(password, data, options)

Параметр options может содержать:

  • mode — режим шифрования (например, “ccm”)
  • iv — вектор инициализации (nonce)
  • iter — количество итераций KDF
  • salt — соль
  • adata — дополнительные аутентифицированные данные

Пример базовой структуры:

const encrypted = sjcl.encrypt("secretPassword", "Sensitive message", {
  mode: "ccm",
  adata: "header-information"
});

Что именно попадает в adata

AAD в SJCL — это строка или сериализуемые данные, которые:

  • добавляются в MAC
  • не включаются в ciphertext
  • должны быть идентичны при расшифровке

Типичные примеры AAD:

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

Пример структуры защищённого сообщения

Рассмотрим сценарий обмена сообщениями:

const message = "transfer 1000 coins";

const encrypted = sjcl.encrypt("key123", message, {
  mode: "ccm",
  adata: JSON.stringify({
    userId: 42,
    type: "transaction",
    version: 1
  })
});

Здесь:

  • "transfer 1000 coins" — шифруется
  • JSON объект — участвует только в аутентификации

Расшифрование с AAD

При расшифровании AAD должен быть идентичным побитово:

const decrypted = sjcl.decrypt("key123", encrypted, {
  mode: "ccm",
  adata: JSON.stringify({
    userId: 42,
    type: "transaction",
    version: 1
  })
});

Если изменить хотя бы один символ:

adata: '{"userId":43,"type":"transaction","version":1}'

результат:

  • ошибка аутентификации
  • невозможность расшифровки

Внутренний механизм: CCM и AAD

CCM mode (Counter with CBC-MAC) реализует AAD через CBC-MAC.

Процесс вычисления:

  1. AAD разбивается на блоки

  2. включается в CBC-MAC до обработки plaintext

  3. затем добавляется ciphertext (в режиме счётчика)

  4. итоговый MAC зависит от:

    • ключа
    • nonce
    • AAD
    • ciphertext

Важно:

  • AAD не шифруется
  • AAD влияет на MAC до шифрования данных

Формат хранения AAD в SJCL

Внутри SJCL AAD сериализуется в строку и включается в структуру параметров:

{
  "iv": "...",
  "v": 1,
  "iter": 10000,
  "ks": 128,
  "ts": 64,
  "mode": "ccm",
  "adata": "..."
}

AAD хранится вместе с зашифрованным текстом, но логически отделён.


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

SJCL работает с AAD как с:

  • строкой
  • JSON-строкой
  • произвольным текстом

Однако важное свойство:

  • никакой нормализации не выполняется автоматически

Это означает:

  • пробелы значимы
  • порядок JSON полей значим
  • кодировка UTF-8 должна быть стабильной

Практическая роль AAD в протоколах

AAD используется для защиты контекста, который нельзя подделать без ключа.

1. Защита заголовков

adata: "msg-type:payment"

Любая подмена типа сообщения делает ciphertext недействительным.


2. Защита идентификаторов

adata: JSON.stringify({
  sessionId: "A1B2C3"
})

Если ciphertext переносят между сессиями — проверка проваливается.


3. Защита версии протокола

adata: "protocol:v3"

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


Ошибки при работе с AAD

Несовпадение сериализации

JSON.stringify({a:1, b:2})
JSON.stringify({b:2, a:1})

Результат:

  • разные строки
  • разные MAC
  • расшифровка невозможна

Изменение whitespace

"data"
" data "

Даже пробел критичен.


Использование нестабильных структур

Объекты JavaScript с нефиксированным порядком ключей приводят к ошибкам.


Рекомендации по стабильному AAD

Для корректной работы AAD в SJCL применяются строгие принципы сериализации:

  • фиксированный порядок ключей JSON
  • отсутствие лишних пробелов
  • детерминированное кодирование

Пример стабильного подхода:

function stableStringify(obj) {
  const sorted = {};
  Object.keys(obj).sort().forEach(k => sorted[k] = obj[k]);
  return JSON.stringify(sorted);
}

AAD и безопасность архитектуры

AAD позволяет отделить:

  • секретные данные (ciphertext)
  • контекст (AAD)

Это даёт архитектурные преимущества:

  • проверка целостности метаданных
  • защита от подмены контекста
  • предотвращение replay- и substitution-атак

Использование AAD в сложных структурах сообщений

Пример комбинированного сообщения:

const payload = {
  user: 1001,
  permissions: ["read", "write"],
  timestamp: Date.now()
};

const encrypted = sjcl.encrypt("key", "payload-data", {
  mode: "ccm",
  adata: JSON.stringify(payload)
});

Здесь AAD фиксирует:

  • идентичность пользователя
  • права доступа
  • момент времени

Ограничения AAD в SJCL

  • отсутствие встроенной нормализации JSON
  • ручное управление сериализацией
  • зависимость от режима CCM (в классической конфигурации)
  • необходимость строгой согласованности на обеих сторонах

Взаимодействие AAD и ключевого деривационного слоя

AAD не участвует в KDF (Key Derivation Function), но влияет на:

  • итоговую проверку аутентичности
  • валидность дешифрования

В SJCL ключ генерируется отдельно через PBKDF2:

  • password + salt → key
  • AAD применяется позже, на этапе MAC

Ошибки архитектурного уровня

Частая ошибка — попытка использовать AAD как скрытый канал данных.

AAD:

  • не шифруется
  • видим в ciphertext-структуре
  • не предназначен для секретности

Он предназначен только для:

  • проверки целостности
  • привязки контекста

Итоговая модель поведения AAD в SJCL

  • входит в MAC
  • не входит в шифротекст
  • должен совпадать при шифровании и расшифровании
  • чувствителен к любым изменениям байтов
  • требует детерминированной сериализации