Генерация нескольких ключей из одного мастер-ключа

В криптографических системах часто возникает задача: из одного исходного секрета получить несколько независимых ключей с разными назначениями. Такой исходный секрет обычно называют мастер-ключом или корневым материалом (keying material). В Web Crypto API это реализуется через механизм деривации ключей, позволяющий получать новые криптографические ключи без повторного хранения или передачи исходного секрета.

K_{derived} = (K_{master}, , )

Ключевой принцип: один и тот же мастер-ключ должен порождать разные производные ключи при разных контекстных параметрах, сохраняя криптографическую независимость результатов.


Зачем из одного мастер-ключа получать несколько ключей

Разделение ключей по назначению — базовая практика криптографической инженерии:

  • отдельный ключ для шифрования данных
  • отдельный ключ для HMAC-подписи
  • отдельный ключ для аутентификации сессии
  • отдельный ключ для защиты локального хранилища

Использование одного и того же ключа для всех операций приводит к следующим проблемам:

  • утечка одного контекста компрометирует все остальные
  • нарушение криптографических предположений алгоритмов
  • возможность атак через повторное использование ключевого материала

Деривация ключей позволяет устранить эти риски за счет строгого разделения контекстов.


Криптографические примитивы Web Crypto API для деривации

В Web Crypto API основными механизмами генерации производных ключей являются:

deriveKey

Создаёт новый криптографический ключ из исходного материала.

crypto.subtle.deriveKey(
  algorithm,
  baseKey,
  derivedKeyAlgorithm,
  extractable,
  keyUsages
)

deriveBits

Генерирует необработанные байты ключевого материала:

crypto.subtle.deriveBits(
  algorithm,
  baseKey,
  length
)

importKey

Используется для загрузки мастер-ключа в криптографический контекст:

crypto.subtle.importKey(
  format,
  keyData,
  algorithm,
  extractable,
  usages
)

HKDF как основной механизм разделения ключей

HKDF (HMAC-based Key Derivation Function) — наиболее рекомендуемый способ получения нескольких ключей из одного мастер-секрета. Он основан на HMAC и поддерживает строгую изоляцию контекстов через параметр info.

K_{out} = (K_{in}, , )

Базовый пример использования HKDF в Web Crypto API

const masterKeyMaterial = await crypto.subtle.importKey(
  "raw",
  new TextEncoder().encode("master-secret"),
  "HKDF",
  false,
  ["deriveKey", "deriveBits"]
);

const encryptionKey = await crypto.subtle.deriveKey(
  {
    name: "HKDF",
    hash: "SHA-256",
    salt: crypto.getRandomValues(new Uint8Array(16)),
    info: new TextEncoder().encode("encryption-key")
  },
  masterKeyMaterial,
  {
    name: "AES-GCM",
    length: 256
  },
  false,
  ["encrypt", "decrypt"]
);

const signingKey = await crypto.subtle.deriveKey(
  {
    name: "HKDF",
    hash: "SHA-256",
    salt: crypto.getRandomValues(new Uint8Array(16)),
    info: new TextEncoder().encode("signing-key")
  },
  masterKeyMaterial,
  {
    name: "HMAC",
    hash: "SHA-256",
    length: 256
  },
  false,
  ["sign", "verify"]
);

PBKDF2 как альтернативный механизм

PBKDF2 чаще используется для получения мастер-ключа из пароля, но также может служить базой для дальнейшей деривации.

K = (P, S, c, dkLen)

Где:

  • P — пароль
  • S — соль
  • c — количество итераций
  • dkLen — длина ключа

Пример:

const baseKey = await crypto.subtle.importKey(
  "raw",
  new TextEncoder().encode("user-password"),
  "PBKDF2",
  false,
  ["deriveKey"]
);

const masterKey = await crypto.subtle.deriveKey(
  {
    name: "PBKDF2",
    salt: crypto.getRandomValues(new Uint8Array(16)),
    iterations: 100000,
    hash: "SHA-256"
  },
  baseKey,
  {
    name: "HKDF"
  },
  false,
  ["deriveKey"]
);

PBKDF2 редко используется напрямую для создания нескольких независимых ключей, но часто является стартовой точкой цепочки деривации.


Практическая схема: один мастер-ключ → несколько специализированных ключей

Типовая архитектура включает два уровня:

  1. получение мастер-ключа (из пароля, биометрии или случайного генератора)
  2. derivation layer (HKDF)

Пример архитектуры

const master = await crypto.subtle.importKey(
  "raw",
  crypto.getRandomValues(new Uint8Array(32)),
  "HKDF",
  false,
  ["deriveKey"]
);

const contexts = [
  "db-encryption",
  "session-auth",
  "file-storage"
];

const keys = {};

for (const ctx of contexts) {
  keys[ctx] = await crypto.subtle.deriveKey(
    {
      name: "HKDF",
      hash: "SHA-256",
      salt: crypto.getRandomValues(new Uint8Array(16)),
      info: new TextEncoder().encode(ctx)
    },
    master,
    {
      name: "AES-GCM",
      length: 256
    },
    false,
    ["encrypt", "decrypt"]
  );
}

Контекстная изоляция ключей

Ключевой элемент безопасности — уникальность параметра info. Он выполняет роль «пространства имен» для ключа.

K_1 K_2 info

Даже при одинаковом мастер-ключе изменение info приводит к полностью независимым производным ключам.

Типичные значения info:

  • имя подсистемы
  • идентификатор протокола
  • версия схемы
  • роль ключа (encrypt / sign / mac)

Ошибки при генерации нескольких ключей

1. Повторное использование salt и info

Использование одинаковых параметров приводит к одинаковым ключам.

2. Отсутствие разделения контекста

Если info слишком общий (например, “key”), возникает риск коллизий.

3. Использование одного ключа для разных алгоритмов

Даже при деривации ключи должны строго соответствовать назначению (AES ≠ HMAC).

4. Хранение мастер-ключа в открытом виде

Мастер-ключ должен существовать только в памяти Web Crypto и быть недоступен напрямую.


Рекомендации по проектированию схем деривации

  • всегда использовать HKDF для разделения ключей
  • задавать уникальный info для каждого назначения
  • избегать повторного использования salt между независимыми системами
  • минимизировать доступность masterKey в приложении
  • разделять ключи по алгоритмам и зонам ответственности

Масштабируемая модель деривации

В сложных системах используется иерархическая структура:

K_{service} = (K_{master}, info_{service}) K_{function} = (K_{service}, info_{function})

Такой подход позволяет строить безопасную многоуровневую систему ключей без увеличения количества хранимых секретов.