Метод subtle.unwrapKey

Метод SubtleCrypto.unwrapKey используется для преобразования зашифрованного ключевого материала обратно в объект CryptoKey с помощью другого криптографического ключа, выполняющего роль ключа для «развёртывания» (unwrapping). По сути, это операция обратная wrapKey: если wrapKey упаковывает ключ в безопасный переносимый формат, то unwrapKey восстанавливает его из этого состояния.

Работа метода строго зависит от выбранных алгоритмов, формата ключа и контекста криптографической операции, так как Web Crypto API требует явного указания всех параметров преобразования.


Метод вызывается через интерфейс SubtleCrypto:

crypto.subtle.unwrapKey(
  format,
  wrappedKey,
  unwrappingKey,
  unwrapAlgo,
  unwrappedKeyAlgo,
  extractable,
  keyUsages
);

Возвращаемое значение — Promise<CryptoKey>.


Форматы входных данных (format)

Параметр format определяет способ представления зашифрованного ключа:

  • "raw" — необработанные байты ключа
  • "pkcs8" — приватный ключ в формате PKCS#8
  • "spki" — публичный ключ в формате SubjectPublicKeyInfo
  • "jwk" — JSON Web Key

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


wrappedKey

wrappedKey — это зашифрованный ключевой материал, представленный как ArrayBuffer или TypedArray.

Он является результатом crypto.subtle.wrapKey, где ключ был защищён с использованием криптографического алгоритма (например, AES-GCM или RSA-OAEP).


unwrappingKey

unwrappingKey — объект CryptoKey, используемый для расшифровки wrappedKey.

Он должен быть:

  • доступен для операции "decrypt"
  • совместим с алгоритмом, указанным в unwrapAlgo
  • уже импортирован или сгенерирован в рамках Web Crypto API

Примеры алгоритмов для ключа развёртывания:

  • AES-GCM
  • RSA-OAEP
  • AES-KW (Key Wrap)

unwrapAlgo

Параметр unwrapAlgo описывает алгоритм, с помощью которого был зашифрован ключ.

Чаще всего используется:

AES-GCM

{
  name: "AES-GCM",
  iv: ivBuffer
}

RSA-OAEP

{
  name: "RSA-OAEP"
}

Этот параметр должен строго соответствовать алгоритму, использованному при wrapKey.


unwrappedKeyAlgo

unwrappedKeyAlgo описывает алгоритм будущего ключа, который будет получен после операции.

Пример для AES-256:

{
  name: "AES-GCM",
  length: 256
}

Для RSA:

{
  name: "RSA-PSS",
  hash: "SHA-256"
}

Этот объект аналогичен параметрам метода importKey, так как unwrapKey фактически выполняет импорт после расшифровки.


extractable

Булевый параметр, определяющий возможность дальнейшего экспорта ключа:

  • true — ключ можно экспортировать через exportKey
  • false — ключ остаётся внутри Web Crypto API

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


keyUsages

Массив строк, определяющий допустимые операции с восстановленным ключом:

  • "encrypt"
  • "decrypt"
  • "sign"
  • "verify"
  • "deriveKey"
  • "deriveBits"
  • "wrapKey"
  • "unwrapKey"

Пример:

["encrypt", "decrypt"]

Если указанные usage не соответствуют алгоритму ключа, браузер выдаст ошибку.


Пример использования с AES-GCM

Сценарий: ключ был упакован с использованием AES-GCM и затем восстанавливается тем же алгоритмом.

const wrappedKeyBuffer = /* ArrayBuffer с зашифрованным ключом */;
const iv = /* initialization vector */;

const unwrappingKey = await crypto.subtle.importKey(
  "raw",
  secretKeyMaterial,
  { name: "AES-GCM" },
  false,
  ["decrypt"]
);

const key = await crypto.subtle.unwrapKey(
  "raw",
  wrappedKeyBuffer,
  unwrappingKey,
  { name: "AES-GCM", iv },
  { name: "AES-GCM", length: 256 },
  true,
  ["encrypt", "decrypt"]
);

Пример использования с RSA-OAEP

RSA часто применяется для защиты симметричных ключей.

const unwrappingKey = await crypto.subtle.importKey(
  "pkcs8",
  privateKeyBuffer,
  {
    name: "RSA-OAEP",
    hash: "SHA-256"
  },
  false,
  ["decrypt"]
);

const aesKey = await crypto.subtle.unwrapKey(
  "raw",
  wrappedAesKey,
  unwrappingKey,
  {
    name: "RSA-OAEP"
  },
  {
    name: "AES-GCM",
    length: 256
  },
  true,
  ["encrypt", "decrypt"]
);

Взаимосвязь с wrapKey

unwrapKey всегда предполагает наличие предварительного вызова wrapKey:

  • wrapKey → шифрует CryptoKey и экспортирует его
  • unwrapKey → расшифровывает и импортирует обратно в CryptoKey

Если алгоритмы не совпадают, операция невозможна.


Типовые ошибки

Несоответствие алгоритмов

Если unwrapAlgo отличается от использованного при wrapKey, результатом будет OperationError.


Неверный формат ключа

Переданный format должен совпадать с исходным форматом при упаковке.


Ошибки в keyUsages

Несоответствие между назначением ключа и usage приводит к SyntaxError.


Неподходящий unwrappingKey

Ключ должен поддерживать операцию "decrypt", иначе будет ошибка InvalidAccessError.


Безопасностные особенности

Операция unwrapKey считается чувствительной, так как:

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

Критично ограничивать:

  • extractable
  • keyUsages
  • жизненный цикл unwrappingKey

Особенности реализации в браузерах

  • Операция всегда асинхронная
  • Возвращаемый объект CryptoKey не содержит сырого ключевого материала (если extractable=false)
  • Все операции выполняются внутри изолированной криптографической подсистемы браузера
  • Поддержка алгоритмов зависит от конкретной реализации Web Crypto API

Типовой сценарий использования в протоколах

unwrapKey часто применяется в гибридной криптографии:

  1. Генерация симметричного ключа (AES)
  2. Шифрование данных этим ключом
  3. Упаковка AES-ключа через RSA публичным ключом
  4. Передача зашифрованного ключа
  5. Восстановление через unwrapKey на стороне получателя

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