Функции деривации ключей: PBKDF2, Argon2 и scrypt в сравнении
Сравните функции деривации ключей для парольного шифрования. Преимущества PBKDF2, Argon2 и scrypt.
Для ключей шифрования, производных от пароля, в 2026 году рекомендуется Argon2id (победитель PHC, топ-выбор OWASP, активно защищён от GPU и ASIC-атак), scrypt — надёжная альтернатива (устойчив к памяти, широко применяется в криптовалютах), а PBKDF2-SHA-256 с 600 000+ итерациями остаётся приемлемым из соображений совместимости, но обеспечивает минимальную устойчивость к GPU. Для приложений передачи файлов, где пользователь вводит пароль для защиты общего файла, Argon2id с 3 итерациями, 64 МиБ памяти и 4 степенями параллелизма — современный базовый уровень. PBKDF2 сохраняет актуальность, поскольку встроен в Web Crypto API и не требует зависимости от WASM. Ниже разобраны различия между тремя вариантами и когда каждый из них уместен.
Сравнительная таблица
| Свойство | PBKDF2 | scrypt | Argon2id | |---|---|---|---| | Год появления | 2000 (RFC 2898) | 2009 (RFC 7914) | 2015 (победитель PHC) | | Устойчивость к памяти | Нет | Да | Да | | Гибкость параметров | Только итерации | N, r, p | time, memory, parallelism | | Устойчивость к GPU | Слабая | Умеренная | Высокая | | Устойчивость к ASIC | Очень слабая | Умеренная | Высокая | | Нативная поддержка браузера (Web Crypto) | Да | Нет | Нет | | Рекомендация OWASP 2024 | Допустимый фолбэк | Допустимый | Предпочтительный | | Типичная нагрузка в браузере (современное железо) | 600 000 итер. ≈ 500 мс | N=2^17 ≈ 800 мс | 3 итер., 64 МиБ ≈ 1 с |
Почему устойчивость к памяти важна
Модель угроз для шифрования на основе пароля — автономный перебор. Злоумышленник захватывает шифртекст вместе с солью, перебирает словарь паролей и пытается вывести ключ, успешно расшифровывающий данные. Защита — сделать каждую попытку дорогостоящей.
PBKDF2 делает каждую попытку дорогостоящей только по времени ЦП (итерации SHA-256). Современные GPU выполняют миллиарды операций SHA-256 в секунду; игровой GPU может проверить 10–100 миллионов угадываний PBKDF2-SHA-256-600000 в день. ASIC-атакующие справляются на порядки лучше.
Устойчивые к памяти функции (scrypt, Argon2) требуют фиксированного объёма памяти на каждую попытку. GPU и ASIC имеют ограниченную пропускную способность памяти, поэтому параллелизм на устройство ограничен. Требование 64 МиБ памяти означает, что GPU с 16 ГБ VRAM может выполнять не более 256 параллельных попыток, а не миллионы. Экономическая стоимость перебора возрастает на 2–3 порядка.
PBKDF2: устаревший стандарт по умолчанию
PBKDF2 (RFC 2898) итерирует псевдослучайную функцию, как правило HMAC-SHA-256 или HMAC-SHA-512, поверх пароля и соли. Количество итераций — единственный настраиваемый параметр.
const passwordKey = await crypto.subtle.importKey(
"raw", new TextEncoder().encode(password),
"PBKDF2", false, ["deriveKey"]
);
const aesKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt, // 16 случайных байт
iterations: 600000,
hash: "SHA-256",
},
passwordKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
OWASP 2023 рекомендует минимум 600 000 итераций PBKDF2-SHA-256. NIST SP 800-132 более старый и менее конкретный. Некоторые настройки (например, 100 100 итераций по умолчанию в LastPass в 2018 году) считаются недостаточными в 2026 году.
Преимущества: встроен в Web Crypto, не требует WASM, FIPS-валидирован, поддерживается в возобновлении сессий TLS 1.3, работает в Node и браузерах одинаково.
Ограничения: нет устойчивости к памяти, уязвим к GPU и ASIC-ускорению. Удвоение итераций удваивает стоимость для злоумышленника, но также удваивает её для легитимного пользователя. В какой-то момент пользователи не готовы ждать и количество итераций ограничивается.
scrypt: первое практическое решение с устойчивостью к памяти
scrypt (RFC 7914) был изобретён Колином Перциваль в 2009 году для Tarsnap. Алгоритм пропускает материал пароля через большой буфер памяти, вынуждая злоумышленника удерживать этот буфер при каждой попытке.
Три параметра:
- N: фактор стоимости (обычно 2^14–2^20). Использование памяти приблизительно 128 * N * r байт.
- r: размер блока (обычно 8). Влияет на объём памяти и количество итераций GHASH.
- p: параллелизм (обычно 1). Большие значения ускоряют легитимные вычисления, но также ускоряют атаку; как правило, оставляют равным 1.
OWASP рекомендует N=2^17, r=8, p=1 в качестве базового уровня, что потребляет около 128 МиБ и выполняется примерно за 800 мс на современном железе.
scrypt не входит в Web Crypto API. В JavaScript используйте scrypt-js, @noble/hashes или libsodium.js. Litecoin и Dogecoin используют scrypt как алгоритм доказательства работы, что стимулировало разработку ASIC именно для scrypt, несколько подрывая его первоначальное асимметричное преимущество перед ASIC.
Argon2id: стандарт 2026 года
Argon2 победил в Password Hashing Competition в 2015 году. Три варианта: Argon2d (быстрейший, с зависимостью от данных, уязвим к побочным каналам), Argon2i (независимый от данных, медленнее), Argon2id (гибридный, рекомендуется для большинства задач). RFC 9106 стандартизировал его в 2021 году.
Три параметра:
- t (time): итерации через память. Обычно 2–3.
- m (memory): память в КиБ. Обычно 65 536 (64 МиБ) или выше.
- p (parallelism): степень параллелизма. Обычно 1–4.
Базовый уровень OWASP 2024: t=2, m=19456 (19 МиБ), p=1 — минимальный; t=3, m=65536 (64 МиБ), p=4 — усиленная защита.
import { argon2id } from '@noble/hashes/argon2';
import { utf8ToBytes } from '@noble/hashes/utils';
const derivedKey = argon2id(utf8ToBytes(password), salt, {
t: 3, m: 65536, p: 4, dkLen: 32
});
Или через argon2-browser (WASM):
import argon2 from 'argon2-browser';
const hash = await argon2.hash({
pass: password, salt,
type: argon2.ArgonType.Argon2id,
time: 3, mem: 65536, parallelism: 4, hashLen: 32
});
Argon2id эффективнее противостоит GPU-атакующим, чем scrypt, потому что его паттерн доступа к памяти менее пригоден для оптимизаций с большим объёмом памяти. ASIC для Argon2 существуют в исследовательской среде, но ещё не развёрнуты в экономически значимом масштабе атакующими.
Выбор параметров для вашего приложения
Метод калибровки: выберите максимальное время ожидания, которое готовы терпеть ваши пользователи (обычно 500 мс — 2 с), измерьте на самом медленном целевом устройстве и установите параметры для достижения этого бюджета.
Для защищённых паролем файловых ресурсов в стиле HexaTransfer, где деривация выполняется один раз при загрузке и один раз при скачивании, 1–2 секунды приемлемы. Параметры:
- PBKDF2-SHA-256: 600 000–1 200 000 итераций
- scrypt: N=2^17, r=8, p=1
- Argon2id: t=3, m=65536, p=4
Для систем входа, где пользователь ждёт после ввода пароля, 300–500 мс — потолок UX. Параметры примерно вдвое меньше. Для фоновых сценариев, где пользователь не ждёт (например, повторное шифрование в фоне), можно поднять до 3–5 секунд.
Управление солью
Всем трём KDF нужна соль. Правила:
- Минимум 16 случайных байт.
- Генерируется через
crypto.getRandomValues(), никогда черезMath.random(). - Уникальна на каждый пароль (если Алиса и Боб используют один пароль, их соли должны различаться, чтобы выводимые ключи отличались).
- Не секретна — хранится вместе с шифртекстом.
Перец (секрет, добавляемый ко всем выводам) иногда обсуждается. Для передачи файлов, где «сервер» — простое хранилище объектов, перец не даёт ценности, поскольку нет серверного секрета. В системах с аккаунтами серверный перец, хранящийся отдельно от базы паролей, делает дампы базы менее полезными для злоумышленников.
Миграция между KDF
Если у вас есть существующая система на PBKDF2 и вы хотите перейти на Argon2id:
- Храните идентификатор KDF в метаданных шифртекста (
"kdf": "pbkdf2-sha256-600000"или"kdf": "argon2id-3-65536-4"). - Для новых загрузок используйте Argon2id.
- При расшифровке читайте идентификатор KDF и используйте соответствующую функцию.
- Никогда не обновляйте старые шифртексты вслепую: для повторного вывода нужен пароль.
LastPass, 1Password и Bitwarden прошли через эту миграцию. Все трое сейчас используют PBKDF2 с 600 000+ итерациями по умолчанию, с Argon2id в более новых версиях. Даже менеджеры паролей были медленны с переходом на Argon2 — он внедряется постепенно, поскольку инструментарий экосистемы созревал со временем.
А как насчёт bcrypt?
bcrypt (1999) — достойная функция хеширования паролей с умеренной устойчивостью к памяти. Она ограничивает ввод 72 байтами (известная проблема — длинные пароли молча усекаются перед хешированием). Это исторический стандарт в Ruby on Rails и многих PHP-фреймворках. Для нового кода в 2026 году предпочтительнее Argon2id; bcrypt подходит для поддержки существующих систем.
Практическая рекомендация
Для нового сервиса передачи файлов в 2026 году:
- Если вы можете добавить зависимость 15–200 КБ: Argon2id через @noble/hashes или libsodium.js.
- Если нужны нулевые зависимости и минимальный размер бандла: PBKDF2-SHA-256 с 600 000 итерациями через Web Crypto.
- Если пишете криптовалютный кошелёк или наследуете устаревший scrypt: scrypt при N=2^17.
Для production-приложений, работающих с чувствительными файлами, Argon2id стоит WASM-зависимости. Для простых защищённых паролем ресурсов, где пользователи в любом случае генерируют случайный пароль, PBKDF2 достаточен — энтропия в пароле, а не в KDF.
Попробуйте на hexatransfer.com — бесплатно, без регистрации, до 10 ГБ.
Безопасная отправка больших файлов со сквозным шифрованием
Передавайте файлы до 10 ГБ бесплатно со сквозным шифрованием. Регистрация не требуется. Ваши файлы шифруются в браузере перед загрузкой — никто другой не может их прочитать.
Отправить файл