В криптографических системах качество случайности напрямую определяет устойчивость ключей, nonce, IV и всех операций, связанных с генерацией секретов. В JavaScript-среде задача усложняется тем, что выполнение кода происходит в предсказуемой виртуальной машине, а доступ к аппаратным источникам случайности ограничен. Именно поэтому в Stanford JavaScript Crypto Library (SJCL) особое внимание уделяется сбору и агрегации энтропии из множества слабых источников, а также механизму её пополнения извне.
В основе случайности в библиотеке лежит модуль
sjcl.random. Он реализует криптографически стойкий
генератор псевдослучайных чисел (CSPRNG), который периодически
«подпитывается» энтропией из окружающей среды.
Генератор устроен как буферизированная система:
Главная идея заключается не в том, чтобы мгновенно получать идеальную случайность, а в том, чтобы постепенно накапливать достаточную энтропию перед использованием.
SJCL использует несколько категорий источников случайности:
Наиболее ценные источники:
Эти события содержат высокую степень непредсказуемости, особенно в таймингах между событиями и координатах.
Каждое событие преобразуется в набор числовых значений:
Далее эти данные преобразуются в энтропийные блоки.
Даже без активности пользователя браузер генерирует события:
Разница между ожидаемым и фактическим временем исполнения используется как слабый, но полезный источник случайности.
В зависимости от окружения могут использоваться:
window.crypto.getRandomValues (если доступен)performance.now())Однако SJCL не полагается исключительно на них, а рассматривает как дополнение.
Ключевой механизм расширения случайности в SJCL — функция:
sjcl.random.addEntropy(data, bits, source);
Она позволяет явно внести дополнительные данные в пул энтропии.
Параметры функции:
data — входные данные (число, массив или строка)bits — оценка количества бит реальной энтропииsource — идентификатор источникаПараметр bits не описывает размер данных, а оценивает их
непредсказуемость.
Пример:
Эта оценка критична: завышение делает систему уязвимой, занижение — замедляет «разогрев» генератора.
document.addEventListener("click", function (e) {
sjcl.random.addEntropy([
e.clientX,
e.clientY,
Date.now()
], 2, "mouse_click");
});
Здесь каждое событие клика добавляет небольшое количество энтропии, основанное на координатах и времени.
SJCL хранит энтропию в нескольких пулах. Каждому источнику соответствует свой вклад, который затем смешивается.
Процесс включает:
Чем выше пул, тем более строгие требования к качеству случайности для его использования.
Перед использованием криптографических операций важно убедиться, что энтропии достаточно.
Используется:
sjcl.random.isReady(threshold);
где threshold — уровень уверенности (например, 1, 2 или
3).
Также существует:
sjcl.random.getProgress(threshold);
Он возвращает степень готовности от 0 до 1.
Если генератор не готов, SJCL может блокировать выполнение операций:
Это критично для предотвращения использования слабых seed-значений.
В реальных системах часто используется дополнительная стратегия: загрузка энтропии извне.
Пример использования серверного значения:
fetch("/entropy")
.then(res => res.arrayBuffer())
.then(buf => {
sjcl.random.addEntropy(
new Uint8Array(buf),
128,
"server_seed"
);
});
Такой подход особенно полезен при:
Практическая безопасность требует комбинирования источников:
SJCL не требует наличия всех источников одновременно, но устойчивость растёт при их объединении.
После старта приложения генератор может находиться в состоянии низкой энтропии. В этот период важно:
Типичный паттерн:
Если приложение полагается только на
crypto.getRandomValues, это снижает гибкость и устойчивость
в старых окружениях.
Самая критичная ошибка — переоценка энтропии. Например:
могут быть ошибочно приняты за случайные данные.
Использование PRNG до накопления достаточной энтропии приводит к:
SJCL интегрируется в event-driven модель Jav * aScript:
Это позволяет собирать энтропию без влияния на производительность интерфейса.
Основная криптографическая идея SJCL заключается в том, что ни один источник не считается полностью надёжным. Вместо этого используется принцип:
Это снижает риск компрометации одного источника.
В реальных приложениях использование энтропии обычно выглядит как непрерывный процесс:
Такой подход позволяет обеспечить стабильное криптографическое поведение даже в ограниченных средах браузера.