Полный цикл шифрования строки через AES

AES в CryptoJS реализуется поверх стандартных криптографических примитивов: симметричного блочного шифра, режима работы (чаще CBC) и механизма дополнения данных. Вся логика полного цикла шифрования строки сводится к нескольким строго связанным этапам: подготовка ключевого материала, преобразование строки в бинарный формат, выполнение шифрования с использованием IV, сериализация результата и обратное восстановление исходного текста.


В среде браузера или Node.js библиотека подключается стандартным образом:

import CryptoJS from "crypto-js";

или

const CryptoJS = require("crypto-js");

Внутри CryptoJS данные почти всегда представлены в виде объектов WordArray. Это промежуточный формат между строкой и бинарным представлением, необходимый для корректной работы AES.


Подготовка исходных данных

Строка перед шифрованием не может быть использована напрямую. Она преобразуется в UTF-8 представление, а затем в WordArray автоматически внутри методов CryptoJS.

const message = "Секретное сообщение";

Ключ и вектор инициализации (IV)

AES требует два критически важных элемента:

  • ключ (key) — секретная последовательность байтов
  • IV (Initialization Vector) — случайное значение для защиты от повторяемости шифротекста

Формирование ключа

На практике ключ часто задаётся строкой и преобразуется через хеширование:

const password = "strong-password";
const key = CryptoJS.SHA256(password);

SHA-256 обеспечивает фиксированную длину ключа 256 бит, что соответствует AES-256.


Генерация IV

IV должен быть уникальным для каждого шифрования:

const iv = CryptoJS.lib.WordArray.random(16);

16 байт соответствует размеру блока AES.


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

Основной этап выполняется через CryptoJS.AES.encrypt.

const encrypted = CryptoJS.AES.encrypt(message, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
});

Разбор параметров

  • mode CBC Режим цепочки блоков. Каждый блок шифруется с учётом предыдущего.

  • padding PKCS7 Дополняет строку до размера блока AES.

  • iv Обеспечивает уникальность результата при одинаковом ключе и одинаковом тексте.


Формирование итогового шифротекста

Результат encrypt содержит бинарные данные, которые обычно сериализуются в Base64:

const ciphertext = encrypted.toString();

На этом этапе получается строка, которую можно безопасно хранить или передавать.


Полный цикл шифрования с сохранением IV

В реальных системах IV обязательно сохраняется вместе с шифротекстом.

const payload = {
    iv: iv.toString(CryptoJS.enc.Base64),
    data: ciphertext
};

Без IV расшифровка становится невозможной.


Процесс расшифрования

Обратная операция требует тех же параметров: ключ, IV и шифротекст.

const decrypted = CryptoJS.AES.decrypt(payload.data, key, {
    iv: CryptoJS.enc.Base64.parse(payload.iv),
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
});

Получение исходной строки

После расшифровки результат находится в формате WordArray и требует преобразования:

const originalMessage = decrypted.toString(CryptoJS.enc.Utf8);

Полный пример цикла шифрование → расшифрование

const CryptoJS = require("crypto-js");

// исходное сообщение
const message = "Секретное сообщение";

// ключ
const password = "strong-password";
const key = CryptoJS.SHA256(password);

// IV
const iv = CryptoJS.lib.WordArray.random(16);

// шифрование
const encrypted = CryptoJS.AES.encrypt(message, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
});

const ciphertext = encrypted.toString();

// сохранение данных
const payload = {
    iv: iv.toString(CryptoJS.enc.Base64),
    data: ciphertext
};

// расшифрование
const decrypted = CryptoJS.AES.decrypt(payload.data, key, {
    iv: CryptoJS.enc.Base64.parse(payload.iv),
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
});

const original = decrypted.toString(CryptoJS.enc.Utf8);

console.log(original);

Важные особенности внутреннего устройства AES в CryptoJS

1. Работа с WordArray

CryptoJS не оперирует строками напрямую. Внутренний формат:

  • массив 32-битных слов
  • оптимизация под поблочные операции

2. Роль режима CBC

CBC (Cipher Block Chaining):

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

3. Padding PKCS7

Если длина текста не кратна 16 байтам:

  • добавляются байты вида 0x01, 0x02
  • последний байт определяет длину паддинга

4. Кодирование результата

CryptoJS поддерживает несколько форматов вывода:

encrypted.toString(CryptoJS.enc.Base64);
encrypted.toString(CryptoJS.enc.Hex);

Base64 используется чаще из-за компактности.


Типичная схема хранения зашифрованных данных

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

{
    iv: "Base64...",
    ciphertext: "Base64...",
    algorithm: "AES",
    mode: "CBC",
    padding: "PKCS7"
}

Это позволяет однозначно восстановить параметры шифрования.


Частые ошибки при реализации полного цикла

Использование постоянного IV

При фиксированном IV:

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

Потеря IV

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


Неправильное кодирование ключа

CryptoJS.AES.encrypt(message, "password")

Такой вариант создаёт внутренную производную ключа, но поведение может отличаться от ожидаемого при SHA-256.


Несовпадение режимов

Шифрование и расшифрование обязаны использовать одинаковые:

  • mode (CBC, ECB и т.д.)
  • padding
  • IV

Использование производного ключа через PBKDF2

Более безопасный вариант:

const key = CryptoJS.PBKDF2(password, "salt", {
    keySize: 256 / 32,
    iterations: 1000
});

Это снижает риск атак на слабые пароли.


Структура полного криптографического пайплайна

  1. Исходная строка
  2. Преобразование в WordArray
  3. Генерация ключа (SHA-256 или PBKDF2)
  4. Генерация IV
  5. AES шифрование (CBC + PKCS7)
  6. Кодирование результата (Base64)
  7. Сохранение IV вместе с данными
  8. Обратное декодирование Base64
  9. Расшифрование теми же параметрами
  10. Преобразование WordArray в UTF-8 строку