SubtleCrypto: Methode unwrapKey()
Baseline
Weitgehend verfügbar
Diese Funktion ist gut etabliert und funktioniert auf vielen Geräten und in vielen Browserversionen. Sie ist seit Januar 2020 browserübergreifend verfügbar.
Sicherer Kontext: Diese Funktion ist nur in sicheren Kontexten (HTTPS) in einigen oder allen unterstützenden Browsern verfügbar.
Hinweis: Diese Funktion ist in Web Workers verfügbar.
Die Methode unwrapKey() der Schnittstelle SubtleCrypto „entpackt“ einen Schlüssel. Dazu nimmt sie einen Schlüssel entgegen, der exportiert und anschließend verschlüsselt wurde (auch „wrapped“ genannt). Sie entschlüsselt und importiert den Schlüssel und gibt ein CryptoKey-Objekt zurück, das in der Web Crypto API verwendet werden kann.
Wie bei SubtleCrypto.importKey() geben Sie das Importformat und weitere Eigenschaften des zu importierenden Schlüssels an, etwa ob er exportierbar ist und für welche Operationen er verwendet werden darf.
Da unwrapKey() den zu importierenden Schlüssel auch entschlüsselt, müssen Sie außerdem den Schlüssel übergeben, mit dem er entschlüsselt werden soll. Dieser wird manchmal als „Unwrapping-Schlüssel“ bezeichnet.
Das Gegenstück zu unwrapKey() ist SubtleCrypto.wrapKey(): unwrapKey kombiniert Entschlüsseln und Importieren, wrapKey dagegen Verschlüsseln und Exportieren.
Syntax
unwrapKey(format, wrappedKey, unwrappingKey, unwrapAlgo, unwrappedKeyAlgo, extractable, keyUsages)
Parameter
format-
Ein String, der das Datenformat des zu entpackenden Schlüssels beschreibt. Folgende Werte sind möglich:
raw: Raw-Format.pkcs8: PKCS-#8-Format.spki: SubjectPublicKeyInfo-Format.jwk: JSON-Web-Key-Format.
wrappedKey-
Ein
ArrayBuffer, der den verpackten Schlüssel im angegebenen Format enthält. unwrappingKey-
Der
CryptoKey, mit dem der verpackte Schlüssel entschlüsselt wird. Für diesen Schlüssel muss die VerwendungunwrapKeyfestgelegt sein. unwrapAlgo-
Ein Objekt, das den Algorithmus zum Entschlüsseln des verpackten Schlüssels sowie gegebenenfalls erforderliche zusätzliche Parameter angibt:
- Für RSA-OAEP übergeben Sie ein
RsaOaepParams-Objekt. - Für AES-CTR übergeben Sie ein
AesCtrParams-Objekt. - Für AES-CBC übergeben Sie ein
AesCbcParams-Objekt. - Für AES-GCM übergeben Sie ein
AesGcmParams-Objekt. - Für AES-KW übergeben Sie den String
"AES-KW"oder ein Objekt der Form{ "name": "AES-KW }.
- Für RSA-OAEP übergeben Sie ein
unwrappedKeyAlgo-
Ein Objekt, das den Typ des zu entpackenden Schlüssels definiert und gegebenenfalls zusätzliche algorithmusspezifische Parameter bereitstellt.
- Für RSASSA-PKCS1-v1_5, RSA-PSS oder RSA-OAEP: Übergeben Sie ein
RsaHashedImportParams-Objekt. - Für ECDSA oder ECDH: Übergeben Sie ein
EcKeyImportParams-Objekt. - Für HMAC: Übergeben Sie ein
HmacImportParams-Objekt. - Für AES-CTR, AES-CBC, AES-GCM oder AES-KW: Übergeben Sie den String, der den Algorithmus bezeichnet, oder ein Objekt der Form
{ "name": ALGORITHM }, wobeiALGORITHMder Name des Algorithmus ist. - Für Ed25519: Übergeben Sie ein Objekt der Form
{ "name": "Ed25519" }. - Für X25519: Übergeben Sie ein Objekt der Form
{name: 'X25519'}.
- Für RSASSA-PKCS1-v1_5, RSA-PSS oder RSA-OAEP: Übergeben Sie ein
extractable-
Ein boolescher Wert, der angibt, ob der Schlüssel mit
SubtleCrypto.exportKey()oderSubtleCrypto.wrapKey()exportiert werden kann. keyUsages-
Ein
Array, das angibt, wofür der Schlüssel verwendet werden darf. Folgende Werte sind möglich:encrypt: Der Schlüssel darf zum Verschlüsseln von Nachrichten verwendet werden.decrypt: Der Schlüssel darf zum Entschlüsseln von Nachrichten verwendet werden.sign: Der Schlüssel darf zum Signieren von Nachrichten verwendet werden.verify: Der Schlüssel darf zum Überprüfen von Signaturen verwendet werden.deriveKey: Der Schlüssel darf zum Ableiten eines neuen Schlüssels verwendet werden.deriveBits: Der Schlüssel darf zum Ableiten von Bits verwendet werden.wrapKey: Der Schlüssel darf zum Verpacken eines Schlüssels verwendet werden.unwrapKey: Der Schlüssel darf zum Entpacken eines Schlüssels verwendet werden.
Rückgabewert
Eine Promise, die mit dem entpackten Schlüssel als CryptoKey-Objekt erfüllt wird.
Ausnahmen
Die Promise wird zurückgewiesen, wenn eine der folgenden Ausnahmen auftritt:
InvalidAccessErrorDOMException-
Wird ausgelöst, wenn der Unwrapping-Schlüssel nicht für den angeforderten Unwrapping-Algorithmus geeignet ist oder wenn der Wert
keyUsagesdieses Schlüsselsunwrapnicht enthält. NotSupportedErrorDOMException-
Wird ausgelöst, wenn versucht wird, einen unbekannten Algorithmus oder einen Algorithmus zu verwenden, der sich nicht zum Verschlüsseln oder Verpacken eignet.
SyntaxErrorDOMException-
Wird ausgelöst, wenn
keyUsagesleer ist, der entpackte Schlüssel aber den Typsecretoderprivatehat. TypeError-
Wird ausgelöst, wenn versucht wird, ein ungültiges Format zu verwenden.
Unterstützte Algorithmen
Die Methode unwrapKey() unterstützt dieselben Algorithmen wie die Methode wrapKey().
Beispiele
Hinweis: Sie können die funktionsfähigen Beispiele auf GitHub ausprobieren.
Entpacken eines Schlüssels im „raw“-Format
In diesem Beispiel entpacken wir einen symmetrischen AES-GCM-Schlüssel. Der Schlüssel wurde im „raw“-Format exportiert und mit dem AES-KW-Algorithmus verschlüsselt. Der dafür verwendete Schlüssel wurde aus einem Passwort abgeleitet.
Zum Entpacken fragen wir den Benutzer nach dem Passwort und leiten mithilfe von PBKDF2 und einem Salt den AES-KW-Unwrapping-Schlüssel ab. Der Salt muss mit dem übereinstimmen, der zum Ableiten des ursprünglichen AES-KW-Schlüssels zum Verpacken verwendet wurde.
Anschließend übergeben wir den Unwrapping-Schlüssel zusammen mit dem verpackten Schlüssel und weiteren Parametern an unwrapKey(). Den vollständigen Code finden Sie auf 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
);
}
Entpacken eines Schlüssels im „pkcs8“-Format
In diesem Beispiel entpacken wir einen privaten RSA-PSS-Signaturschlüssel. Der Schlüssel wurde im „pkcs8“-Format exportiert und mit dem AES-GCM-Algorithmus verschlüsselt. Der dafür verwendete Schlüssel wurde aus einem Passwort abgeleitet.
Zum Entpacken fragen wir den Benutzer nach dem Passwort und leiten mithilfe von PBKDF2 und einem Salt den AES-GCM-Unwrapping-Schlüssel ab. Der Salt muss mit dem übereinstimmen, der zum Ableiten des ursprünglichen AES-GCM-Schlüssels zum Verpacken verwendet wurde.
Anschließend übergeben wir den Unwrapping-Schlüssel zusammen mit dem verpackten Schlüssel und weiteren Parametern an unwrapKey(). Beachten Sie, dass wir bei Verwendung von AES-GCM den iv-Wert an unwrapKey() übergeben müssen. Er muss mit dem iv-Wert übereinstimmen, der beim entsprechenden wrapKey()-Aufruf verwendet wurde. Den vollständigen Code finden Sie auf 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
);
}
Spezifikationen
| Spezifikation |
|---|
| Web Cryptography Level 2> # SubtleCrypto-method-unwrapKey> |