PBKDF2 (Password-Based Key Derivation Function 2) в контексте Stanford Javascript Crypto Library реализован как вычислительно затратная функция, основная цель которой — замедлить перебор паролей за счёт многократного применения псевдослучайной функции (обычно HMAC).
Ключевой параметр алгоритма — число итераций. Он определяет, сколько
раз базовая криптографическая операция будет повторена при выводе ключа
из пароля. В SJCL это значение передаётся как третий аргумент функции
sjcl.misc.pbkdf2.
var key = sjcl.misc.pbkdf2(password, salt, iterations, keySize, prf);
Увеличение числа итераций линейно увеличивает время вычисления ключа, но экспоненциально усложняет атаки перебора при условии массового использования слабых паролей.
PBKDF2 не улучшает энтропию пароля, но усложняет каждую попытку проверки кандидата. При атаке brute-force злоумышленник вынужден выполнять полный цикл вычислений для каждого предполагаемого пароля.
Пусть:
Тогда стоимость проверки одного пароля:
T ≈ n * t
Таким образом, увеличение n в 10 раз увеличивает
стоимость атаки в 10 раз, но одновременно замедляет и легитимную
аутентификацию.
Выбор количества итераций — компромисс между:
На клиентской стороне (браузерный JavaScript) этот баланс особенно критичен, поскольку вычисления выполняются в однопоточном окружении и напрямую влияют на отзывчивость интерфейса.
Типичные диапазоны:
Однако фиксированные значения постепенно теряют актуальность из-за роста вычислительных мощностей GPU и специализированных атакующих систем.
Базовая реализация SJCL позволяет задавать параметры напрямую:
var derivedKey = sjcl.misc.pbkdf2(
"user-password",
sjcl.codec.hex.toBits("a3f1c9..."),
150000,
256,
sjcl.misc.hmac
);
Здесь:
password — исходная строкаsalt — случайная соль в битовом представлении150000 — число итераций256 — размер ключа в битахprf — псевдослучайная функция (обычно HMAC-SHA256)Важный момент: SJCL оперирует битами, а не байтами, что часто становится источником ошибок при переносе кода из других криптобиблиотек.
Корректный выбор числа итераций невозможен без измерений. Основная цель — добиться времени вычисления, приемлемого для пользователя, но достаточного для усложнения перебора.
Практический подход:
n, не превышающее порогПример бенчмарка:
function benchmarkPBKDF2(iterations) {
var start = performance.now();
sjcl.misc.pbkdf2(
"test-password",
sjcl.codec.utf8String.toBits("salt"),
iterations,
256
);
var end = performance.now();
return end - start;
}
Поведение сильно зависит от:
Фиксированное число итераций постепенно теряет эффективность, поэтому применяется адаптивный подход:
iterations вместе с хэшем
пароляСтруктура хранения:
hash = PBKDF2(password, salt, iterations)
И вместе с этим:
{ salt, iterations, hash }
Такой подход позволяет эволюционно повышать стоимость атак без массового принудительного сброса паролей.
PBKDF2 в SJCL выполняется синхронно, что приводит к блокировке основного потока браузера. При высоких значениях итераций это становится заметным:
Частичное решение — выполнение криптографии в Web Workers:
// worker.js
self.onmess age = function(e) {
var result = sjcl.misc.pbkdf2(
e.data.password,
e.data.salt,
e.data.iterations,
256
);
self.postMessage(result);
};
Это переносит нагрузку вне UI-потока, но не уменьшает общее время вычисления.
Рост производительности GPU и появление специализированных ASIC существенно изменили модель угроз. PBKDF2 остаётся CPU-ориентированным алгоритмом, что делает его менее устойчивым по сравнению с memory-hard функциями, однако в SJCL он по-прежнему используется как базовый механизм.
Влияние аппаратных факторов:
Это приводит к необходимости регулярного пересмотра параметра
iterations.
Для реальных систем на базе SJCL применяются следующие ориентиры:
Однако каждый диапазон должен корректироваться под конкретную инфраструктуру и требования к UX.
Частые проблемы:
Особенно критична ситуация, когда значение выбирается «по умолчанию» без тестирования на реальных устройствах пользователей.
Изменение числа итераций требует обратной совместимости:
iterationsТиповая логика:
if (verify(password, hash, salt, oldIterations)) {
newHash = pbkdf2(password, salt, newIterations, 256);
}
Это обеспечивает постепенное усиление криптографической стойкости без массового сброса данных.
Некоторые системы применяют адаптацию:
Такой подход позволяет выравнивать UX между слабыми и мощными устройствами, сохраняя одинаковый уровень безопасности по времени атаки, а не по числу операций.