PBKDF2 применяется там, где исходным материалом для ключа выступает пароль пользователя. HKDF используется в сценариях, где уже имеется криптографически стойкий секрет, и требуется детерминированное расширение ключевого материала для разных целей.
PBKDF2 (Password-Based Key Derivation Function 2) решает проблему слабости паролей. Любой пользовательский пароль обладает низкой энтропией, поэтому прямое использование его как ключа недопустимо. PBKDF2 увеличивает стоимость перебора за счёт итераций хеширования.
В Web Crypto API он доступен через
crypto.subtle.deriveKey и deriveBits.
const enc = new TextEncoder();
const passwordKey = await crypto.subtle.importKey(
"raw",
enc.encode("user-password"),
"PBKDF2",
false,
["deriveKey"]
);
const salt = crypto.getRandomValues(new Uint8Array(16));
const derivedKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: 310000,
hash: "SHA-256"
},
passwordKey,
{
name: "AES-GCM",
length: 256
},
false,
["encrypt", "decrypt"]
);
Ключевые характеристики PBKDF2:
iterationsСлабое место PBKDF2 заключается в линейной природе вычислений. Увеличение мощности атакующего железа напрямую уменьшает его эффективность.
HKDF (HMAC-based Extract-and-Expand Key Derivation Function) не предназначен для паролей. Его задача — преобразовать уже безопасный секрет в несколько независимых ключей.
В Web Crypto API HKDF также используется через deriveKey
или deriveBits.
const enc = new TextEncoder();
const inputKeyMaterial = await crypto.subtle.importKey(
"raw",
enc.encode("shared-secret"),
"HKDF",
false,
["deriveKey"]
);
const salt = crypto.getRandomValues(new Uint8Array(16));
const derivedKey = await crypto.subtle.deriveKey(
{
name: "HKDF",
salt: salt,
info: enc.encode("encryption key"),
hash: "SHA-256"
},
inputKeyMaterial,
{
name: "AES-GCM",
length: 256
},
false,
["encrypt", "decrypt"]
);
HKDF состоит из двух этапов:
info)Свойства HKDF:
infoPBKDF2 и HKDF решают принципиально разные задачи, несмотря на схожий интерфейс Web Crypto API.
PBKDF2:
HKDF:
Использование PBKDF2 вместо HKDF приводит к избыточным вычислениям и отсутствию логического разделения ключей. Например, попытка выводить несколько ключей из одного пароля через PBKDF2 с разными salt не создаёт корректной криптографической изоляции контекста.
Использование HKDF вместо PBKDF2 приводит к критической уязвимости: отсутствие защиты от перебора пароля. Любой атакующий получает возможность мгновенно проверять гипотезы о пароле.
Одним из ключевых преимуществ HKDF является возможность безопасного вывода нескольких ключей из одного исходного материала без пересечения областей применения.
const enc = new TextEncoder();
const baseKey = await crypto.subtle.importKey(
"raw",
enc.encode("master-secret"),
"HKDF",
false,
["deriveKey"]
);
const encKey = await crypto.subtle.deriveKey(
{
name: "HKDF",
salt: new Uint8Array(16),
info: enc.encode("encryption"),
hash: "SHA-256"
},
baseKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
const macKey = await crypto.subtle.deriveKey(
{
name: "HKDF",
salt: new Uint8Array(16),
info: enc.encode("authentication"),
hash: "SHA-256"
},
baseKey,
{ name: "HMAC", hash: "SHA-256" },
false,
["sign", "verify"]
);
Разделение через info обеспечивает криптографическую
независимость ключей при сохранении одного источника секретности.
PBKDF2 используется в момент, когда:
HKDF используется в момент, когда:
В Web Crypto API оба алгоритма находятся в одной функциональной категории, но выполняют разные роли в криптографическом конвейере: PBKDF2 превращает небезопасное в пригодное, HKDF структурирует уже безопасное в системно разделённое.