В SJCL зашифрованные данные обычно представляют собой структурированный JSON-объект, в котором объединены параметры криптографического контекста и непосредственно ciphertext. Такой формат делает возможной полную самодостаточность результата шифрования: без внешнего хранения IV, соли или параметров ключа.
Основная идея сериализации в SJCL заключается в том, что результат шифрования — это строка JSON, содержащая все необходимые данные для последующей расшифровки. Это позволяет безопасно передавать зашифрованные сообщения между системами, хранить их в базе данных или пересылать через небезопасные каналы связи без потери контекста.
При вызове:
const ciphertext = sjcl.encrypt(password, "секретное сообщение");
результатом будет строка, которая после парсинга JSON превращается в объект следующей структуры:
{
"iv": "base64...",
"v": 1,
"iter": 10000,
"ks": 128,
"ts": 64,
"mode": "ccm",
"adata": "",
"cipher": "aes",
"salt": "base64...",
"ct": "base64..."
}
Каждое поле играет строго определённую роль в процессе восстановления исходного текста.
Инициализационный вектор используется для обеспечения уникальности шифрования одного и того же текста при одинаковом ключе. Даже если входные данные не меняются, изменение IV приводит к полностью различному ciphertext.
IV в SJCL кодируется в Base64 и хранится прямо в объекте.
Соль используется при выводе ключа из пароля (KDF — Key Derivation Function). Она предотвращает атаки с использованием радужных таблиц и делает невозможным предварительный расчёт ключей для популярных паролей.
SJCL генерирует случайную соль при каждом шифровании, что гарантирует уникальность производного ключа даже при одинаковом пароле.
Количество итераций функции PBKDF2, используемой для получения ключа из пароля. Чем выше значение, тем медленнее вычисление ключа и тем выше устойчивость к brute-force атакам.
sjcl.encrypt(password, data, { iter: 20000 });
Увеличение iter напрямую влияет на стоимость атаки
перебором.
Размер ключа в битах. Обычно используется 128, 192 или 256 бит. В большинстве реализаций SJCL по умолчанию применяется 128-битный ключ.
Размер аутентификационного тега. Используется в режимах аутентифицированного шифрования (например, CCM). Чем больше значение, тем сложнее подделать ciphertext.
Режим шифрования. SJCL поддерживает несколько режимов, наиболее часто используется:
"ccm" — Counter with CBC-MAC (аутентифицированное
шифрование)"ocb2" — более старый режим, но быстрее"gcm" — в некоторых сборкахРежим определяет способ объединения конфиденциальности и целостности данных.
Алгоритм шифрования. В стандартной конфигурации SJCL используется:
"aes"AES является базовым блочным шифром, на котором строится вся криптосистема библиотеки.
Дополнительные данные, которые не шифруются, но участвуют в проверке целостности. Используются для защиты структуры сообщения или метаданных.
Если adata изменяется после шифрования, расшифровка завершится ошибкой проверки целостности.
Основное зашифрованное содержимое. Представлено в Base64 и является результатом применения симметричного шифрования к исходному тексту.
Функция sjcl.encrypt выполняет несколько этапов:
Именно последний шаг делает результат пригодным для хранения:
const encrypted = sjcl.encrypt("password", "data");
console.log(typeof encrypted); // "string"
Несмотря на то что внутри используется объектная структура, наружу библиотека возвращает строку.
Обратный процесс начинается с преобразования строки в объект:
const obj = sjcl.json.parse(encrypted);
или напрямую:
const decrypted = sjcl.decrypt("password", encrypted);
Внутри SJCL выполняет автоматический разбор JSON и извлекает все необходимые параметры.
Если используется ручной подход, десериализация выглядит так:
const data = JSON.parse(encrypted);
После этого структура становится доступной для низкоуровневой работы.
const encrypted = sjcl.encrypt("password", "секрет");
const decrypted = sjcl.decrypt("password", encrypted);
На уровне реализации происходит:
SJCL активно использует внутренний тип bitArray, который
отличается от привычных строк или Uint8Array.
При сериализации происходит преобразование:
Пример:
const bits = sjcl.codec.utf8String.toBits("hello");
const base64 = sjcl.codec.base64.fromBits(bits);
Именно такой механизм лежит в основе полей ct,
iv, salt.
Формат SJCL JSON считается стабильным, однако имеет зависимость от версии библиотеки.
Поле v (version) указывает версию формата:
"v": 1
При изменении алгоритмов или структуры сериализации возможна необходимость обратной совместимости через этот параметр.
Изменение любых полей внутри JSON приводит к изменению результата расшифровки. Особенно критичны:
Даже минимальное изменение Base64 строки делает объект невалидным.
Чаще всего SJCL-объекты сохраняются:
Пример:
localStorage.setItem("secureData", sjcl.encrypt(password, data));
И восстановление:
const decrypted = sjcl.decrypt(password, localStorage.getItem("secureData"));
Типичные причины:
SJCL в таких случаях выбрасывает исключение, не возвращая частично расшифрованные данные, что критично для безопасности.
Сериализованный объект SJCL фактически является минималистичным криптоконтейнером, включающим:
Такой подход избавляет от необходимости хранить метаданные отдельно и делает каждое сообщение автономным.