Проверка целостности получаемых данных

Проверка целостности данных в контексте криптографии означает гарантию того, что полученное сообщение не было изменено в процессе передачи и действительно создано владельцем ключа. В Stanford JavaScript Crypto Library (SJCL) эта задача решается не отдельным механизмом, а встроенной моделью аутентифицированного шифрования и криптографических MAC.

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

Базовые механизмы целостности в SJCL

В библиотеке применяются два основных подхода:

  • HMAC (Hash-based Message Authentication Code)
  • Аутентифицированные режимы шифрования (CCM, OCB)

Каждый из них решает задачу проверки целостности, но на разных уровнях.

HMAC как отдельный слой проверки

HMAC используется, когда данные не шифруются, но требуется гарантировать их неизменность.

В SJCL он реализуется через sjcl.misc.hmac и криптографические хеш-функции, например SHA-256:

const key = sjcl.codec.utf8String.toBits("secret-key");
const hmac = new sjcl.misc.hmac(key, sjcl.hash.sha256);

const data = sjcl.codec.utf8String.toBits("message");
const tag = hmac.encrypt(data);

const valid = sjcl.bitArray.equal(
    tag,
    hmac.encrypt(data)
);

Особенности проверки

  • результат HMAC — это битовый массив (bitArray)
  • сравнение выполняется через sjcl.bitArray.equal
  • любое изменение данных приводит к полностью другому тегу

HMAC применяется, когда шифрование не требуется, но нужна защита от подмены (например, для API-запросов или подписанных сообщений).

Аутентифицированное шифрование CCM

На практике чаще используется режим CCM (Counter with CBC-MAC), который объединяет шифрование и проверку целостности в одном процессе.

В SJCL это реализовано через sjcl.mode.ccm.

Пример шифрования и автоматической проверки целостности

const key = sjcl.codec.utf8String.toBits("encryption-key");
const iv = sjcl.random.randomWords(4, 0);

const plaintext = "confidential data";

const encrypted = sjcl.encrypt(key, plaintext, {
    mode: "ccm",
    iv: iv,
    ts: 64
});

Здесь ts (tag size) определяет размер аутентификационного тега в битах.

Проверка целостности при расшифровке

Главная особенность SJCL заключается в том, что проверка целостности выполняется автоматически при расшифровке.

const decrypted = sjcl.decrypt(key, encrypted);

Если данные были изменены хотя бы на один бит, происходит одно из двух:

  • выбрасывается исключение
  • расшифровка завершается ошибкой аутентификации

Это означает, что результат не просто “неправильный текст”, а полностью недоверенные данные.

Что именно проверяется

Аутентифицированные режимы проверяют:

  • целостность зашифрованного текста
  • корректность IV (вектора инициализации)
  • соответствие аутентификационного тега
  • неизменность дополнительных параметров (AAD, если используется)

Любое расхождение делает данные недействительными.

Роль bitArray в контроле целостности

SJCL оперирует не строками, а бинарным форматом bitArray. Это важно, поскольку криптографические операции чувствительны к побитовым изменениям.

const a = sjcl.codec.utf8String.toBits("abc");
const b = sjcl.codec.utf8String.toBits("abc");

sjcl.bitArray.equal(a, b); // true

При малейшем изменении:

const c = sjcl.codec.utf8String.toBits("abd");

sjcl.bitArray.equal(a, c); // false

Такой подход исключает ошибки, связанные с кодировками или строковыми преобразованиями.

Проверка целостности через ручной HMAC

В системах, где требуется явное управление процессом, HMAC используется отдельно от шифрования.

Формирование подписи

const key = sjcl.codec.utf8String.toBits("auth-key");
const hmac = new sjcl.misc.hmac(key, sjcl.hash.sha256);

const message = sjcl.codec.utf8String.toBits("important message");
const signature = hmac.encrypt(message);

Проверка подписи

const incomingMessage = sjcl.codec.utf8String.toBits("important message");
const incomingSignature = signature;

const computed = hmac.encrypt(incomingMessage);

const isValid = sjcl.bitArray.equal(computed, incomingSignature);

Если сообщение изменено:

const tampered = sjcl.codec.utf8String.toBits("important messagE");

sjcl.bitArray.equal(
    hmac.encrypt(tampered),
    signature
); // false

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

В режимах типа CCM возможно добавление дополнительных аутентифицируемых данных, которые не шифруются, но участвуют в проверке целостности.

const encrypted = sjcl.encrypt(key, plaintext, {
    mode: "ccm",
    iv: iv,
    adata: "header-data"
});

Эти данные:

  • не скрываются
  • но защищаются от изменения
  • проверяются при расшифровке

Изменение adata делает сообщение недействительным.

Ошибки целостности и их поведение

При нарушении целостности SJCL не пытается “исправить” данные. Поведение строгое:

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

Это критично для защиты от атак типа:

  • bit-flipping
  • replay attacks (в связке с корректным использованием IV)
  • подмена ciphertext

Типичная схема проверки целостности

В реальных приложениях используется следующая логика:

  1. Получение зашифрованного сообщения
  2. Передача в sjcl.decrypt
  3. Автоматическая проверка тега
  4. Либо получение данных, либо ошибка
try {
    const data = sjcl.decrypt(key, payload);
} catch (e) {
    // данные повреждены или подделаны
}

Взаимосвязь шифрования и целостности

В SJCL эти две задачи не разделяются в современных режимах. Это принципиально:

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

Особенно это важно в CCM:

  • один процесс шифрует данные
  • он же формирует тег
  • он же проверяет тег при расшифровке

Практическое значение модели SJCL

Такой подход делает невозможными целые классы ошибок:

  • забытая проверка подписи
  • несоответствие HMAC и ciphertext
  • неправильное сравнение строк вместо битов
  • ручная ошибка при сериализации

Целостность в SJCL — это не дополнительный слой, а встроенное свойство криптографической операции, зависящее от корректности ключа и параметров режима.