Система кодеков и представлений данных

В основе Stanford JavaScript Crypto Library лежит принцип строгого разделения между внутренним представлением данных и их внешними форматами. Криптографические алгоритмы оперируют не строками и не байтами в привычном смысле JavaScript, а специализированной структурой — bitArray. Поверх неё построен слой кодеков (codecs), отвечающих за преобразование данных между человекочитаемыми форматами и внутренним представлением библиотеки.


Внутреннее представление: bitArray

Ключевой тип данных в SJCL — это bitArray. Он представляет собой массив 32-битных слов с дополнительным первым элементом, содержащим длину в битах.

Структура:

[bitLength, word0, word1, word2, ...]

где:

  • bitLength — количество значимых бит
  • wordN — 32-битные целые числа

Особенности модели

  • Хранение идёт не побайтно, а побитово
  • Последнее слово может быть частично заполнено
  • Арифметика выполняется через побитовые операции JavaScript

Такой подход позволяет эффективно реализовать криптографические операции без привязки к строковым или байтовым ограничениям среды исполнения.


Причины использования bitArray

Стандартные типы JavaScript плохо подходят для криптографии:

  • строки зависят от UTF-16
  • массивы байтов отсутствуют в базовой спецификации ES5
  • операции с бинарными данными требуют дополнительных преобразований

bitArray решает эти проблемы:

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

Архитектура кодеков

Кодеки в SJCL находятся в пространстве sjcl.codec. Они отвечают за преобразование:

  • строк → bitArray
  • bitArray → строки

Каждый кодек реализует два базовых метода:

  • toBits(data)
  • fromBits(bitArray)

Дополнительно могут использоваться вспомогательные функции для работы с подформатами.


Hex-кодек

Hex (шестнадцатеричное представление) — один из базовых способов отображения бинарных данных.

Преобразование в hex

sjcl.codec.hex.fromBits(bitArray)

Каждые 4 бита преобразуются в один символ [0-9a-f].

Преобразование из hex

sjcl.codec.hex.toBits(hexString)

Особенности

  • строка должна иметь чётную длину
  • не допускаются пробелы и префиксы 0x
  • используется для ключей, хешей, IV

Пример использования

const hashHex = sjcl.codec.hex.fromBits(hashBits);
const bits = sjcl.codec.hex.toBits(hashHex);

Hex остаётся основным форматом для низкоуровневого представления криптографических значений.


Base64-кодек

Base64 используется для компактного представления бинарных данных в текстовом виде.

Основные свойства

  • кодирует 6 бит в один символ
  • использует алфавит A–Z, a–z, 0–9, +, /
  • поддерживает padding =

Преобразование

sjcl.codec.base64.fromBits(bitArray)
sjcl.codec.base64.toBits(base64String)

Варианты реализации

В SJCL существует несколько режимов base64:

  • стандартный RFC 4648
  • URL-safe вариант (в некоторых расширениях)

UTF-8 строковый кодек

UTF-8 кодек предназначен для преобразования строк JavaScript в битовый формат и обратно.

Преобразование строки в bits

sjcl.codec.utf8String.toBits("текст")

Обратное преобразование

sjcl.codec.utf8String.fromBits(bitArray)

Особенности работы

JavaScript строки используют UTF-16, поэтому кодек выполняет:

  • декодирование суррогатных пар
  • нормализацию символов Unicode
  • разбиение на байты UTF-8

Внутренний процесс

  1. символ → Unicode code point
  2. кодирование в UTF-8 последовательность байт
  3. упаковка байтов в bitArray

ByteArray и совместимость

Хотя SJCL не использует нативные Uint8Array в ядре, существует концептуальная совместимость через промежуточные преобразования.

Преобразование bitArray → байты

Используется построчная декомпозиция 32-битных слов:

  • каждое слово разбивается на 4 байта
  • учитывается длина в битах
  • лишние биты отбрасываются

JSON-кодирование

SJCL включает JSON-кодек для сериализации структур, содержащих bitArray.

Особенности

  • не является криптографическим кодеком
  • используется для хранения зашифрованных объектов
  • работает через промежуточное base64 или hex представление

Типичная структура:

{
  "iv": "...",
  "salt": "...",
  "ct": "..."
}

Где все поля — закодированные bitArray.


Сравнение кодеков

Кодек Назначение Плотность Читаемость
hex отладка, ключи низкая высокая
base64 передача данных средняя средняя
utf8String текстовые данные переменная высокая
bitArray внутренний формат SJCL максимальная отсутствует

Взаимодействие кодеков с криптографическими примитивами

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

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

Любая криптографическая функция SJCL принимает и возвращает bitArray, что делает кодеки вспомогательным, но критически важным слоем.


Потоки преобразований данных

Типичный жизненный цикл данных в SJCL выглядит следующим образом:

Шифрование

  1. строка (UTF-8)
  2. utf8String.toBits
  3. AES/HMAC/и т.д.
  4. bitArray
  5. base64.fromBits

Дешифрование

  1. base64
  2. base64.toBits
  3. криптоалгоритм
  4. utf8String.fromBits

Побитовая точность и выравнивание

Одной из ключевых проблем при работе с бинарными данными в JavaScript является выравнивание.

SJCL решает это через:

  • явное хранение длины в битах
  • маскирование лишних битов в последнем слове
  • отсутствие зависимости от байтовых границ

Пример:

[13, 0b10101000000000000000000000000000]

означает только первые 13 бит значимы.


Влияние на производительность

Использование bitArray и кодеков имеет компромиссы:

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

Однако:

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

Расширяемость системы кодеков

Архитектура SJCL допускает добавление собственных кодеков.

Для этого достаточно реализовать интерфейс:

{
  toBits: function (data) { ... },
  fromBits: function (bits) { ... }
}

Это позволяет интегрировать:

  • нестандартные бинарные форматы
  • специализированные протоколы передачи
  • оптимизированные сериализаторы

Практические особенности использования

При работе с кодеками важно учитывать:

  • несоответствие длины данных (особенно в base64)
  • корректную обработку Unicode
  • необходимость явного выбора формата хранения
  • различие между транспортным и внутренним представлением

Ошибки на уровне кодеков часто приводят не к сбоям, а к тихой порче данных, что особенно критично в криптографии.


Связь с криптографическими режимами SJCL

Кодеки тесно связаны с высокоуровневыми API библиотеки:

  • sjcl.encrypt
  • sjcl.decrypt
  • sjcl.misc

Эти функции принимают строки, но внутри всегда преобразуют их в bitArray, а затем возвращают результат через кодек.

Таким образом, кодеки формируют границу между:

  • пользовательскими данными
  • криптографическим ядром библиотеки