В прикладной криптографии редко используется «сырой» пароль или исходный ключ напрямую. Причина проста: такие значения обычно не обладают достаточной энтропией и плохо подходят для современных атакующих моделей.
Производные ключи решают сразу несколько задач:
В JavaScript-экосистеме, особенно при работе с JWT/JWE/JWS через
библиотеку jose, эти механизмы реализуются через WebCrypto API
(SubtleCrypto), который jose использует как основной
криптографический backend.
PBKDF2 (Password-Based Key Derivation Function 2) предназначен для получения стойкого ключа из пароля за счёт вычислительно дорогой функции:
K = (P, S, c, dkLen)
где:
Ключевой смысл PBKDF2 — замедлить перебор паролей за счёт большого числа итераций.
В jose напрямую PBKDF2 не оборачивается отдельной утилитой —
используется стандартный crypto.subtle.deriveKey.
Пример получения ключа AES-GCM из пароля:
const enc = new TextEncoder();
const password = 'user-password';
const salt = crypto.getRandomValues(new Uint8Array(16));
const baseKey = await crypto.subtle.importKey(
'raw',
enc.encode(password),
'PBKDF2',
false,
['deriveKey']
);
const derivedKey = await crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt,
iterations: 100000,
hash: 'SHA-256'
},
baseKey,
{
name: 'AES-GCM',
length: 256
},
false,
['encrypt', 'decrypt']
);
HKDF (HMAC-based Key Derivation Function) используется не для паролей, а для расширения уже существующего криптографического ключа.
Он состоит из двух этапов:
Формально:
(IKM, salt, info) = ((IKM, salt), info)
где:
Библиотека jose активно работает с:
В этих схемах часто требуется:
HKDF идеально подходит для этого сценария.
const enc = new TextEncoder();
const masterKey = await crypto.subtle.importKey(
'raw',
enc.encode('master-secret'),
'HKDF',
false,
['deriveKey']
);
const derivedKey = await crypto.subtle.deriveKey(
{
name: 'HKDF',
hash: 'SHA-256',
salt: crypto.getRandomValues(new Uint8Array(16)),
info: enc.encode('jose-encryption-context')
},
masterKey,
{
name: 'AES-GCM',
length: 256
},
false,
['encrypt']
);
infoinfo — это ключевая особенность HKDF. Он позволяет
привязать ключ к конкретному контексту использования.
Примеры значений:
"jose.jwt.sign""jose.jwt.encrypt""session-key-v1"Это защищает от атак повторного использования ключей в разных сценариях.
| Характеристика | PBKDF2 | HKDF |
|---|---|---|
| Вход | пароль | криптографический ключ |
| Основная цель | защита от перебора | расширение ключей |
| Использование соли | обязательно | рекомендуется |
| Контекст (info) | отсутствует | обязательный элемент дизайна |
| Производительность | медленный | быстрый |
| Современность | устаревает | актуальный стандарт |
В экосистеме jose ключи редко создаются «вручную». Вместо этого:
Пример типичного сценария:
В процессе JWE часто требуется:
HKDF может использоваться для детерминированного вывода этих ключей из одного источника.
Пример концептуальной схемы:
Это обеспечивает изоляцию криптографических ролей.
Слишком маленькое значение делает систему уязвимой к перебору.
Повторяемость ключей при одинаковых паролях.
info в
HKDFУбирает контекстную защиту и превращает HKDF в менее безопасную конструкцию.
Один ключ для шифрования и подписи — критическая ошибка.
При построении системы на jose важно разделять уровни:
Такая структура обеспечивает:
PBKDF2 остаётся совместимым стандартом, но в современных системах часто рассматриваются альтернативы:
HKDF же остаётся базовым строительным блоком современных протоколов (TLS 1.3, JOSE-экосистема, WebAuthn-подобные схемы).
В системах, построенных на jose, производные ключи обычно формируют цепочку:
Такой подход позволяет не хранить и не использовать напрямую исходные секреты, а работать только с производными материалами, строго ограниченными по контексту применения.