Расширение пространства имён sjcl

Библиотека Stanford JavaScript Crypto Library организована вокруг единого глобального объекта sjcl, который выступает контейнером для всех криптографических примитивов, утилит и внутренних механизмов. Архитектура построена таким образом, чтобы новые компоненты могли быть добавлены без изменения исходного кода ядра.

Пространство имён sjcl включает несколько ключевых областей:

  • sjcl.cipher — блочные шифры (AES и расширения)
  • sjcl.hash — хеш-функции (SHA-256 и др.)
  • sjcl.mode — режимы шифрования (CBC, CCM и т.д.)
  • sjcl.misc — вспомогательные утилиты
  • sjcl.random — генератор случайных чисел
  • sjcl.codec — кодеки преобразования данных
  • sjcl.exception — обработка ошибок

Каждая из этих областей реализована как вложенный объект внутри sjcl, что позволяет сохранять единообразную структуру и расширяемость.


Принципы расширения пространства имён

Расширение sjcl основывается на нескольких принципах:

  • отсутствие жёсткой связности модулей
  • добавление функциональности через присваивание свойств
  • использование прототипного наследования для криптографических примитивов
  • совместимость с существующими интерфейсами (например, единый API encrypt/decrypt)

Любой новый компонент фактически подключается как дополнительное поле в объекте sjcl или в одном из его подпространств.


Добавление собственных модулей в sjcl

Наиболее прямой способ расширения заключается в добавлении нового объекта в соответствующее пространство имён.

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

sjcl.myModule = {
  version: "1.0.0",

  hello: function (name) {
    return "Hello " + name;
  }
};

После этого модуль становится частью глобального пространства:

sjcl.myModule.hello("crypto");

Такой подход используется для простых расширений, не требующих интеграции в криптографическое ядро.


Расширение sjcl.misc

sjcl.misc предназначен для вспомогательных функций и часто используется как точка расширения для утилитарных возможностей.

Пример добавления функции кодирования:

sjcl.misc.toHexString = function (arr) {
  var out = "";
  for (var i = 0; i < arr.length; i++) {
    out += arr[i].toString(16);
  }
  return out;
};

Особенность подхода заключается в том, что sjcl.misc не накладывает строгих ограничений на тип добавляемых функций, что делает его удобным для расширений общего назначения.


Добавление нового шифра в sjcl.cipher

Криптографическое ядро SJCL позволяет подключать новые блочные шифры через пространство имён sjcl.cipher.

Каждый шифр должен реализовывать единый интерфейс:

  • encrypt(data)
  • decrypt(data)
  • конструктор с ключом

Пример минимальной структуры:

sjcl.cipher.MyCipher = function (key) {
  this.key = key;
};

sjcl.cipher.MyCipher.prototype.encrypt = function (data) {
  return data ^ this.key;
};

sjcl.cipher.MyCipher.prototype.decrypt = function (data) {
  return data ^ this.key;
};

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

var cipher = new sjcl.cipher.MyCipher(42);
cipher.encrypt(10);

Интеграция через регистрацию алгоритмов

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

Например, хеш-функции регистрируются в sjcl.hash:

sjcl.hash.MyHash = function () {
  this._state = 0;
};

sjcl.hash.MyHash.prototype.update = function (data) {
  this._state += data.length;
};

sjcl.hash.MyHash.prototype.finalize = function () {
  return this._state;
};

Такой объект автоматически становится доступным через пространство имён sjcl.hash.


Расширение генератора случайных чисел

sjcl.random представляет собой подсистему, которая может быть расширена источниками энтропии.

Добавление нового источника:

sjcl.random.addEntropySource = function (fn) {
  sjcl.random._sources = sjcl.random._sources || [];
  sjcl.random._sources.push(fn);
};

Источник энтропии должен возвращать числовые значения, используемые для наполнения пула случайности.

Пример источника:

function mouseEntropy() {
  return Date.now() % 256;
}

sjcl.random.addEntropySource(mouseEntropy);

Использование sjcl.extend и паттерн миксинов

