Режимы шифрования AES объяснены Почему GCM превосходит CBC в большинстве случаев (и когда это не так)

Опубликовано

AES сам по себе не является полным выбором алгоритма. Режим — CBC, CTR, GCM, ECB — определяет всё о том, безопасна ли ваша шифровка. Ниже — практическое объяснение, которое нужны разработчикам.

Объяснение режимов шифрования AES: почему GCM превосходит CBC в большинстве случаев (и когда это не так) 1
Реклама · УДАЛИТЬ?

Когда документация говорит вам «использовать AES-256», это неполное руководство. AES — это блочный шифр — он шифрует ровно один блок из 128 бит за раз. Режим работы определяет, как AES обрабатывает данные длиной более 16 байт, и насколько он защищает вас от атакующих, которые могут наблюдать или вмешиваться в шифрованные данные. Ошибки в этом аспекте приводят к тому, что «зашифрованные» данные утечивают структуру файлов или система уязвима к атакам с изменением битов. режим работы определяет, как AES обрабатывает реальные данные длиной более 16 байт, и насколько он защищает вас от атакующих, которые могут наблюдать или вмешиваться в шифрованные данные. Ошибки в этом аспекте приводят к тому, что «зашифрованные» данные утечивают структуру файлов или система уязвима к атакам с изменением битов.

Полный алгоритм описывается так AES-256-GCM или AES-128-CBC — размер ключа, за которым следует режим. В этой статье описано, что делает каждый режим, почему GCM является правильным стандартом по умолчанию, и в каких случаях вы можете законно выбрать что-то иное.

Во-первых, почему ECB — это мем, а не просто шутка

ECB (Electronic Codebook) — это простой режим. Каждый блок из 16 байт исходных данных шифруется независимо с использованием одного и того же ключа. Это означает, что одинаковые блоки исходных данных дают одинаковые блоки шифрованных данных.

Классическим примером является шифрование Linux-пингвина (Tux). Изображение шифруется блоками, но поскольку большие участки изображения имеют единый цвет, в шифрованном виде всё ещё остаётся очевидной форма пингвина. Шифрование математически корректно — данные перемешаны — но паттерн сохраняется.

На практике это важно каждый раз, когда в исходных данных есть повторения: строки базы данных с общим префиксом, заголовки файлов, заполненные поля. ECB раскрывает структуру. Нет законных случаев использования ECB в новых программах. Если вы поддерживаете код, использующий ECB: замените его.

Режимы, которые стоит знать

CBC — режим, который используется большинством устаревших систем

Шифрование блоков цепочкой (CBC) XOR-шифрует каждый блок исходных данных с предыдущим блоком шифрованного текста перед шифрованием. Это решает проблему паттерна ECB — одинаковые блоки исходных данных дают разные блоки шифрованного текста, потому что цепочка делает шифрование каждого блока зависеть от предыдущего блока.

CBC требует вектора инициализации (IV) — случайного значения из 16 байт, которое инициализирует цепочку для первого блока. IV не должен быть секретным, но он должен быть случайным и передаваться вместе с шифрованным текстом.

Проблема с CBC: предоставляет конфиденциальность но не целостность. Атакующий, который может изменять шифрованный текст в процессе передачи, может изменять конкретные биты в расшифрованном выводе по предсказуемым правилам. Это основа атак с паддингом, которые уже сломали реальные системы (POODLE, BEAST, Lucky Thirteen). Если вы используете CBC без отдельного MAC (Message Authentication Code) для проверки целостности, вы уязвимы. Паттерн называется «шифрование-затем-MAC» — сначала шифруем, затем HMAC-шифруем шифрованный текст, затем проверяем MAC перед расшифровкой. Ошибка в порядке выполнения — классическая ошибка.

CBC также является последовательным — вы не можете параллелизировать шифрование (каждый блок зависит от предыдущего шифрованного блока), а расшифровка может быть только частично параллелизируема.

CTR — поведение потокового шифра, основанное на блочном шифре

Режим CTR превращает AES в потоковый шифр. Вместо прямого шифрования исходных данных, он шифрует последовательные значения счётчика и XOR-шифрует результат с исходными данными. Это означает, что режим CTR не требует заполнения (он работает с данными любой длины), полностью параллелизируем в обоих направлениях, и позволяет произвольный доступ к любому месту в шифрованном тексте при расшифровке.

CTR использует nonce (число, используемое один раз), а не полный IV. Нонс должен быть уникальным для каждого сообщения при заданном ключе — повторное использование nonce с тем же ключом раскрывает XOR двух исходных данных, что является катастрофой. В отличие от CBC, CTR также не обеспечивает защиту целостности. Та же история: требуется шифрование-затем-MAC, если вы хотите защиту от вмешательства.

