В основе работы CryptoJS лежит структура WordArray,
представляющая собой массив 32-битных слов с дополнительной информацией
о количестве значащих байтов. Эта модель позволяет откладывать часть
вычислений до момента, когда результат действительно требуется.
Ключевой момент заключается в том, что многие операции над
WordArray не приводят к немедленной переработке данных в
строковое представление или другой формат. Вместо этого формируется
новое представление поверх исходных данных.
При конкатенации:
var result = wordArray1.concat(wordArray2);
фактическое копирование данных происходит только при необходимости обращения к итоговому буферу в виде строки или при криптографической операции. До этого момента сохраняется структура ссылок и метаданных.
Метод clamp также демонстрирует ленивую модель: он лишь
корректирует последние биты, не пересоздавая массив целиком.
Операции кодирования и декодирования (UTF-8, Base64, Hex) реализованы через промежуточные преобразования, которые часто откладываются до момента сериализации результата.
Пример:
var encrypted = CryptoJS.AES.encrypt("text", "key");
var base64 = encrypted.toString();
Шифрование возвращает объект CipherParams, внутри
которого хранится WordArray. Преобразование в строку Base64
выполняется только при вызове toString.
Это снижает количество промежуточных преобразований при цепочках операций, где итоговое представление может быть изменено несколько раз.
Хешеры в CryptoJS реализуют потоковую модель вычислений. Основной механизм основан на методах:
updatefinalizeКаждый вызов update не приводит к финальному вычислению
хеша, а лишь накапливает состояние внутри внутреннего буфера.
var hash = CryptoJS.SHA256();
hash.update("part1");
hash.update("part2");
var result = hash.finalize();
Промежуточные данные сохраняются в состоянии объекта, включая:
Финальное вычисление происходит только при вызове
finalize, где выполняется padding и обработка остатка
блока.
В алгоритмах вроде AES ключ проходит стадию расширения (key expansion). В CryptoJS это представлено как формирование round keys.
Хотя API скрывает детали, внутри создаётся структура, которая используется повторно в рамках одного экземпляра шифрования.
Это приводит к следующей модели поведения:
Такой подход снижает стоимость операций при множественных вызовах одного и того же алгоритма с фиксированным ключом.
HMAC строится поверх хеш-функции и включает два предварительно вычисленных состояния:
При создании HMAC происходит подготовка ключа и формирование двух
промежуточных WordArray, которые затем используются при
каждом обновлении данных.
var hmac = CryptoJS.HmacSHA256("data", "secret");
Если реализуется потоковая модель:
var h = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);
h.update("chunk1");
h.update("chunk2");
var result = h.finalize();
то внутренние состояния хранятся в объекте и переиспользуются без пересоздания padding-структур.
При использовании PBKDF2 вычисление ключа основано на множестве итераций хеширования. Несмотря на отсутствие глобального кеша внутри библиотеки, промежуточные результаты итераций сохраняются внутри одной операции.
var key = CryptoJS.PBKDF2("password", "salt", {
keySize: 256 / 32,
iterations: 1000
});
Каждый блок результата вычисляется последовательно, и промежуточные HMAC-состояния переиспользуются внутри цикла итераций, что снижает избыточные пересоздания объектов хешера.
Метод clone в WordArray не выполняет
глубокого пересчёта буфера, а создаёт новую обёртку над существующими
данными:
var copy = wordArray.clone();
Это позволяет:
Одним из частых источников затрат становится повторное преобразование
между строками и WordArray.
Типичный сценарий без оптимизации:
В ленивой модели CryptoJS промежуточные представления могут сохраняться в виде объекта, исключая лишние перекодировки.
Рекомендуемая стратегия кеширования строится вокруг хранения
WordArray как единственного источника данных, а не
строковых представлений.
Внешняя оптимизация часто играет большую роль, чем внутренние механизмы библиотеки.
Примеры устойчивых паттернов:
PBKDF2 для одинаковых
параметровWordArray вместо строкconst cache = new Map();
function getHash(input) {
if (cache.has(input)) return cache.get(input);
const value = CryptoJS.SHA256(input).toString();
cache.set(input, value);
return value;
}
Цепочки преобразований в CryptoJS часто выглядят как последовательные вызовы, но внутренне могут откладывать вычисления до финального этапа:
var result = CryptoJS.enc.Utf8.parse("text")
.toString(CryptoJS.enc.Base64);
Каждый шаг не обязательно приводит к немедленной обработке всего объёма данных. Вместо этого формируется промежуточное представление, которое может быть преобразовано только при необходимости конечного формата.
Ленивая модель снижает количество временных объектов:
Особенно это проявляется при обработке больших потоков данных, где
update-модель позволяет избегать построения единого
большого буфера до момента финализации.