Метод subtle.importKey

Назначение метода

Метод crypto.subtle.importKey() используется для преобразования внешнего представления ключа (сырого массива байтов, JWK-объекта, ключа в формате PKCS#8 или SPKI) в объект CryptoKey, с которым работает Web Crypto API.

Этот этап является обязательным, когда ключ:

  • хранится вне Web Crypto API (например, на сервере или в localStorage),
  • передаётся в виде сериализованного значения,
  • импортируется из внешних криптографических систем.

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


Сигнатура

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

Параметр format

Определяет формат входного ключа. Поддерживаются четыре основных варианта:

“raw”

Сырые байты ключа.

Используется для:

  • симметричных ключей (AES)
  • секретов для HMAC
  • входных данных PBKDF2
new Uint8Array([1, 2, 3, 4])

“jwk”

JSON Web Key — объект в формате JSON.

Пример:

{
  "kty": "oct",
  "k": "base64url-encoded-key",
  "alg": "A256GCM",
  "ext": true
}

“pkcs8”

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

Формат:

  • DER-encoded ASN.1 структура
  • ArrayBuffer

“spki”

Используется для публичных ключей.

Формат:

  • SubjectPublicKeyInfo
  • DER-encoded

keyData

Входные данные ключа. Тип зависит от format:

format keyData
raw ArrayBuffer / TypedArray
jwk Object
pkcs8 ArrayBuffer
spki ArrayBuffer

algorithm

Описывает криптографический алгоритм, для которого импортируется ключ.

Объект всегда содержит поле name, остальные зависят от алгоритма.


AES

{ name: "AES-GCM" }
{ name: "AES-CBC" }
{ name: "AES-KW" }

HMAC

{
  name: "HMAC",
  hash: "SHA-256"
}

RSA

{
  name: "RSA-OAEP",
  hash: "SHA-256"
}
{
  name: "RSASSA-PKCS1-v1_5",
  hash: "SHA-512"
}

ECDSA / ECDH

{
  name: "ECDSA",
  namedCurve: "P-256"
}
{
  name: "ECDH",
  namedCurve: "P-384"
}

PBKDF2 (импорт пароля как ключевого материала)

{
  name: "PBKDF2"
}

extractable

Булево значение:

  • true — ключ можно экспортировать обратно через exportKey
  • false — ключ становится неизвлекаемым

Ключевая характеристика безопасности:

  • неизвлекаемые ключи предпочтительнее для production-сценариев

keyUsages

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

Возможные значения:

Симметричные ключи

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

Асимметричные ключи

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

Возвращаемое значение

Метод возвращает Promise<CryptoKey>.

const key = await crypto.subtle.importKey(...)

Импорт AES ключа (raw)

const rawKey = new Uint8Array([
  21, 31, 42, 55, 66, 77, 88, 99,
  10, 20, 30, 40, 50, 60, 70, 80
]);

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

Импорт HMAC ключа

const secret = new TextEncoder().encode("super-secret");

const key = await crypto.subtle.importKey(
  "raw",
  secret,
  {
    name: "HMAC",
    hash: "SHA-256"
  },
  true,
  ["sign", "verify"]
);

Импорт RSA публичного ключа (SPKI)

const spki = new Uint8Array([...]); // DER data

const publicKey = await crypto.subtle.importKey(
  "spki",
  spki.buffer,
  {
    name: "RSA-OAEP",
    hash: "SHA-256"
  },
  true,
  ["encrypt"]
);

Импорт RSA приватного ключа (PKCS#8)

const pkcs8 = new Uint8Array([...]);

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

Импорт ключа в формате JWK

Симметричный ключ (AES)

const jwk = {
  kty: "oct",
  k: "mX4f3s9kq0xYv2zA1bC9dQ",
  alg: "A256GCM",
  ext: true
};

const key = await crypto.subtle.importKey(
  "jwk",
  jwk,
  { name: "AES-GCM" },
  true,
  ["encrypt", "decrypt"]
);

RSA ключ (JWK)

const jwk = {
  kty: "RSA",
  n: "...modulus...",
  e: "AQAB",
  d: "...privateExponent...",
  alg: "RSA-OAEP-256",
  ext: true
};

const privateKey = await crypto.subtle.importKey(
  "jwk",
  jwk,
  {
    name: "RSA-OAEP",
    hash: "SHA-256"
  },
  true,
  ["decrypt"]
);

Импорт ключа для PBKDF2

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

const password = new TextEncoder().encode("password123");

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

Далее используется deriveKey:

const derivedKey = await crypto.subtle.deriveKey(
  {
    name: "PBKDF2",
    salt: new TextEncoder().encode("salt"),
    iterations: 100000,
    hash: "SHA-256"
  },
  baseKey,
  { name: "AES-GCM", length: 256 },
  false,
  ["encrypt", "decrypt"]
);

Типичные ошибки

DataError

Возникает при:

  • неверном формате keyData
  • несоответствии algorithm и ключа

NotSupportedError

Возникает при:

  • неподдерживаемом format
  • неподдерживаемом алгоритме

SyntaxError

Возникает при:

  • неправильном JWK объекте
  • отсутствующих обязательных полях

Взаимосвязь формата и алгоритма

Алгоритм Поддерживаемые форматы
AES raw, jwk
HMAC raw, jwk
RSA spki, pkcs8, jwk
ECDSA spki, pkcs8, jwk
ECDH spki, pkcs8, jwk
PBKDF2 raw

Особенности поведения

  • Импорт не выполняет криптографических операций — только преобразование формата
  • Ключ становится привязанным к origin браузера
  • extractable: false нельзя обойти после импорта
  • Web Crypto API не позволяет прямой инспекции содержимого ключа

Безопасные практики использования

  • минимизировать использование extractable: true
  • передавать ключи только по защищённому каналу (HTTPS)
  • избегать хранения приватных ключей в JWK без необходимости
  • использовать spki для публичных ключей вместо raw представлений
  • ограничивать keyUsages строго необходимыми операциями