CTR подходит, когда вам нужно свойство потокового шифра — большие файлы, расшифровка с произвольным доступом, высокая производительность в сценариях, где важна параллельность — и вы обрабатываете слой MAC отдельно.

GCM — аутентифицированное шифрование, один шаг

Режим Galois/Counter (GCM) — это CTR с встроенной меткой аутентификации (GHASH). Вы получаете конфиденциальность и целостность в одном примитиве. Метка аутентификации — обычно 128 бит — позволяет получателю проверить, что шифрованный текст не был изменён, до расшифровки. Нет отдельного шага HMAC, нет шанса ошибиться в порядке шифрования-затем-MAC.

GCM также поддерживает Дополнительные аутентифицированные данные (AAD) — данные, которые подтверждаются, но не шифруются. Это полезно для заголовков, метаданных или любых данных, которым нужна защита целостности, но не требуется конфиденциальность. Данные AAD проверяются вместе с шифрованным текстом на метке аутентификации.

Нонс для GCM по умолчанию составляет 96 бит (12 байт). Как и в случае с CTR, повторное использование нонса с тем же ключом приводит к полному нарушению безопасности — раскрываются как сама исходная информация, так и ключ аутентификации (H). Всегда генерируйте нонсы с помощью криптографически безопасного генератора случайных чисел; никогда не вычисляйте их из последовательных счётчиков, если вы не используете тщательно управляемый глобальный счётчик с жёсткими гарантиями уникальности.

GCM является параллелизуемым и не требует заполнения. Это рекомендация по умолчанию в TLS 1.3, Signal Protocol и большинстве современных криптографических библиотек. Если вы пишете новый код, GCM — ваш выбор по умолчанию.

Сравнение режимов

РежимАвторизованныйПараллелизуемыйТребует заполненияРиск повторного использования нонса/IVВердикт
ECBНетДаДаН/Д (нет IV)Никогда не использовать
CBCНет (добавить MAC)Шифрование: Нет / Расшифровка: ДаДаУмеренныйУстаревший только
CTRНет (добавить MAC)ДаНетКритично — повторное использование приводит к утечке исходных данныхОграниченное применение
GCMДа (встроено)ДаНетКритично — повторное использование приводит к полному нарушению безопасностиСтандартный выбор

AES-256-GCM в Node.js

Вот полная реализация шифрования и расшифровки с использованием встроенной библиотеки Node.js — без необходимости в зависимостях: crypto Несколько моментов, на которые стоит обратить внимание в этом коде:

const crypto = require('crypto');

const ALGORITHM = 'aes-256-gcm';
const KEY_LENGTH = 32; // 256 bits
const NONCE_LENGTH = 12; // 96 bits — GCM default
const TAG_LENGTH = 16; // 128-bit auth tag

function encrypt(plaintext, key) {
  const nonce = crypto.randomBytes(NONCE_LENGTH);
  const cipher = crypto.createCipheriv(ALGORITHM, key, nonce, {
    authTagLength: TAG_LENGTH,
  });

  const encrypted = Buffer.concat([
    cipher.update(plaintext, 'utf8'),
    cipher.final(),
  ]);
  const tag = cipher.getAuthTag();

  // Prepend nonce + tag to ciphertext for storage/transmission
  return Buffer.concat([nonce, tag, encrypted]);
}

function decrypt(ciphertext, key) {
  const nonce = ciphertext.subarray(0, NONCE_LENGTH);
  const tag = ciphertext.subarray(NONCE_LENGTH, NONCE_LENGTH + TAG_LENGTH);
  const data = ciphertext.subarray(NONCE_LENGTH + TAG_LENGTH);

  const decipher = crypto.createDecipheriv(ALGORITHM, key, nonce, {
    authTagLength: TAG_LENGTH,
  });
  decipher.setAuthTag(tag);

  // Throws if auth tag doesn't match — do not catch this silently
  return Buffer.concat([decipher.update(data), decipher.final()]).toString('utf8');
}

// Generate a key (do this once; store it securely)
const key = crypto.randomBytes(KEY_LENGTH);

const message = 'Hello, authenticated encryption.';
const ciphertext = encrypt(message, key);
console.log('Encrypted:', ciphertext.toString('hex'));

const plaintext = decrypt(ciphertext, key);
console.log('Decrypted:', plaintext); // Hello, authenticated encryption.

