Библиотека 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 основывается на нескольких
принципах:
encrypt/decrypt)Любой новый компонент фактически подключается как дополнительное поле
в объекте sjcl или в одном из его подпространств.
sjclНаиболее прямой способ расширения заключается в добавлении нового объекта в соответствующее пространство имён.
Пример добавления пользовательского модуля утилит:
sjcl.myModule = {
version: "1.0.0",
hello: function (name) {
return "Hello " + name;
}
};
После этого модуль становится частью глобального пространства:
sjcl.myModule.hello("crypto");
Такой подход используется для простых расширений, не требующих интеграции в криптографическое ядро.
sjcl.miscsjcl.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
Каждый уровень добавляется независимо, но сохраняет общую семантику библиотеки.