WebCrypto AES-KW key wrap/unwrap (RFC 3394) over
crypto.subtle.
Module webcryptoAesKw | Source packages/front/fw/src/crypto/webcrypto/aeskw.js | Deps none | Worker-safe yes
Async, CryptoKey / Uint8Array. Wraps crypto.subtle.wrapKey / unwrapKey with the AES-KW algorithm (RFC 3394 / SP 800-38F §6.2). Supports 128, 192, and 256-bit key-encryption keys (KEKs). Opt-in alternative to the pure-JS mode/kw module. Every method resolves to a result or false — never rejects.
Resolve
const webcryptoAesKw = runtime.resolve('webcryptoAesKw');
// Returns: { isAvailable, generateKek, importKek, wrapKey, unwrapKey }
API
| Method | Signature | Returns |
|---|---|---|
isAvailable |
() => boolean |
true when crypto.subtle is present |
generateKek |
(lengthBits?: 128|192|256, extractable?: boolean) => Promise<CryptoKey|false> |
New AES-KW KEK; default 256-bit, extractable |
importKek |
(raw: Uint8Array, extractable?: boolean) => Promise<CryptoKey|false> |
Import raw bytes as AES-KW KEK; default non-extractable |
wrapKey |
(kek: CryptoKey, keyToWrap: CryptoKey) => Promise<Uint8Array|false> |
Wrapped key bytes or false on error |
unwrapKey |
(kek: CryptoKey, wrapped: Uint8Array, unwrappedKeyAlg: object, usages: KeyUsage[], extractable?: boolean) => Promise<CryptoKey|false> |
Unwrapped CryptoKey or false on integrity failure |
importKek: raw.length must be 16 (128-bit), 24 (192-bit), or 32 (256-bit) bytes; other lengths resolve false.
wrapKey: the key being wrapped must be extractable; WebCrypto enforces this at the platform level.
unwrapKey: unwrappedKeyAlg is the algorithm dict of the wrapped key (e.g. { name: 'AES-GCM', length: 256 }). An integrity failure (wrong KEK, tampered bytes) causes crypto.subtle to reject — the rejection is caught and false is returned.
Examples
Generate a KEK and wrap an inner key
const webcryptoAesKw = runtime.resolve('webcryptoAesKw');
if (!webcryptoAesKw.isAvailable()) {
// Fall back to the pure-JS kw module
}
// Generate a 256-bit KEK (non-extractable by default in importKek; extractable here)
const kek = await webcryptoAesKw.generateKek(256, false);
// The inner key must be extractable for wrapKey to succeed
const innerKey = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']
);
const wrapped = await webcryptoAesKw.wrapKey(kek, innerKey);
// wrapped is a Uint8Array of length 40 (32 inner + 8 AES-KW IV)
Import a KEK from raw bytes and unwrap
const rawKek = new Uint8Array(32); // 256-bit key material
const kek = await webcryptoAesKw.importKek(rawKek, false);
const recovered = await webcryptoAesKw.unwrapKey(
kek,
wrapped,
{ name: 'AES-GCM', length: 256 },
['encrypt', 'decrypt'],
false // non-extractable
);
if (recovered === false) {
// Integrity failure, wrong KEK, or crypto.subtle unavailable
}
Availability guard
if (!webcryptoAesKw.isAvailable()) {
// Use pure-JS kw module as fallback
const kw = runtime.resolve('kw');
// kw.wrap(prf, plaintext)
}
Worker Usage
const worker = fw.createWorker(
function ({ libs, args }) {
const kek = await libs.webcryptoAesKw.importKek(args.kekBytes, false);
const recovered = await libs.webcryptoAesKw.unwrapKey(
kek, args.wrapped, { name: 'AES-GCM', length: 256 }, ['encrypt', 'decrypt']
);
self.postMessage(recovered !== false ? 'ok' : 'fail');
},
{ dependencies: ['webcryptoAesKw'], args: { kekBytes, wrapped } }
);
Notes
- RFC 3394 AES-KW: WebCrypto exposes AES-KW only — KWP (with-pad, RFC 5649) is not available via
crypto.subtle. Use the pure-JSkwmodule for KWP or for environments withoutcrypto.subtle. - Extractable inner key: the key passed to
wrapKeymust beextractable: true; WebCrypto enforces this contract and rejects non-extractable keys —wrapKeyreturnsfalsein that case. - No-throw contract: all methods are
asyncand resolve to a value orfalse.crypto.subtlerejections (integrity failure, invalid parameters) are caught and logged viaconsole.error('[crypto] FAIL: webcryptoAesKw.<method>: …'). They never propagate. - KEK sizes: AES-KW supports 128, 192, and 256-bit KEKs.
importKekvalidatesraw.length ∈ {16, 24, 32}and returnsfalsefor other sizes. - Worker-safe:
crypto.subtleis available in Web Workers; this module has no DOM dependency and no main-thread closures.
See also
- kw — pure-JS AES-KW and KWP (RFC 3394 / RFC 5649); synchronous, bitArray in/out; default choice
- aes — WebCrypto AES-GCM/CBC bulk encryption (
crypto.subtle) - webcryptoDigest — WebCrypto SHA hash module