scrypt в SJCL: подключение и использование

scrypt в SJCL используется как функция вывода ключа (KDF), предназначенная для получения криптографически стойких ключей из паролей с защитой от атак перебором и специализированного оборудования. Основное отличие scrypt от более простых KDF (например, PBKDF2) заключается в высокой требовательности к памяти, что делает массовый перебор существенно дороже по ресурсам.

Библиотека SJCL не всегда включает scrypt в базовую сборку. Модуль может подключаться отдельно, так как относится к более тяжёлым криптографическим операциям.

Обычно структура подключения выглядит так:

<script src="sjcl.js"></script>
<script src="sjcl-scrypt.js"></script>

После подключения расширения становится доступен интерфейс:

sjcl.misc.scrypt

Ключевой момент: без подключения дополнительного модуля вызов функции будет недоступен.

Основной интерфейс функции

Функция scrypt в SJCL вызывается следующим образом:

sjcl.misc.scrypt(password, salt, N, r, p, dkLen)

Параметры:

  • password — строка или bitArray с исходным паролем
  • salt — соль (строка или bitArray), обязательна для защиты от радужных таблиц
  • N — параметр CPU/памяти (должен быть степенью двойки)
  • r — параметр блоков памяти (memory cost)
  • p — параллелизм (parallelization factor)
  • dkLen — длина производного ключа в байтах

Результат возвращается в формате bitArray, используемом внутри SJCL для всех криптографических операций.

Базовый пример использования

var password = "secure-password";
var salt = "random-salt";

var derivedKey = sjcl.misc.scrypt(password, salt, 16384, 8, 1, 32);

var hexKey = sjcl.codec.hex.fromBits(derivedKey);

console.log(hexKey);

В этом примере:

  • N = 16384 задаёт умеренную стойкость и нагрузку
  • r = 8 и p = 1 используются как стандартный баланс
  • dkLen = 32 формирует 256-битный ключ

Влияние параметров N, r и p

Параметр N

N = 2^k

Значение N определяет базовую сложность алгоритма. Увеличение N экспоненциально повышает затраты памяти и времени. Например:

  • 2¹⁴ = 16384 — умеренная безопасность
  • 2¹⁶ = 65536 — высокая нагрузка
  • 2²⁰ = 1048576 — крайне тяжёлые вычисления

Параметр r

Параметр r увеличивает размер внутренних блоков памяти. Рост r линейно увеличивает потребление RAM, усиливая защиту от GPU/ASIC атак.

Параметр p

p определяет количество параллельных потоков вычислений. В большинстве JS-реализаций значение p чаще всего оставляют равным 1, так как увеличение приводит к значительному росту CPU-нагрузки в браузере.

Преобразование результата

SJCL оперирует внутренним типом bitArray, поэтому для дальнейшего использования ключ часто преобразуется:

var hex = sjcl.codec.hex.fromBits(derivedKey);
var base64 = sjcl.codec.base64.fromBits(derivedKey);

Частые сценарии:

  • хранение ключа в hex-формате
  • передача в API в base64
  • использование в AES-GCM внутри SJCL

Использование с шифрованием AES

scrypt обычно применяется как этап генерации ключа для симметричного шифрования:

var key = sjcl.misc.scrypt("password", "salt", 16384, 8, 1, 32);

var cipher = new sjcl.cipher.aes(key);

var encrypted = sjcl.encrypt("password", "секретное сообщение", {
  mode: "gcm"
});

В реальных сценариях ключ из scrypt передаётся напрямую в AES без промежуточных строковых преобразований.

Производительность и ограничения в браузере

scrypt в JavaScript является ресурсоёмкой операцией. В SJCL он выполняется синхронно, что означает блокировку основного потока выполнения.

Практические последствия:

  • при высоких N интерфейс может «замораживаться»
  • мобильные устройства испытывают значительную нагрузку
  • использование требует аккуратного выбора параметров

Типичный диапазон для браузера:

  • N: 2¹⁴ – 2¹⁶
  • r: 8
  • p: 1

Практика выбора параметров

Баланс между безопасностью и производительностью определяется целевым сценарием:

  • аутентификация пользователя в веб-приложении → минимальные параметры
  • локальное шифрование данных → средние параметры
  • долговременное хранение секретов → повышенные параметры с учетом UX

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

Работа с salt и генерация случайных значений

Соль должна быть уникальной для каждого пароля:

var salt = sjcl.random.randomWords(4, 0);

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

Сравнение с PBKDF2 внутри SJCL

SJCL также содержит PBKDF2, который проще в вычислении:

  • PBKDF2 — быстрее, но слабее против GPU атак
  • scrypt — медленнее, но устойчивее за счёт memory-hard дизайна

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

Типичные ошибки при использовании

Часто встречающиеся проблемы:

  • слишком маленький N (создаёт уязвимость к перебору)
  • отсутствие salt или использование фиксированного значения
  • попытка использовать scrypt в основном потоке без оптимизации UX
  • неверная обработка bitArray при конвертации

Внутренний формат данных SJCL

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

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

Работа напрямую со строками без кодеков приводит к ошибкам интерпретации ключей.

Рекомендации по интеграции в проекты

При использовании scrypt в веб-приложениях с SJCL обычно применяют следующую архитектуру:

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

Такая схема исключает необходимость хранения пароля в явном виде и снижает риск компрометации при утечках данных на сервере.