Верификация источника зашифрованного сообщения

Шифрование само по себе не гарантирует, что сообщение было отправлено именно ожидаемым источником или что оно не было изменено в процессе передачи. Для решения этих задач применяются механизмы аутентификации и проверки целостности. В библиотеке SJCL эти аспекты реализуются через комбинацию криптографических примитивов: HMAC, режимы аутентифицированного шифрования и проверка тегов подлинности.


Проблема подмены источника

При передаче зашифрованных данных возможны следующие атаки:

  • Подмена отправителя — злоумышленник отправляет сообщение, выдавая себя за доверенную сторону
  • Модификация данных — изменение содержимого без возможности обнаружения
  • Повторная отправка (replay attack) — повтор уже перехваченного сообщения

Шифрование (например, AES) скрывает содержимое, но не предотвращает такие атаки. Поэтому используется дополнительный слой — криптографическая аутентификация.


HMAC как средство проверки источника

SJCL предоставляет реализацию HMAC (Hash-based Message Authentication Code), которая позволяет убедиться, что сообщение:

  1. Было создано стороной, обладающей секретным ключом
  2. Не было изменено после создания

Принцип работы

  • Отправитель вычисляет HMAC от сообщения с использованием секретного ключа
  • Получатель выполняет ту же операцию и сравнивает результат

Если значения совпадают — сообщение считается подлинным

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

var key = sjcl.codec.utf8String.toBits("secret-key");
var message = "Important data";

var hmac = new sjcl.misc.hmac(key, sjcl.hash.sha256);
var mac = hmac.encrypt(message);

Проверка:

var hmacVerify = new sjcl.misc.hmac(key, sjcl.hash.sha256);
var macCheck = hmacVerify.encrypt(message);

if (sjcl.bitArray.equal(mac, macCheck)) {
    console.log("Сообщение подлинное");
}

Аутентифицированное шифрование (AEAD)

Современный подход — объединение шифрования и аутентификации. SJCL поддерживает режимы, обеспечивающие оба свойства одновременно.

Режим CCM (Counter with CBC-MAC)

SJCL использует AES-CCM как основной режим аутентифицированного шифрования.

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

  • Шифрование и проверка целостности в одном процессе
  • Генерация authentication tag (тега подлинности)
  • Обнаружение любых изменений в зашифрованных данных

Пример

var password = "strong-password";
var plaintext = "Sensitive message";

var encrypted = sjcl.encrypt(password, plaintext);

Результат содержит:

  • ciphertext (зашифрованные данные)
  • salt
  • iv
  • tag (аутентификационный тег)

Расшифровка автоматически включает проверку:

try {
    var decrypted = sjcl.decrypt(password, encrypted);
    console.log("Сообщение корректно:", decrypted);
} catch (e) {
    console.log("Ошибка аутентификации или повреждение данных");
}

Проверка источника через ключи

Аутентификация напрямую зависит от управления ключами:

  • Симметричная схема: общий секретный ключ у отправителя и получателя
  • Ассиметричная схема (вне SJCL): подписи с использованием приватного ключа

В контексте SJCL чаще используется симметричная модель, где:

  • ключ известен только доверенным сторонам
  • злоумышленник не может корректно сгенерировать HMAC или тег

Использование дополнительных данных (AAD)

В режиме CCM можно включать дополнительные аутентифицируемые данные (Additional Authenticated Data):

  • не шифруются
  • но участвуют в вычислении тега

Это позволяет защищать метаданные:

var adata = sjcl.codec.utf8String.toBits("header-data");

var encrypted = sjcl.mode.ccm.encrypt(
    new sjcl.cipher.aes(key),
    plaintextBits,
    iv,
    adata,
    128
);

Любое изменение AAD приведёт к ошибке проверки.


Защита от повторных атак

Для предотвращения повторной отправки сообщений применяются:

  • уникальные IV (инициализационные векторы)
  • временные метки
  • счётчики сообщений

SJCL требует уникальности IV в режиме CCM:

var iv = sjcl.random.randomWords(3, 0);

Повторное использование IV с тем же ключом нарушает безопасность.


Типичные ошибки при верификации

Игнорирование проверки тега

Некоторые реализации расшифровывают данные без проверки:

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

SJCL автоматически выбрасывает исключение — это поведение нельзя игнорировать


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

Сравнение MAC через обычные операции (==) может привести к атаке по времени выполнения.

Правильный способ:

sjcl.bitArray.equal(a, b);

Повторное использование ключей и IV

  • одинаковый ключ + IV = уязвимость
  • возможна утечка информации

Архитектура безопасной передачи

Полноценная схема выглядит так:

  1. Генерация случайного IV

  2. Шифрование сообщения (AES-CCM)

  3. Добавление AAD (при необходимости)

  4. Передача: ciphertext + IV + tag

  5. Получатель:

    • проверяет тег
    • расшифровывает данные

Комбинирование HMAC и шифрования

Иногда используется схема:

  • Encrypt-then-MAC

В SJCL это можно реализовать вручную:

var ciphertext = sjcl.encrypt(password, message);

var hmac = new sjcl.misc.hmac(key, sjcl.hash.sha256);
var mac = hmac.encrypt(ciphertext);

Получатель:

  1. Проверяет MAC
  2. Только потом расшифровывает

Роль энтропии в аутентификации

Надёжность проверки источника напрямую зависит от:

  • качества ключа
  • случайности IV

SJCL использует встроенный генератор:

sjcl.random.startCollectors();

Недостаток энтропии снижает устойчивость ко всем видам атак.


Практические рекомендации

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

Верификация как обязательный этап

Любое зашифрованное сообщение должно проходить проверку:

  • источник известен и доверен
  • данные не изменялись
  • сообщение актуально

Без этих гарантий шифрование теряет смысл, превращаясь лишь в средство сокрытия, но не защиты.