Перейти к содержанию
HexaTransfer
Вернуться к блогу
Шифрование и безопасность

Функции деривации ключей: 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 ГБ бесплатно со сквозным шифрованием. Регистрация не требуется. Ваши файлы шифруются в браузере перед загрузкой — никто другой не может их прочитать.

Отправить файл