Нонс генерируется свежим на каждом вызове шифрования

  • является криптографически безопасным. Не заменяйте его на счётчик, если вы не понимаете проблемы распределённой уникальности.crypto.randomBytes Нонс и метка аутентификации хранятся вместе с шифрованным текстом
  • — они должны передаваться вместе с зашифрованными данными. Нонс является публичным; метка — публичной. Только ключ является секретным. выбрасывает при неудаче проверки аутентичности
  • decipher.final() — это корректное поведение. Не поймите и возвращайте частичный текст. Неудача проверки аутентичности означает, что данные были изменены или ключ неверен. Управление ключами — сложная часть
  • предоставляет вам хороший ключ, но то, где вы его храните и как вы его обновляете, имеет большее значение, чем выбор алгоритма. Используйте менеджер секретов, а не константу, встроенную в код.crypto.randomBytes(32) Хотите тестировать режимы шифрования интерактивно?

IO Tools’ инструмент шифрования/расшифровки AES позволяет шифровать и расшифровывать с использованием режимов CBC и GCM прямо в браузере — полезно для проверки совместимости или отладки интеграции. Для генерации криптографически безопасного ключа из 256 бит используйте Генератор ключа AES IV и нонс: правила, которые действительно важны.

Неправильное использование нонса/IV приводит к большему количеству реальных нарушений, чем выбор алгоритма. Правила:

Всегда генерируйте нонсы/IV с помощью CSPRNG

  • в Node,crypto.randomBytes() в Java. Не os.urandom() в Node.js все требуют одинаковое время независимо от того, где строки отличаются. Используйте их каждый раз при сравнении подписи — без исключений. SecureRandom . Не временная метка. Не инкрементирующий счётчик, если он не является правильно управляемым глобальным счётчиком с жёсткими гарантиями уникальности. Math.random()Повторное использование нонса в GCM приводит к полному нарушению аутентификации
  • — при одинаковом ключе и нонсе GCM раскрывает ключ аутентификации H. Атакующий может затем создавать аутентичные метки для любых шифрованных данных. Это не теоретическая проблема: атака Forbidden использует это и применялась к реальным реализациям. Повторное использование IV в CBC менее катастрофично, но всё равно плохое
  • — возможны атаки на выбранное сообщение. На практике всегда генерируйте новый IV для каждого сообщения. Никогда не вычисляйте нонс из содержимого сообщения
  • — детерминированные нонсы, зависящие от предсказуемых данных, создают предсказуемые паттерны. Используйте случайность. Когда CBC или CTR всё ещё являются правильным выбором

GCM не всегда является правильным решением:

Совместимость с устаревшими системами

  • — если вы интегрируетесь с системой, которая использует только AES-CBC, вы используете CBC. Чётко документируйте требования к MAC и правильно реализуйте их (шифрование-затем-MAC с HMAC-SHA256). Ограниченные среды без аппаратной поддержки GHASH
  • — шаг аутентификации GCM использует GHASH, который более трудоёмок, чем простое блочное шифрование на аппаратных платформах без специальной ускоренной поддержки. В некоторых встраиваемых системах, где доступно CTR+CMAC, но нет GHASH, может быть оправдано использование режима CTR. Потоковое шифрование очень больших файлов, где требуется расшифровка с произвольным доступом
  • — свойство произвольного доступа CTR полезно, когда нужно расшифровать позицию N без чтения позиций от 0 до N-1. GCM теоретически позволяет это, но проверка метки аутентификации требует обработки всего шифрованного текста, что противоречит цели. Шифрование диска
  • — полное шифрование диска использует режим XTS (не охваченный здесь), а не GCM, потому что XTS разработан для фиксированных секторов с произвольным доступом. GCM предназначен для шифрования сообщений, а не секторов. AES-256-GCM

Краткий вариант

Используйте для новых программ. Генерируйте свежий 12-байтовый случайный нонс на каждом вызове шифрования. Храните нонс и метку аутентификации вместе с шифрованным текстом. Трактуйте неудачи проверки аутентичности как ошибки, а не как предупреждения — никогда не возвращайте текст при том, что GCM говорит о его недействительности. Если вы проводите аудит существующего кода CBC: убедитесь, что реализовано правильное шифрование-затем-MAC, проверьте, что IV-значения случайны (не повторяются, не последовательны), и разработайте план миграции на GCM в течение доступного периода обслуживания. CBC с правильным HMAC не сломан — он просто имеет больше «ловушек», чем GCM.

ECB: просто замените его. Нет пути аудита, который бы завершился фразой «ECB здесь допустим».

AES Encryption Modes Explained: Why GCM Beats CBC in Most Cases (and When It Doesn’t) 2

Хотите убрать рекламу? Откажитесь от рекламы сегодня

Установите наши расширения

Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска

в Расширение Chrome в Расширение края в Расширение Firefox в Расширение Opera

Табло результатов прибыло!

Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!

Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?

новости с техническими моментами

Примите участие

Помогите нам продолжать предоставлять ценные бесплатные инструменты

Купи мне кофе
Реклама · УДАЛИТЬ?