Добавление пользовательской энтропии

В криптографических системах качество случайности напрямую определяет устойчивость ключей, nonce, IV и всех операций, связанных с генерацией секретов. В JavaScript-среде задача усложняется тем, что выполнение кода происходит в предсказуемой виртуальной машине, а доступ к аппаратным источникам случайности ограничен. Именно поэтому в Stanford JavaScript Crypto Library (SJCL) особое внимание уделяется сбору и агрегации энтропии из множества слабых источников, а также механизму её пополнения извне.


В основе случайности в библиотеке лежит модуль sjcl.random. Он реализует криптографически стойкий генератор псевдослучайных чисел (CSPRNG), который периодически «подпитывается» энтропией из окружающей среды.

Генератор устроен как буферизированная система:

  • внутренняя «пул-энтропия» (entropy pool)
  • накопление битовой неопределённости
  • криптографический PRNG (обычно AES в режиме counter)
  • механизм оценки готовности

Главная идея заключается не в том, чтобы мгновенно получать идеальную случайность, а в том, чтобы постепенно накапливать достаточную энтропию перед использованием.


Источники энтропии в браузерной среде

SJCL использует несколько категорий источников случайности:

Динамические события пользователя

Наиболее ценные источники:

  • движения мыши
  • нажатия клавиш
  • касания экрана
  • прокрутка

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

Каждое событие преобразуется в набор числовых значений:

  • координаты (x, y)
  • временные метки
  • коды клавиш
  • изменения состояния устройства ввода

Далее эти данные преобразуются в энтропийные блоки.


Тайминговые шумы (timing jitter)

Даже без активности пользователя браузер генерирует события:

  • requestAnimationFrame
  • setTimeout / setInterval
  • обработка событий DOM
  • сетевые задержки

Разница между ожидаемым и фактическим временем исполнения используется как слабый, но полезный источник случайности.


Внутренние системные источники

В зависимости от окружения могут использоваться:

  • window.crypto.getRandomValues (если доступен)
  • системные таймеры высокой точности
  • изменения состояния производительности (performance.now())

Однако SJCL не полагается исключительно на них, а рассматривает как дополнение.


Добавление энтропии вручную

Ключевой механизм расширения случайности в SJCL — функция:

sjcl.random.addEntropy(data, bits, source);

Она позволяет явно внести дополнительные данные в пул энтропии.

Параметры функции:

  • data — входные данные (число, массив или строка)
  • bits — оценка количества бит реальной энтропии
  • source — идентификатор источника

Смысл параметра bits

Параметр bits не описывает размер данных, а оценивает их непредсказуемость.

Пример:

  • время с точностью до миллисекунд → ~10–12 бит
  • движение мыши → ~1–3 бита на событие
  • внешнее криптографическое значение → может быть 128+ бит

Эта оценка критична: завышение делает систему уязвимой, занижение — замедляет «разогрев» генератора.


Пример добавления пользовательской энтропии

document.addEventListener("click", function (e) {
    sjcl.random.addEntropy([
        e.clientX,
        e.clientY,
        Date.now()
    ], 2, "mouse_click");
});

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


Внутренняя модель накопления энтропии

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

Процесс включает:

  • сбор входных данных
  • хеширование (обычно SHA-256)
  • распределение по пулам разной «глубины»
  • периодическое перемешивание

Чем выше пул, тем более строгие требования к качеству случайности для его использования.


Оценка готовности генератора

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

Используется:

sjcl.random.isReady(threshold);

где threshold — уровень уверенности (например, 1, 2 или 3).

Также существует:

sjcl.random.getProgress(threshold);

Он возвращает степень готовности от 0 до 1.


Блокировка операций до накопления энтропии

Если генератор не готов, SJCL может блокировать выполнение операций:

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

Это критично для предотвращения использования слабых seed-значений.


Подключение внешних источников энтропии

В реальных системах часто используется дополнительная стратегия: загрузка энтропии извне.

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

fetch("/entropy")
  .then(res => res.arrayBuffer())
  .then(buf => {
      sjcl.random.addEntropy(
          new Uint8Array(buf),
          128,
          "server_seed"
      );
  });

Такой подход особенно полезен при:

  • старте приложения
  • отсутствии пользовательской активности
  • сервер-инициализированных сессиях

Стратегии усиления энтропии

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

  1. Пользовательские события (основной поток)
  2. Системные таймеры
  3. Web Crypto API
  4. Серверные seed-значения

SJCL не требует наличия всех источников одновременно, но устойчивость растёт при их объединении.


Переинициализация и «разогрев» генератора

После старта приложения генератор может находиться в состоянии низкой энтропии. В этот период важно:

  • активно собирать события интерфейса
  • избегать генерации ключей
  • инициировать искусственные события сбора

Типичный паттерн:

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

Опасные ошибки при работе с энтропией

Игнорирование пользовательской активности

Если приложение полагается только на crypto.getRandomValues, это снижает гибкость и устойчивость в старых окружениях.

Завышение оценки bits

Самая критичная ошибка — переоценка энтропии. Например:

  • фиксированные значения времени
  • предсказуемые ID
  • константные строки

могут быть ошибочно приняты за случайные данные.

Раннее использование генератора

Использование PRNG до накопления достаточной энтропии приводит к:

  • повторяемым ключам
  • предсказуемым IV
  • криптографическим уязвимостям

Взаимодействие с браузерной моделью событий

SJCL интегрируется в event-driven модель Jav * aScript:

  • подписка на события DOM
  • асинхронное накопление данных
  • неблокирующая обработка

Это позволяет собирать энтропию без влияния на производительность интерфейса.


Принцип смешивания источников

Основная криптографическая идея SJCL заключается в том, что ни один источник не считается полностью надёжным. Вместо этого используется принцип:

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

Это снижает риск компрометации одного источника.


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

В реальных приложениях использование энтропии обычно выглядит как непрерывный процесс:

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

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