Spec-Zone.ru › Web APIs

SubtleCrypto: метод unwrapKey()

Базовая Широко доступная

Эта функция хорошо отработана и работает на многих устройствах и версиях браузеров. Она доступна в браузерах с июля 2015 года.

  • Узнать больше
  • Полная совместимость
  • Отправить отзыв

Безопасный контекст: Эта функция доступна только в безопасных контекстах (HTTPS), в некоторых или во всех поддерживающих браузерах.

Примечание: Эта функция доступна в Web Workers.

Метод unwrapKey() интерфейса SubtleCrypto "распаковывает" ключ. Это означает, что он принимает на вход ключ, который был экспортирован и затем зашифрован (также называется "завёрнутым"). Он расшифровывает ключ и затем импортирует его, возвращая объект CryptoKey, который можно использовать в Web Crypto API.

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

Но поскольку unwrapKey() также расшифровывает импортируемый ключ, вам также необходимо передать ключ, который должен быть использован для его расшифровки. Это иногда называется "ключом для распаковки".

Обратной операцией к unwrapKey() является SubtleCrypto.wrapKey(): в то время как unwrapKey состоит из расшифровки + импорта, wrapKey состоит из шифрования + экспорта.

Синтаксис

unwrapKey(format, wrappedKey, unwrappingKey, unwrapAlgo, unwrappedKeyAlgo, extractable, keyUsages)

Параметры

format

Строка, описывающая формат данных ключа для распаковки. Может быть одним из следующих:

  • raw: формат «сырой».
  • pkcs8: формат PKCS #8.
  • spki: формат SubjectPublicKeyInfo.
  • jwk: формат JSON Web Key.
wrappedKey

ArrayBuffer, содержащий зашифрованный ключ в указанном формате.

unwrappingKey

CryptoKey, который будет использоваться для расшифровки зашифрованного ключа. Ключ должен иметь установленное значение unwrapKey.

unwrapAlgo

