AES-CBC: алгоритм, вектор инициализации, паддинг

AES-CBC (Advanced Encryption Standard in Cipher Block Chaining mode) в Web Crypto API реализует блочный симметричный шифр, в котором каждый блок открытого текста перед шифрованием комбинируется с предыдущим зашифрованным блоком. Это устраняет повторяемость одинаковых блоков данных и повышает устойчивость к анализу структуры сообщения.

В браузерной реализации используется интерфейс crypto.subtle, где AES-CBC доступен как один из режимов алгоритма AES.


Алгоритм AES-CBC

Режим CBC работает по следующему принципу:

  • данные разбиваются на блоки фиксированного размера (AES использует блоки по 16 байт);
  • каждый блок открытого текста перед шифрованием XOR-ится с предыдущим шифротекстом;
  • первый блок использует вектор инициализации (IV);
  • результат шифруется алгоритмом AES.

Формально:

C1 = AES(K, P1 ⊕ IV)
C2 = AES(K, P2 ⊕ C1)
C3 = AES(K, P3 ⊕ C2)
...

где:

  • P — блоки открытого текста,
  • C — блоки шифротекста,
  • K — секретный ключ,
  • IV — вектор инициализации.

Поддержка в Web Crypto API

AES-CBC реализуется через SubtleCrypto:

  • encrypt
  • decrypt
  • generateKey
  • importKey

Алгоритм задаётся структурой:

{
  name: "AES-CBC",
  iv: ...
}

Ключи могут иметь длину:

  • 128 бит
  • 192 бит
  • 256 бит

Вектор инициализации (IV)

Вектор инициализации является критически важной частью AES-CBC.

Свойства IV:

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

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

Пример генерации:

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

Паддинг (PKCS#7)

AES — блочный алгоритм, и Web Crypto API в режиме CBC не выполняет автоматическое дополнение данных.

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

  • длина данных должна быть кратна 16 байтам,
  • если это не так — требуется ручной padding.

На практике используется PKCS#7.

Принцип PKCS#7

Если нужно добавить n байт, каждый байт имеет значение n.

Пример:

Исходные данные: "HELLO" (5 байт)
Блок: 16 байт
Добавляется: 11 байт со значением 0x0B

Реализация padding

function pkcs7Pad(data) {
  const blockSize = 16;
  const pad = blockSize - (data.length % blockSize);
  const result = new Uint8Array(data.length + pad);

  result.set(data);
  result.fill(pad, data.length);

  return result;
}

Удаление padding при расшифровке

function pkcs7Unpad(data) {
  const pad = data[data.length - 1];
  return data.slice(0, data.length - pad);
}

Шифрование AES-CBC

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

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

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

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

const encoder = new TextEncoder();
const plaintext = encoder.encode("secret message");

const padded = pkcs7Pad(plaintext);

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

Дешифрование AES-CBC

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

const unpadded = pkcs7Unpad(new Uint8Array(decrypted));
const decoder = new TextDecoder();
const result = decoder.decode(unpadded);

Хранение IV вместе с шифротекстом

Так как IV не секретен, его обычно добавляют в начало сообщения:

function concat(iv, data) {
  const result = new Uint8Array(iv.length + data.length);
  result.set(iv);
  result.set(new Uint8Array(data), iv.length);
  return result;
}

При расшифровке:

const iv = data.slice(0, 16);
const ciphertext = data.slice(16);

Особенности реализации Web Crypto API

  • алгоритм работает только с ArrayBuffer / TypedArray;
  • строки должны быть закодированы вручную через TextEncoder;
  • API полностью асинхронный;
  • операции выполняются в изолированном криптоконтексте браузера.

Типичные ошибки при работе с AES-CBC

Повторное использование IV

Использование одного IV с одним ключом приводит к утечке информации о структуре данных.


Отсутствие padding

Попытка шифровать данные, длина которых не кратна 16 байтам, вызывает ошибку выполнения.


Использование AES-CBC без аутентификации

AES-CBC не обеспечивает целостность данных. Возможны атаки с подменой блоков (bit flipping attack).

Для защиты обычно добавляют:

  • HMAC поверх шифротекста
  • или переходят на AES-GCM

Потеря IV при передаче

Без корректного хранения IV расшифровка невозможна, даже при наличии ключа.


Структура безопасного сообщения

Типичная схема хранения данных:

[ IV (16 байт) ][ ciphertext (n байт) ]

или расширенная:

[ IV ][ ciphertext ][ HMAC ]

Криптографические ограничения AES-CBC в Web Crypto

  • отсутствие встроенного padding,
  • отсутствие встроенной аутентификации,
  • необходимость строгого контроля IV,
  • ручное управление сериализацией данных.

Сравнение с AES-GCM (контекстно)

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