В библиотеке SJCL (Stanford Javascript Crypto Library) генератор псевдослучайных чисел (PRNG) является критически важным компонентом, поскольку от качества энтропии зависит стойкость всех криптографических операций: генерации ключей, nonce, salt и других случайных значений.
По умолчанию SJCL использует собственный PRNG, основанный на состоянии внутреннего генератора и накоплении энтропии из браузерных событий. Однако в ряде архитектур требуется замена или усиление источника случайности внешними системами: аппаратными генераторами, серверной энтропией, WebCrypto API или специализированными криптографическими сервисами.
В основе лежит объект sjcl.random, который
управляет:
randomWords()Ключевой момент: SJCL не полагается на один источник, а смешивает данные из разных источников в общий пул.
sjcl.random.addEntropy(data, strength, source)
data — числовое значение или массивstrength — оценка количества бит энтропииsource — идентификатор источникаЗамена или расширение PRNG требуется в следующих случаях:
В таких системах стандартный браузерный шум (mouse move, keyboard events) отсутствует или недостаточен.
SJCL не предоставляет прямого механизма «замены PRNG», но позволяет полностью переопределить источник энтропии через добавление высококачественных внешних данных.
Основной метод:
sjcl.random.addEntropy(externalBytes, 256, "external-source");
Где externalBytes должен представлять криптографически
стойкий набор данных.
В современных браузерах стандартным источником является:
crypto.getRandomValues(new Uint32Array(n))
Интеграция в SJCL:
function injectWebCryptoEntropy() {
const arr = new Uint32Array(32);
crypto.getRandomValues(arr);
sjcl.random.addEntropy(arr, 1024, "webcrypto");
}
Особенность: WebCrypto уже считается CSPRNG, поэтому его энтропия может рассматриваться как максимально надёжная.
При необходимости полного контроля можно подавить зависимость от внутренних событий SJCL и кормить пул вручную.
sjcl.random.startCollectors = function () {
// отключение стандартных сборщиков
};
Далее система полностью переходит на внешнее наполнение:
async function initEntropyFromServer() {
const response = await fetch("/api/random");
const data = await response.arrayBuffer();
sjcl.random.addEntropy(new Uint8Array(data), 2048, "server");
}
На сервере часто используется комбинация источников:
/dev/urandomПример API-ответа:
{
"random": "base64-encoded-bytes"
}
Клиентская обработка:
function base64ToBytes(base64) {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
Инжекция:
const entropy = base64ToBytes(response.random);
sjcl.random.addEntropy(entropy, entropy.length * 8, "server-api");
В высокозащищённых системах стандартные источники событий могут считаться недостоверными или непредсказуемыми по качеству.
Отключение:
sjcl.random.events = {};
sjcl.random.isReady = function () {
return true;
};
Далее генерация становится строго управляемой внешними данными.
В корпоративных системах часто применяется аппаратный модуль:
Доступ осуществляется через backend:
async function getHSMEntropy() {
const res = await fetch("/hsm/random");
const buffer = await res.arrayBuffer();
sjcl.random.addEntropy(new Uint8Array(buffer), 4096, "hsm");
}
Особенность таких источников — сертифицированная криптостойкость.
SJCL использует оценку качества через параметр strength.
При работе с внешними источниками важно корректно задавать уровень:
/dev/urandom: зависит от реализацииПример комбинирования:
sjcl.random.addEntropy(webEntropy, 1024, "webcrypto");
sjcl.random.addEntropy(serverEntropy, 2048, "server");
sjcl.random.addEntropy(hsmEntropy, 4096, "hsm");
SJCL блокирует выдачу случайных чисел, если считает энтропию недостаточной. При внешнем управлении можно контролировать готовность:
while (!sjcl.random.isReady()) {
await injectEntropy();
}
После этого становится доступно:
const words = sjcl.random.randomWords(8);
В крайних архитектурах PRNG SJCL фактически не используется как генератор, а превращается в интерфейс хранения энтропии.
Реализация внешнего генератора:
async function externalRandomWords(n) {
const res = await fetch(`/api/rng?n=${n}`);
const buffer = await res.arrayBuffer();
const view = new Uint32Array(buffer);
return Array.from(view);
}
И синхронизация с SJCL:
function syncExternalToSJCL(n) {
externalRandomWords(n).then(words => {
sjcl.random.addEntropy(words, words.length * 32, "external-csprng");
});
}
Безопасная практика заключается в обязательном смешивании нескольких источников:
Это снижает риск полного компрометации одного источника.
function mixEntropy(sources) {
sources.forEach(src => {
sjcl.random.addEntropy(src.data, src.strength, src.name);
});
}
SJCL использует внутренний пул состояний, который:
При внешней замене важно учитывать, что переполнение пула без достаточной энтропии снижает качество генерации.
Корректная архитектура внешней замены обычно выглядит так:
sjcl.random.isReady()Эта схема обеспечивает предсказуемость и криптографическую стойкость генерации без зависимости от внутренних механизмов браузера