Signatur
Beschreibung
wrapKey() umhüllt einen Schlüssel („Key Wrapping“). Das heißt: Der Schlüssel wird zuerst in ein externes Format exportiert (raw, pkcs8, spki oder jwk) und dann mit einem Wrapping-Schlüssel verschlüsselt. Das Ergebnis ist ein ArrayBuffer mit dem verschlüsselten Schlüsselmaterial. Den Klartext des Schlüssels bekommt dabei kein JavaScript-Code zu sehen.
Typische Einsatzfälle: Man will einen Sitzungs- oder Datenschlüssel verschlüsselt in IndexedDB oder auf einem Server ablegen, einen symmetrischen Schlüssel mit dem öffentlichen RSA-Schlüssel eines Empfängers übertragen (hybride Verschlüsselung) oder Schlüssel mit einem aus einem Passwort abgeleiteten Schlüssel schützen (PBKDF2 + AES-KW). Das Gegenstück ist SubtleCrypto.unwrapKey(). Es entschlüsselt die Daten und importiert sie wieder als CryptoKey.
Als Umhüllungsalgorithmus sind erlaubt: RSA-OAEP, AES-GCM, AES-CBC, AES-CTR und AES-KW. Zwei Bedingungen müssen erfüllt sein: Der zu umhüllende Schlüssel muss extractable: true sein, und der Wrapping-Schlüssel braucht in seinen keyUsages den Eintrag "wrapKey".
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $format Pflicht | "raw" | "pkcs8" | "spki" | "jwk" | Das Exportformat, in das der Schlüssel vor dem Verschlüsseln gebracht wird. raw für symmetrische Schlüssel, pkcs8 für private Schlüssel, spki für öffentliche Schlüssel, jwk für alle Arten (wird als JSON-Text verschlüsselt). |
|
| $key Pflicht | CryptoKey | Der zu umhüllende Schlüssel. Er muss mit extractable: true erzeugt oder importiert worden sein. |
|
| $wrappingKey Pflicht | CryptoKey | Der Schlüssel, mit dem verschlüsselt wird. Er braucht den Verwendungszweck "wrapKey". Bei RSA-OAEP ist das der öffentliche Schlüssel. |
|
| $wrapAlgo Pflicht | RsaOaepParams | AesGcmParams | AesCbcParams | AesCtrParams | AlgorithmIdentifier | Algorithmus samt Parametern, z. B. { name: "AES-GCM", iv }, { name: "RSA-OAEP" } oder "AES-KW". |
Rückgabewert
ArrayBuffer erfüllt wird. Der Puffer enthält den verschlüsselten (umhüllten) Schlüssel. Das Promise wird mit einer DOMException abgelehnt: InvalidAccessError, wenn der Wrapping-Schlüssel nicht zum Algorithmus passt oder "wrapKey" fehlt, NotSupportedError bei unbekanntem Algorithmus, TypeError bei ungültigem Format.Beispiele
AES-Schlüssel mit AES-KW umhüllen (raw-Format)
const subtle = globalThis.crypto.subtle;
// Datenschlüssel, der geschützt werden soll (muss extractable sein)
const dataKey = await subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
// Key-Encryption-Key (KEK) für AES-KW
const kek = await subtle.generateKey(
{ name: 'AES-KW', length: 256 },
false,
['wrapKey', 'unwrapKey']
);
const wrapped = await subtle.wrapKey('raw', dataKey, kek, 'AES-KW');
console.log('Umhüllte Länge:', wrapped.byteLength);
Sitzungsschlüssel für einen Empfänger mit RSA-OAEP umhüllen
const subtle = globalThis.crypto.subtle;
// Schlüsselpaar des Empfängers
const { publicKey, privateKey } = await subtle.generateKey(
{
name: 'RSA-OAEP',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: 'SHA-256'
},
true,
['wrapKey', 'unwrapKey']
);
const sessionKey = await subtle.generateKey(
{ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']
);
// Absender umhüllt mit dem öffentlichen Schlüssel
const wrapped = await subtle.wrapKey('raw', sessionKey, publicKey, { name: 'RSA-OAEP' });
// Empfänger packt mit dem privaten Schlüssel wieder aus
const restored = await subtle.unwrapKey(
'raw', wrapped, privateKey, { name: 'RSA-OAEP' },
{ name: 'AES-GCM' }, false, ['encrypt', 'decrypt']
);
console.log(wrapped.byteLength, restored.algorithm.name);
Privaten Schlüssel passwortgeschützt als JWK umhüllen (PBKDF2 + AES-GCM)
const subtle = globalThis.crypto.subtle;
const enc = new TextEncoder();
const deriveWrappingKey = async (password, salt) => {
const base = await subtle.importKey('raw', enc.encode(password), 'PBKDF2', false, ['deriveKey']);
return subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 600_000, hash: 'SHA-256' },
base,
{ name: 'AES-GCM', length: 256 },
false,
['wrapKey', 'unwrapKey']
);
};
const { privateKey } = await subtle.generateKey(
{ name: 'ECDSA', namedCurve: 'P-256' }, true, ['sign', 'verify']
);
const salt = crypto.getRandomValues(new Uint8Array(16));
const iv = crypto.getRandomValues(new Uint8Array(12));
const wrappingKey = await deriveWrappingKey('geheimes Passwort', salt);
const wrapped = await subtle.wrapKey('jwk', privateKey, wrappingKey, { name: 'AES-GCM', iv });
// salt, iv und wrapped gemeinsam speichern (z. B. in IndexedDB)
console.log({ salt: salt.length, iv: iv.length, bytes: wrapped.byteLength > 0 });