Для более сложного расширения применяется подход миксинов, когда свойства одного объекта копируются в другой.

Типичный механизм:

sjcl.extend = function (dest, src) {
  for (var k in src) {
    if (src.hasOwnProperty(k)) {
      dest[k] = src[k];
    }
  }
  return dest;
};

Применение:

var extra = {
  encode: function (x) { return x + 1; }
};

sjcl.misc = sjcl.extend(sjcl.misc, extra);

Такой механизм позволяет добавлять функциональность без разрушения существующей структуры.


Встраивание модулей в цепочку криптографического процесса

Расширение sjcl часто связано с добавлением новых этапов обработки данных:

  • кодирование (sjcl.codec)
  • хеширование (sjcl.hash)
  • шифрование (sjcl.cipher)
  • режимы (sjcl.mode)

Пример добавления режима шифрования:

sjcl.mode.MyMode = function () {};

sjcl.mode.MyMode.encrypt = function (cipher, data) {
  return cipher.encrypt(data) + 1;
};

sjcl.mode.MyMode.decrypt = function (cipher, data) {
  return cipher.decrypt(data - 1);
};

После добавления режим может использоваться как часть криптографического конвейера.


Расширение кодеков sjcl.codec

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

Пример:

sjcl.codec.myBase = {
  fromBits: function (arr) {
    return arr.join("-");
  },

  toBits: function (str) {
    return str.split("-").map(Number);
  }
};

После регистрации:

sjcl.codec.myBase.fromBits([1,2,3]);

Взаимодействие расширений с ядром библиотеки

Все расширения sjcl работают в одном глобальном контексте, поэтому важно учитывать:

  • совместимость интерфейсов
  • отсутствие конфликтов имён
  • соблюдение структуры прототипов
  • единый формат входных данных (обычно bitArray)

Типичный формат данных SJCL — массив битов:

[1, 0, 1, 1, ...]

Все расширения должны учитывать этот формат при взаимодействии с ядром.


Паттерн безопасного расширения

Чтобы избежать конфликтов при добавлении новых модулей, используется проверка существования пространства имён:

sjcl.myNamespace = sjcl.myNamespace || {};

sjcl.myNamespace.crypto = function () {
  return "secure";
};

Такой подход обеспечивает безопасное расширение без перезаписи существующих компонентов.


Динамическая модификация пространства имён

В JavaScript возможно изменять структуру sjcl во время выполнения:

Object.defineProperty(sjcl, "version", {
  value: "custom-build",
  writable: false
});

Это позволяет фиксировать или защищать критические поля библиотеки.


Модульная композиция расширений

Расширения sjcl могут строиться как слоистая система:

  • базовый криптографический слой
  • утилитарный слой (misc)
  • прикладной слой (форматы, кодеки)
  • пользовательские модули

Пример композиции:

sjcl.app = {};

sjcl.app.encryptMessage = function (msg, cipher) {
  var bits = sjcl.codec.utf8String.toBits(msg);
  return cipher.encrypt(bits);
};

Изоляция расширений в отдельные неймспейсы

Для крупных расширений рекомендуется создавать отдельные подпространства:

sjcl.enterprise = sjcl.enterprise || {};
sjcl.enterprise.audit = {};
sjcl.enterprise.audit.log = function (msg) {
  console.log("AUDIT:", msg);
};

Такой подход предотвращает засорение основного пространства sjcl и упрощает поддержку.


Совместимость расширений с обновлениями библиотеки

Поскольку sjcl активно использует стабильные интерфейсы, расширения должны:

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

Пример безопасного переопределения:

var oldEncrypt = sjcl.cipher.aes.prototype.encrypt;

sjcl.cipher.aes.prototype.encrypt = function (data) {
  var result = oldEncrypt.call(this, data);
  return result;
};

Иерархия пространств имён в расширениях

Расширенная структура может формироваться следующим образом:

sjcl
 ├── cipher
 ├── hash
 ├── mode
 ├── codec
 ├── misc
 ├── random
 ├── myModule
 └── enterprise

Каждый уровень добавляется независимо, но сохраняет общую семантику библиотеки.