Объект, определяющий алгоритм для расшифровки зашифрованного ключа и любые необходимые дополнительные параметры:

  • Для использования RSA-OAEP, передайте объект RsaOaepParams.
  • Для использования AES-CTR, передайте объект AesCtrParams.
  • Для использования AES-CBC, передайте объект AesCbcParams.
  • Для использования AES-GCM, передайте объект AesGcmParams.
  • Для использования AES-KW, передайте строку "AES-KW" или объект вида { "name": "AES-KW }.
unwrappedKeyAlgo

Объект, определяющий тип ключа для распаковки и предоставляющий дополнительные параметры, специфичные для алгоритма, если это необходимо.

  • Для RSASSA-PKCS1-v1_5, RSA-PSS или RSA-OAEP: передайте объект RsaHashedImportParams.
  • Для ECDSA или ECDH: передайте объект EcKeyImportParams.
  • Для HMAC: передайте объект HmacImportParams.
  • Для AES-CTR, AES-CBC, AES-GCM или AES-KW: передайте строку, определяющую алгоритм, или объект вида { "name": ALGORITHM }, где ALGORITHM — имя алгоритма.
  • Для Ed25519: передайте объект вида { "name": "Ed25519" }.
  • Для X25519: передайте объект вида {name: 'X25519'}.
extractable

Булево значение, указывающее, будет ли возможным экспортировать ключ с помощью SubtleCrypto.exportKey() или SubtleCrypto.wrapKey().

keyUsages

Array, указывающий, что можно делать с ключом. Возможные значения массива:

  • encrypt: ключ можно использовать для шифрования сообщений.
  • decrypt: ключ можно использовать для расшифрования сообщений.
  • sign: ключ можно использовать для подписи сообщений.
  • verify: ключ можно использовать для проверки подписей.
  • deriveKey: ключ можно использовать для вывода нового ключа.
  • deriveBits: ключ можно использовать для вывода битов.
  • wrapKey: ключ можно использовать для завёртывания ключа.
  • unwrapKey: ключ можно использовать для распаковки ключа.

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

Promise, который выполняется с распакованным ключом в виде объекта CryptoKey.

Исключения

Обещание отклоняется, когда возникает одно из следующих исключений:

InvalidAccessError DOMException

Возникает, когда ключ для распаковки не является ключом для запрошенного алгоритма распаковки или если значение keyUsages этого ключа не содержит unwrap.

NotSupported DOMException

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

SyntaxError DOMException

Возникает, когда keyUsages пусто, но распакованный ключ имеет тип secret или private.

TypeError

Возникает при попытке использовать неверный формат.

Поддерживаемые алгоритмы

Метод unwrapKey() поддерживает те же алгоритмы, что и метод wrapKey().

Примеры

Примечание: Вы можете попробовать рабочие примеры на GitHub.

Распаковка ключа "сырого" формата

В этом примере мы распаковываем симметричный ключ AES-GCM. Ключ был экспортирован в формате "сырой" и зашифрован с использованием алгоритма AES-KW с ключом, выведенным из пароля.

Для распаковки мы запрашиваем у пользователя пароль и используем PBKDF2 и некоторый соль для вывода ключа AES-KW распаковки. Соль должна быть такой же, как соль, которая использовалась для вывода исходного ключа AES-KW заворачивания.

После получения ключа распаковки мы передаём его в unwrapKey() вместе с зашифрованным ключом и другими параметрами. См. полный код на GitHub.

/*
Salt that is to be used in derivation of the key-wrapping key,
alongside the password the user supplies.
This must match the salt value that was originally used to derive
the key.
*/
const saltBytes = [
  89, 113, 135, 234, 168, 204, 21, 36, 55, 93, 1, 132, 242, 242, 192, 156,
];

/*
The wrapped key itself.
*/
const wrappedKeyBytes = [
  171, 223, 14, 36, 201, 233, 233, 120, 164, 68, 217, 192, 226, 80, 224, 39,
  199, 235, 239, 60, 212, 169, 100, 23, 61, 54, 244, 197, 160, 80, 109, 230,
  207, 225, 57, 197, 175, 71, 80, 209,
];

/*
Convert an array of byte values to an ArrayBuffer.
*/
function bytesToArrayBuffer(bytes) {
  const bytesAsArrayBuffer = new ArrayBuffer(bytes.length);
  const bytesUint8 = new Uint8Array(bytesAsArrayBuffer);
  bytesUint8.set(bytes);
  return bytesAsArrayBuffer;
}

/*
Get some key material to use as input to the deriveKey method.
The key material is a password supplied by the user.
*/
function getKeyMaterial() {
  let password = window.prompt("Enter your password");
  let enc = new TextEncoder();
  return window.crypto.subtle.importKey(
    "raw",
    enc.encode(password),
    { name: "PBKDF2" },
    false,
    ["deriveBits", "deriveKey"],
  );
}

/*
Derive an AES-KW key using PBKDF2.
*/
async function getUnwrappingKey() {
  // 1. get the key material (user-supplied password)
  const keyMaterial = await getKeyMaterial();
  // 2 initialize the salt parameter.
  // The salt must match the salt originally used to derive the key.
  // In this example it's supplied as a constant "saltBytes".
  const saltBuffer = bytesToArrayBuffer(saltBytes);
  // 3 derive the key from key material and salt
  return window.crypto.subtle.deriveKey(
    {
      name: "PBKDF2",
      salt: saltBuffer,
      iterations: 100000,
      hash: "SHA-256",
    },
    keyMaterial,
    { name: "AES-KW", length: 256 },
    true,
    ["wrapKey", "unwrapKey"],
  );
}

/*
Unwrap an AES secret key from an ArrayBuffer containing the raw bytes.
Takes an array containing the bytes, and returns a Promise
that will resolve to a CryptoKey representing the secret key.
*/
async function unwrapSecretKey(wrappedKey) {
  // 1. get the unwrapping key
  const unwrappingKey = await getUnwrappingKey();
  // 2. initialize the wrapped key
  const wrappedKeyBuffer = bytesToArrayBuffer(wrappedKey);
  // 3. unwrap the key
  return window.crypto.subtle.unwrapKey(
    "raw", // import format
    wrappedKeyBuffer, // ArrayBuffer representing key to unwrap
    unwrappingKey, // CryptoKey representing key encryption key
    "AES-KW", // algorithm identifier for key encryption key
    "AES-GCM", // algorithm identifier for key to unwrap
    true, // extractability of key to unwrap
    ["encrypt", "decrypt"], // key usages for key to unwrap
  );
}

Распаковка ключа "pkcs8" формата

В этом примере мы распаковываем приватный ключ подписи RSA-PSS. Ключ был экспортирован в формате "pkcs8" и зашифрован с использованием алгоритма AES-GCM с ключом, выведенным из пароля.

Для распаковки мы запрашиваем у пользователя пароль и используем PBKDF2 и некоторый соль для вывода ключа AES-GCM распаковки. Соль должна быть такой же, как соль, которая использовалась для вывода исходного ключа AES-GCM заворачивания.

После получения ключа распаковки мы передаём его в unwrapKey() вместе с зашифрованным ключом и другими параметрами. Обратите внимание, что при использовании AES-GCM нам нужно передать значение iv в unwrapKey(), и оно должно быть таким же, как значение iv, используемое в соответствующей операции wrapKey(). См. полный код на GitHub.

/*
Salt that is to be used in derivation of the key-wrapping key,
alongside the password the user supplies.
This must match the salt value that was originally used to derive
the key.
*/
const saltBytes = [
  180, 253, 62, 216, 47, 35, 90, 55, 218, 233, 103, 10, 172, 143, 161, 177,
];

/*
IV that is to be used in decrypting the key to unwrap.
This must the same IV that was originally used to encrypt
the key.
*/
const ivBytes = [212, 187, 26, 247, 172, 51, 37, 151, 27, 177, 249, 142];

/*
The wrapped key itself.
*/
const wrappedKeyBytes = [
  6, 155, 182, 208, 7, 141, 44, 18, 3, 151, 58, 126, 68, 100, 252, 225, 241, 11,
  25, 201, 153, 171, 102, 174, 150, 29, 62, 195, 110, 138, 106, 109, 14, 6, 108,
  148, 104, 221, 22, 93, 102, 221, 146, 25, 65, 112, 4, 140, 79, 194, 164, 163,
  156, 250, 108, 11, 14, 220, 78, 194, 161, 17, 14, 57, 121, 70, 13, 28, 220,
  210, 78, 32, 46, 217, 36, 165, 220, 170, 244, 152, 214, 150, 83, 2, 138, 128,
  11, 251, 227, 213, 72, 100, 158, 10, 162, 40, 195, 60, 248, 77, 37, 156, 34,
  10, 213, 171, 67, 147, 73, 231, 31, 63, 80, 176, 103, 206, 187, 164, 214, 250,
  49, 223, 185, 5, 48, 241, 17, 1, 253, 59, 185, 181, 209, 255, 42, 223, 175,
  90, 159, 174, 169, 205, 156, 120, 195, 1, 135, 165, 226, 46, 119, 27, 97, 183,
  23, 197, 227, 85, 138, 235, 79, 158, 167, 59, 62, 194, 34, 210, 214, 240, 215,
  101, 233, 63, 138, 53, 87, 253, 189, 27, 66, 150, 76, 242, 76, 102, 174, 179,
  163, 184, 205, 11, 161, 224, 19, 110, 34, 175, 192, 101, 117, 169, 86, 66, 56,
  241, 128, 13, 156, 165, 125, 139, 110, 138, 50, 108, 129, 251, 137, 26, 186,
  110, 117, 113, 207, 179, 59, 213, 18, 175, 14, 203, 192, 2, 97, 131, 125, 167,
  227, 182, 87, 72, 123, 54, 156, 60, 195, 88, 224, 96, 46, 126, 245, 251, 247,
  147, 110, 147, 173, 82, 106, 93, 210, 55, 71, 127, 133, 41, 37, 181, 17, 106,
  16, 158, 220, 136, 43, 75, 133, 96, 240, 151, 116, 40, 44, 254, 2, 32, 74,
  226, 193, 172, 48, 211, 71, 109, 163, 143, 30, 92, 28, 30, 183, 25, 16, 176,
  207, 77, 93, 139, 242, 114, 91, 218, 126, 123, 234, 18, 9, 245, 53, 46, 172,
  215, 62, 92, 249, 191, 17, 27, 0, 58, 151, 33, 23, 169, 93, 177, 253, 152,
  147, 198, 196, 226, 42, 202, 166, 99, 250, 127, 40, 221, 196, 121, 195, 198,
  235, 30, 159, 159, 95, 182, 107, 175, 137, 177, 49, 72, 63, 131, 162, 198,
  186, 22, 255, 230, 237, 195, 56, 147, 177, 101, 52, 227, 125, 32, 180, 242,
  47, 92, 212, 6, 148, 218, 107, 125, 137, 123, 15, 51, 107, 159, 228, 238, 212,
  60, 54, 184, 48, 110, 248, 252, 208, 46, 23, 149, 78, 169, 201, 68, 242, 193,
  251, 156, 227, 42, 90, 109, 102, 172, 61, 207, 124, 96, 98, 79, 37, 218, 16,
  212, 139, 162, 0, 183, 235, 171, 75, 18, 84, 160, 120, 173, 156, 187, 99, 24,
  58, 88, 213, 148, 24, 193, 111, 75, 169, 10, 158, 207, 148, 84, 249, 156, 248,
  19, 221, 2, 175, 1, 8, 74, 221, 212, 244, 123, 34, 223, 175, 54, 166, 101, 51,
  175, 141, 80, 87, 9, 146, 72, 223, 46, 251, 199, 192, 2, 22, 125, 16, 15, 99,
  26, 159, 165, 133, 172, 169, 26, 236, 44, 86, 182, 162, 81, 143, 249, 15, 207,
  12, 232, 15, 205, 199, 78, 133, 199, 19, 232, 183, 33, 183, 72, 117, 72, 27,
  43, 254, 13, 17, 252, 1, 143, 137, 154, 10, 4, 77, 85, 24, 85, 143, 200, 81,
  76, 171, 43, 124, 42, 191, 150, 70, 10, 90, 178, 198, 40, 233, 233, 225, 146,
  231, 209, 254, 2, 90, 216, 5, 97, 105, 204, 82, 88, 81, 99, 92, 159, 116, 192,
  223, 148, 252, 12, 24, 197, 211, 187, 212, 98, 252, 201, 154, 184, 65, 54, 47,
  13, 106, 151, 168, 208, 112, 212, 74, 204, 36, 233, 98, 104, 58, 103, 1, 194,
  13, 26, 109, 101, 60, 42, 3, 215, 20, 25, 99, 176, 63, 28, 112, 102, 121, 190,
  96, 198, 228, 196, 78, 38, 82, 37, 248, 42, 150, 115, 6, 10, 22, 101, 42, 237,
  175, 69, 232, 212, 231, 40, 193, 70, 211, 245, 106, 231, 175, 150, 88, 105,
  170, 139, 238, 196, 64, 218, 250, 47, 165, 22, 36, 196, 161, 30, 79, 175, 14,
  133, 88, 129, 182, 56, 140, 147, 168, 134, 91, 68, 172, 110, 195, 134, 156,
  68, 78, 249, 215, 68, 250, 11, 23, 70, 59, 156, 99, 75, 249, 159, 84, 16, 206,
  93, 16, 130, 34, 66, 210, 82, 252, 53, 251, 84, 59, 226, 212, 154, 15, 20,
  163, 58, 228, 109, 53, 214, 151, 237, 10, 169, 107, 180, 123, 174, 159, 182,
  8, 240, 115, 115, 220, 131, 128, 79, 80, 61, 133, 58, 24, 98, 193, 225, 56,
  36, 159, 254, 199, 49, 44, 160, 28, 81, 140, 163, 24, 143, 114, 31, 237, 235,
  250, 83, 72, 215, 44, 232, 182, 45, 39, 182, 193, 248, 65, 174, 186, 52, 219,
  30, 198, 48, 1, 134, 151, 81, 114, 38, 124, 7, 213, 205, 138, 28, 22, 216, 76,
  46, 224, 241, 88, 156, 7, 62, 23, 104, 34, 54, 25, 156, 93, 212, 133, 182, 61,
  93, 255, 195, 68, 244, 234, 53, 132, 151, 140, 72, 146, 127, 113, 227, 34,
  243, 218, 222, 47, 218, 113, 18, 173, 203, 158, 133, 90, 156, 214, 77, 20,
  113, 1, 231, 164, 52, 55, 69, 132, 24, 68, 131, 212, 7, 153, 34, 179, 113,
  156, 81, 127, 83, 57, 29, 195, 90, 64, 211, 115, 202, 188, 5, 42, 188, 142,
  203, 109, 231, 53, 206, 72, 220, 90, 23, 12, 1, 178, 122, 60, 221, 68, 6, 14,
  154, 108, 203, 171, 142, 159, 249, 13, 55, 52, 110, 214, 33, 147, 164, 181,
  50, 79, 164, 200, 83, 251, 40, 105, 223, 50, 0, 115, 240, 146, 23, 122, 80,
  204, 169, 38, 198, 154, 31, 29, 23, 236, 39, 35, 131, 147, 242, 163, 138, 158,
  236, 117, 7, 108, 33, 132, 98, 50, 111, 46, 146, 251, 82, 34, 85, 5, 130, 237,
  67, 40, 170, 235, 124, 92, 66, 71, 239, 12, 97, 136, 251, 1, 206, 13, 51, 232,
  92, 46, 35, 95, 5, 123, 24, 183, 99, 243, 124, 75, 155, 89, 66, 54, 72, 17,
  255, 99, 137, 199, 232, 204, 9, 248, 78, 35, 218, 136, 117, 239, 102, 240,
  187, 40, 89, 244, 140, 109, 229, 120, 116, 54, 207, 171, 11, 248, 190, 199,
  81, 53, 109, 8, 188, 51, 93, 165, 34, 255, 165, 191, 198, 130, 220, 41, 192,
  166, 194, 69, 104, 124, 158, 122, 236, 176, 24, 60, 87, 240, 42, 158, 143, 37,
  143, 208, 155, 249, 230, 21, 4, 230, 56, 194, 62, 235, 132, 14, 50, 180, 216,
  134, 28, 25, 159, 64, 199, 161, 236, 60, 233, 160, 172, 68, 169, 2, 5, 252,
  190, 20, 54, 115, 248, 63, 93, 107, 156, 8, 96, 85, 32, 189, 118, 66, 114,
  126, 64, 203, 97, 235, 13, 18, 102, 192, 51, 59, 5, 122, 171, 96, 129, 40, 32,
  154, 4, 191, 234, 75, 184, 112, 201, 244, 110, 50, 216, 44, 88, 139, 175, 58,
  112, 7, 52, 25, 64, 112, 40, 148, 187, 39, 234, 96, 151, 16, 158, 114, 113,
  109, 164, 47, 108, 94, 148, 35, 232, 221, 33, 110, 126, 170, 25, 234, 45, 165,
  180, 210, 193, 120, 247, 155, 127,
];

/*
The unwrapped signing key.
*/
let signingKey;

const signButton = document.querySelector(".pkcs8 .sign-button");

/*
Convert an array of byte values to an ArrayBuffer.
*/
function bytesToArrayBuffer(bytes) {
  const bytesAsArrayBuffer = new ArrayBuffer(bytes.length);
  const bytesUint8 = new Uint8Array(bytesAsArrayBuffer);
  bytesUint8.set(bytes);
  return bytesAsArrayBuffer;
}

/*
Get some key material to use as input to the deriveKey method.
The key material is a password supplied by the user.
*/
function getKeyMaterial() {
  let password = window.prompt("Enter your password");
  let enc = new TextEncoder();
  return window.crypto.subtle.importKey(
    "raw",
    enc.encode(password),
    { name: "PBKDF2" },
    false,
    ["deriveBits", "deriveKey"],
  );
}

/*
Derive an AES-GCM key using PBKDF2.
*/
async function getUnwrappingKey() {
  // 1. get the key material (user-supplied password)
  const keyMaterial = await getKeyMaterial();
  // 2 initialize the salt parameter.
  // The salt must match the salt originally used to derive the key.
  // In this example it's supplied as a constant "saltBytes".
  const saltBuffer = bytesToArrayBuffer(saltBytes);
  // 3 derive the key from key material and salt
  return window.crypto.subtle.deriveKey(
    {
      name: "PBKDF2",
      salt: saltBuffer,
      iterations: 100000,
      hash: "SHA-256",
    },
    keyMaterial,
    { name: "AES-GCM", length: 256 },
    true,
    ["wrapKey", "unwrapKey"],
  );
}

/*
Unwrap an RSA-PSS private signing key from an ArrayBuffer containing
the raw bytes.
Takes an array containing the bytes, and returns a Promise
that will resolve to a CryptoKey representing the private key.
*/
async function unwrapPrivateKey(wrappedKey) {
  // 1. get the unwrapping key
  const unwrappingKey = await getUnwrappingKey();
  // 2. initialize the wrapped key
  const wrappedKeyBuffer = bytesToArrayBuffer(wrappedKey);
  // 3. initialize the iv
  const ivBuffer = bytesToArrayBuffer(ivBytes);
  // 4. unwrap the key
  return window.crypto.subtle.unwrapKey(
    "pkcs8", // import format
    wrappedKeyBuffer, // ArrayBuffer representing key to unwrap
    unwrappingKey, // CryptoKey representing key encryption key
    {
      // algorithm params for key encryption key
      name: "AES-GCM",
      iv: ivBuffer,
    },
    {
      // algorithm params for key to unwrap
      name: "RSA-PSS",
      hash: "SHA-256",
    },
    true, // extractability of key to unwrap
    ["sign"], // key usages for key to unwrap
  );
}

Спецификации

Спецификация
Web Cryptography API
# SubtleCrypto-method-unwrapKey

Совместимость с браузерами

Рабочий стол Мобильный
Chrome Edge Firefox Opera Safari Chrome Android Firefox для Android Opera Android Safari на IOS Samsung Internet WebView Android
unwrapKey 37 79
12–79Не поддерживается: AES-CTR.
34 24 7 37 34 24 7 3.0 37

См. также

  • SubtleCrypto.importKey()
  • Формат PKCS #8.
  • Формат SubjectPublicKeyInfo.
  • Формат JSON Web Key.
  • Спецификация AES-KW.

© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/unwrapKey

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API