UNPKG

@gaonengwww/jose

Version:

JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes

1,597 lines (1,565 loc) 135 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { CompactEncrypt: () => CompactEncrypt, CompactSign: () => CompactSign, EmbeddedJWK: () => EmbeddedJWK, EncryptJWT: () => EncryptJWT, FlattenedEncrypt: () => FlattenedEncrypt, FlattenedSign: () => FlattenedSign, GeneralEncrypt: () => GeneralEncrypt, GeneralSign: () => GeneralSign, SignJWT: () => SignJWT, UnsecuredJWT: () => UnsecuredJWT, base64url: () => base64url_exports, calculateJwkThumbprint: () => calculateJwkThumbprint, calculateJwkThumbprintUri: () => calculateJwkThumbprintUri, compactDecrypt: () => compactDecrypt, compactVerify: () => compactVerify, createLocalJWKSet: () => createLocalJWKSet, createRemoteJWKSet: () => createRemoteJWKSet, cryptoRuntime: () => cryptoRuntime, customFetch: () => customFetch, decodeJwt: () => decodeJwt, decodeProtectedHeader: () => decodeProtectedHeader, errors: () => errors_exports, exportJWK: () => exportJWK, exportPKCS8: () => exportPKCS8, exportSPKI: () => exportSPKI, flattenedDecrypt: () => flattenedDecrypt, flattenedVerify: () => flattenedVerify, generalDecrypt: () => generalDecrypt, generalVerify: () => generalVerify, generateKeyPair: () => generateKeyPair, generateSecret: () => generateSecret, importJWK: () => importJWK, importPKCS8: () => importPKCS8, importSPKI: () => importSPKI, importX509: () => importX509, jwksCache: () => jwksCache, jwtDecrypt: () => jwtDecrypt, jwtVerify: () => jwtVerify }); module.exports = __toCommonJS(index_exports); // src/util/base64url.ts var base64url_exports = {}; __export(base64url_exports, { decode: () => decode, encode: () => encode }); // src/lib/buffer_utils.ts var encoder = new TextEncoder(); var decoder = new TextDecoder(); var MAX_INT32 = 2 ** 32; function concat(...buffers) { const size = buffers.reduce((acc, { length }) => acc + length, 0); const buf = new Uint8Array(size); let i = 0; for (const buffer of buffers) { buf.set(buffer, i); i += buffer.length; } return buf; } function writeUInt32BE(buf, value, offset) { if (value < 0 || value >= MAX_INT32) { throw new RangeError(`value must be >= 0 and <= ${MAX_INT32 - 1}. Received ${value}`); } buf.set([value >>> 24, value >>> 16, value >>> 8, value & 255], offset); } function uint64be(value) { const high = Math.floor(value / MAX_INT32); const low = value % MAX_INT32; const buf = new Uint8Array(8); writeUInt32BE(buf, high, 0); writeUInt32BE(buf, low, 4); return buf; } function uint32be(value) { const buf = new Uint8Array(4); writeUInt32BE(buf, value); return buf; } // src/lib/base64.ts function encodeBase64(input) { if (Uint8Array.prototype.toBase64) { return input.toBase64(); } const CHUNK_SIZE = 32768; const arr = []; for (let i = 0; i < input.length; i += CHUNK_SIZE) { arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE))); } return btoa(arr.join("")); } function decodeBase64(encoded) { if (Uint8Array.fromBase64) { return Uint8Array.fromBase64(encoded); } const binary = atob(encoded); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } return bytes; } // src/util/base64url.ts function decode(input) { if (Uint8Array.fromBase64) { return Uint8Array.fromBase64(typeof input === "string" ? input : decoder.decode(input), { alphabet: "base64url" }); } let encoded = input; if (encoded instanceof Uint8Array) { encoded = decoder.decode(encoded); } encoded = encoded.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, ""); try { return decodeBase64(encoded); } catch { throw new TypeError("The input to be decoded is not correctly encoded."); } } function encode(input) { let unencoded = input; if (typeof unencoded === "string") { unencoded = encoder.encode(unencoded); } if (Uint8Array.prototype.toBase64) { return unencoded.toBase64({ alphabet: "base64url", omitPadding: true }); } return encodeBase64(unencoded).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_"); } // src/util/errors.ts var errors_exports = {}; __export(errors_exports, { JOSEAlgNotAllowed: () => JOSEAlgNotAllowed, JOSEError: () => JOSEError, JOSENotSupported: () => JOSENotSupported, JWEDecryptionFailed: () => JWEDecryptionFailed, JWEInvalid: () => JWEInvalid, JWKInvalid: () => JWKInvalid, JWKSInvalid: () => JWKSInvalid, JWKSMultipleMatchingKeys: () => JWKSMultipleMatchingKeys, JWKSNoMatchingKey: () => JWKSNoMatchingKey, JWKSTimeout: () => JWKSTimeout, JWSInvalid: () => JWSInvalid, JWSSignatureVerificationFailed: () => JWSSignatureVerificationFailed, JWTClaimValidationFailed: () => JWTClaimValidationFailed, JWTExpired: () => JWTExpired, JWTInvalid: () => JWTInvalid }); var JOSEError = class extends Error { /** * A unique error code for the particular error subclass. * * @ignore */ static code = "ERR_JOSE_GENERIC"; /** A unique error code for {@link JOSEError}. */ code = "ERR_JOSE_GENERIC"; /** @ignore */ constructor(message2, options) { super(message2, options); this.name = this.constructor.name; Error.captureStackTrace?.(this, this.constructor); } }; var JWTClaimValidationFailed = class extends JOSEError { /** @ignore */ static code = "ERR_JWT_CLAIM_VALIDATION_FAILED"; /** A unique error code for {@link JWTClaimValidationFailed}. */ code = "ERR_JWT_CLAIM_VALIDATION_FAILED"; /** The Claim for which the validation failed. */ claim; /** Reason code for the validation failure. */ reason; /** * The parsed JWT Claims Set (aka payload). Other JWT claims may or may not have been verified at * this point. The JSON Web Signature (JWS) or a JSON Web Encryption (JWE) structures' integrity * has however been verified. Claims Set verification happens after the JWS Signature or JWE * Decryption processes. */ payload; /** @ignore */ constructor(message2, payload, claim = "unspecified", reason = "unspecified") { super(message2, { cause: { claim, reason, payload } }); this.claim = claim; this.reason = reason; this.payload = payload; } }; var JWTExpired = class extends JOSEError { /** @ignore */ static code = "ERR_JWT_EXPIRED"; /** A unique error code for {@link JWTExpired}. */ code = "ERR_JWT_EXPIRED"; /** The Claim for which the validation failed. */ claim; /** Reason code for the validation failure. */ reason; /** * The parsed JWT Claims Set (aka payload). Other JWT claims may or may not have been verified at * this point. The JSON Web Signature (JWS) or a JSON Web Encryption (JWE) structures' integrity * has however been verified. Claims Set verification happens after the JWS Signature or JWE * Decryption processes. */ payload; /** @ignore */ constructor(message2, payload, claim = "unspecified", reason = "unspecified") { super(message2, { cause: { claim, reason, payload } }); this.claim = claim; this.reason = reason; this.payload = payload; } }; var JOSEAlgNotAllowed = class extends JOSEError { /** @ignore */ static code = "ERR_JOSE_ALG_NOT_ALLOWED"; /** A unique error code for {@link JOSEAlgNotAllowed}. */ code = "ERR_JOSE_ALG_NOT_ALLOWED"; }; var JOSENotSupported = class extends JOSEError { /** @ignore */ static code = "ERR_JOSE_NOT_SUPPORTED"; /** A unique error code for {@link JOSENotSupported}. */ code = "ERR_JOSE_NOT_SUPPORTED"; }; var JWEDecryptionFailed = class extends JOSEError { /** @ignore */ static code = "ERR_JWE_DECRYPTION_FAILED"; /** A unique error code for {@link JWEDecryptionFailed}. */ code = "ERR_JWE_DECRYPTION_FAILED"; /** @ignore */ constructor(message2 = "decryption operation failed", options) { super(message2, options); } }; var JWEInvalid = class extends JOSEError { /** @ignore */ static code = "ERR_JWE_INVALID"; /** A unique error code for {@link JWEInvalid}. */ code = "ERR_JWE_INVALID"; }; var JWSInvalid = class extends JOSEError { /** @ignore */ static code = "ERR_JWS_INVALID"; /** A unique error code for {@link JWSInvalid}. */ code = "ERR_JWS_INVALID"; }; var JWTInvalid = class extends JOSEError { /** @ignore */ static code = "ERR_JWT_INVALID"; /** A unique error code for {@link JWTInvalid}. */ code = "ERR_JWT_INVALID"; }; var JWKInvalid = class extends JOSEError { /** @ignore */ static code = "ERR_JWK_INVALID"; /** A unique error code for {@link JWKInvalid}. */ code = "ERR_JWK_INVALID"; }; var JWKSInvalid = class extends JOSEError { /** @ignore */ static code = "ERR_JWKS_INVALID"; /** A unique error code for {@link JWKSInvalid}. */ code = "ERR_JWKS_INVALID"; }; var JWKSNoMatchingKey = class extends JOSEError { /** @ignore */ static code = "ERR_JWKS_NO_MATCHING_KEY"; /** A unique error code for {@link JWKSNoMatchingKey}. */ code = "ERR_JWKS_NO_MATCHING_KEY"; /** @ignore */ constructor(message2 = "no applicable key found in the JSON Web Key Set", options) { super(message2, options); } }; var JWKSMultipleMatchingKeys = class extends JOSEError { /** @ignore */ [Symbol.asyncIterator]; /** @ignore */ static code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS"; /** A unique error code for {@link JWKSMultipleMatchingKeys}. */ code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS"; /** @ignore */ constructor(message2 = "multiple matching keys found in the JSON Web Key Set", options) { super(message2, options); } }; var JWKSTimeout = class extends JOSEError { /** @ignore */ static code = "ERR_JWKS_TIMEOUT"; /** A unique error code for {@link JWKSTimeout}. */ code = "ERR_JWKS_TIMEOUT"; /** @ignore */ constructor(message2 = "request timed out", options) { super(message2, options); } }; var JWSSignatureVerificationFailed = class extends JOSEError { /** @ignore */ static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED"; /** A unique error code for {@link JWSSignatureVerificationFailed}. */ code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED"; /** @ignore */ constructor(message2 = "signature verification failed", options) { super(message2, options); } }; // src/lib/iv.ts function bitLength(alg) { switch (alg) { case "A128GCM": case "A128GCMKW": case "A192GCM": case "A192GCMKW": case "A256GCM": case "A256GCMKW": return 96; case "A128CBC-HS256": case "A192CBC-HS384": case "A256CBC-HS512": return 128; default: throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`); } } var iv_default = (alg) => crypto.getRandomValues(new Uint8Array(bitLength(alg) >> 3)); // src/lib/check_iv_length.ts var check_iv_length_default = (enc, iv) => { if (iv.length << 3 !== bitLength(enc)) { throw new JWEInvalid("Invalid Initialization Vector length"); } }; // src/lib/check_cek_length.ts var check_cek_length_default = (cek, expected) => { const actual = cek.byteLength << 3; if (actual !== expected) { throw new JWEInvalid( `Invalid Content Encryption Key length. Expected ${expected} bits, got ${actual} bits` ); } }; // src/lib/crypto_key.ts function unusable(name, prop = "algorithm.name") { return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`); } function isAlgorithm(algorithm, name) { return algorithm.name === name; } function getHashLength(hash) { return parseInt(hash.name.slice(4), 10); } function getNamedCurve(alg) { switch (alg) { case "ES256": return "P-256"; case "ES384": return "P-384"; case "ES512": return "P-521"; default: throw new Error("unreachable"); } } function checkUsage(key, usage) { if (usage && !key.usages.includes(usage)) { throw new TypeError( `CryptoKey does not support this operation, its usages must include ${usage}.` ); } } function checkSigCryptoKey(key, alg, usage) { switch (alg) { case "HS256": case "HS384": case "HS512": { if (!isAlgorithm(key.algorithm, "HMAC")) throw unusable("HMAC"); const expected = parseInt(alg.slice(2), 10); const actual = getHashLength(key.algorithm.hash); if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash"); break; } case "RS256": case "RS384": case "RS512": { if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5")) throw unusable("RSASSA-PKCS1-v1_5"); const expected = parseInt(alg.slice(2), 10); const actual = getHashLength(key.algorithm.hash); if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash"); break; } case "PS256": case "PS384": case "PS512": { if (!isAlgorithm(key.algorithm, "RSA-PSS")) throw unusable("RSA-PSS"); const expected = parseInt(alg.slice(2), 10); const actual = getHashLength(key.algorithm.hash); if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash"); break; } case "Ed25519": // Fall through case "EdDSA": { if (!isAlgorithm(key.algorithm, "Ed25519")) throw unusable("Ed25519"); break; } case "ES256": case "ES384": case "ES512": { if (!isAlgorithm(key.algorithm, "ECDSA")) throw unusable("ECDSA"); const expected = getNamedCurve(alg); const actual = key.algorithm.namedCurve; if (actual !== expected) throw unusable(expected, "algorithm.namedCurve"); break; } default: throw new TypeError("CryptoKey does not support this operation"); } checkUsage(key, usage); } function checkEncCryptoKey(key, alg, usage) { switch (alg) { case "A128GCM": case "A192GCM": case "A256GCM": { if (!isAlgorithm(key.algorithm, "AES-GCM")) throw unusable("AES-GCM"); const expected = parseInt(alg.slice(1, 4), 10); const actual = key.algorithm.length; if (actual !== expected) throw unusable(expected, "algorithm.length"); break; } case "A128KW": case "A192KW": case "A256KW": { if (!isAlgorithm(key.algorithm, "AES-KW")) throw unusable("AES-KW"); const expected = parseInt(alg.slice(1, 4), 10); const actual = key.algorithm.length; if (actual !== expected) throw unusable(expected, "algorithm.length"); break; } case "ECDH": { switch (key.algorithm.name) { case "ECDH": case "X25519": break; default: throw unusable("ECDH or X25519"); } break; } case "PBES2-HS256+A128KW": case "PBES2-HS384+A192KW": case "PBES2-HS512+A256KW": if (!isAlgorithm(key.algorithm, "PBKDF2")) throw unusable("PBKDF2"); break; case "RSA-OAEP": case "RSA-OAEP-256": case "RSA-OAEP-384": case "RSA-OAEP-512": { if (!isAlgorithm(key.algorithm, "RSA-OAEP")) throw unusable("RSA-OAEP"); const expected = parseInt(alg.slice(9), 10) || 1; const actual = getHashLength(key.algorithm.hash); if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash"); break; } default: throw new TypeError("CryptoKey does not support this operation"); } checkUsage(key, usage); } // src/lib/invalid_key_input.ts function message(msg, actual, ...types) { types = types.filter(Boolean); if (types.length > 2) { const last = types.pop(); msg += `one of type ${types.join(", ")}, or ${last}.`; } else if (types.length === 2) { msg += `one of type ${types[0]} or ${types[1]}.`; } else { msg += `of type ${types[0]}.`; } if (actual == null) { msg += ` Received ${actual}`; } else if (typeof actual === "function" && actual.name) { msg += ` Received function ${actual.name}`; } else if (typeof actual === "object" && actual != null) { if (actual.constructor?.name) { msg += ` Received an instance of ${actual.constructor.name}`; } } return msg; } var invalid_key_input_default = (actual, ...types) => { return message("Key must be ", actual, ...types); }; function withAlg(alg, actual, ...types) { return message(`Key for the ${alg} algorithm must be `, actual, ...types); } // src/lib/is_key_like.ts function assertCryptoKey(key) { if (!isCryptoKey(key)) { throw new Error("CryptoKey instance expected"); } } function isCryptoKey(key) { return key?.[Symbol.toStringTag] === "CryptoKey"; } function isKeyObject(key) { return key?.[Symbol.toStringTag] === "KeyObject"; } var is_key_like_default = (key) => { return isCryptoKey(key) || isKeyObject(key); }; // src/lib/decrypt.ts async function timingSafeEqual(a, b) { if (!(a instanceof Uint8Array)) { throw new TypeError("First argument must be a buffer"); } if (!(b instanceof Uint8Array)) { throw new TypeError("Second argument must be a buffer"); } const algorithm = { name: "HMAC", hash: "SHA-256" }; const key = await crypto.subtle.generateKey(algorithm, false, ["sign"]); const aHmac = new Uint8Array(await crypto.subtle.sign(algorithm, key, a)); const bHmac = new Uint8Array(await crypto.subtle.sign(algorithm, key, b)); let out = 0; let i = -1; while (++i < 32) { out |= aHmac[i] ^ bHmac[i]; } return out === 0; } async function cbcDecrypt(enc, cek, ciphertext, iv, tag2, aad) { if (!(cek instanceof Uint8Array)) { throw new TypeError(invalid_key_input_default(cek, "Uint8Array")); } const keySize = parseInt(enc.slice(1, 4), 10); const encKey = await crypto.subtle.importKey( "raw", cek.subarray(keySize >> 3), "AES-CBC", false, ["decrypt"] ); const macKey = await crypto.subtle.importKey( "raw", cek.subarray(0, keySize >> 3), { hash: `SHA-${keySize << 1}`, name: "HMAC" }, false, ["sign"] ); const macData = concat(aad, iv, ciphertext, uint64be(aad.length << 3)); const expectedTag = new Uint8Array( (await crypto.subtle.sign("HMAC", macKey, macData)).slice(0, keySize >> 3) ); let macCheckPassed; try { macCheckPassed = await timingSafeEqual(tag2, expectedTag); } catch { } if (!macCheckPassed) { throw new JWEDecryptionFailed(); } let plaintext; try { plaintext = new Uint8Array( await crypto.subtle.decrypt({ iv, name: "AES-CBC" }, encKey, ciphertext) ); } catch { } if (!plaintext) { throw new JWEDecryptionFailed(); } return plaintext; } async function gcmDecrypt(enc, cek, ciphertext, iv, tag2, aad) { let encKey; if (cek instanceof Uint8Array) { encKey = await crypto.subtle.importKey("raw", cek, "AES-GCM", false, ["decrypt"]); } else { checkEncCryptoKey(cek, enc, "decrypt"); encKey = cek; } try { return new Uint8Array( await crypto.subtle.decrypt( { additionalData: aad, iv, name: "AES-GCM", tagLength: 128 }, encKey, concat(ciphertext, tag2) ) ); } catch { throw new JWEDecryptionFailed(); } } var decrypt_default = async (enc, cek, ciphertext, iv, tag2, aad) => { if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { throw new TypeError( invalid_key_input_default(cek, "CryptoKey", "KeyObject", "Uint8Array", "JSON Web Key") ); } if (!iv) { throw new JWEInvalid("JWE Initialization Vector missing"); } if (!tag2) { throw new JWEInvalid("JWE Authentication Tag missing"); } check_iv_length_default(enc, iv); switch (enc) { case "A128CBC-HS256": case "A192CBC-HS384": case "A256CBC-HS512": if (cek instanceof Uint8Array) check_cek_length_default(cek, parseInt(enc.slice(-3), 10)); return cbcDecrypt(enc, cek, ciphertext, iv, tag2, aad); case "A128GCM": case "A192GCM": case "A256GCM": if (cek instanceof Uint8Array) check_cek_length_default(cek, parseInt(enc.slice(1, 4), 10)); return gcmDecrypt(enc, cek, ciphertext, iv, tag2, aad); default: throw new JOSENotSupported("Unsupported JWE Content Encryption Algorithm"); } }; // src/lib/is_disjoint.ts var is_disjoint_default = (...headers) => { const sources = headers.filter(Boolean); if (sources.length === 0 || sources.length === 1) { return true; } let acc; for (const header of sources) { const parameters = Object.keys(header); if (!acc || acc.size === 0) { acc = new Set(parameters); continue; } for (const parameter of parameters) { if (acc.has(parameter)) { return false; } acc.add(parameter); } } return true; }; // src/lib/is_object.ts function isObjectLike(value) { return typeof value === "object" && value !== null; } var is_object_default = (input) => { if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") { return false; } if (Object.getPrototypeOf(input) === null) { return true; } let proto = input; while (Object.getPrototypeOf(proto) !== null) { proto = Object.getPrototypeOf(proto); } return Object.getPrototypeOf(input) === proto; }; // src/lib/aeskw.ts function checkKeySize(key, alg) { if (key.algorithm.length !== parseInt(alg.slice(1, 4), 10)) { throw new TypeError(`Invalid key size for alg: ${alg}`); } } function getCryptoKey(key, alg, usage) { if (key instanceof Uint8Array) { return crypto.subtle.importKey("raw", key, "AES-KW", true, [usage]); } checkEncCryptoKey(key, alg, usage); return key; } async function wrap(alg, key, cek) { const cryptoKey = await getCryptoKey(key, alg, "wrapKey"); checkKeySize(cryptoKey, alg); const cryptoKeyCek = await crypto.subtle.importKey( "raw", cek, { hash: "SHA-256", name: "HMAC" }, true, ["sign"] ); return new Uint8Array(await crypto.subtle.wrapKey("raw", cryptoKeyCek, cryptoKey, "AES-KW")); } async function unwrap(alg, key, encryptedKey) { const cryptoKey = await getCryptoKey(key, alg, "unwrapKey"); checkKeySize(cryptoKey, alg); const cryptoKeyCek = await crypto.subtle.unwrapKey( "raw", encryptedKey, cryptoKey, "AES-KW", { hash: "SHA-256", name: "HMAC" }, true, ["sign"] ); return new Uint8Array(await crypto.subtle.exportKey("raw", cryptoKeyCek)); } // src/lib/digest.ts var digest_default = async (algorithm, data) => { const subtleDigest = `SHA-${algorithm.slice(-3)}`; return new Uint8Array(await crypto.subtle.digest(subtleDigest, data)); }; // src/lib/ecdhes.ts function lengthAndInput(input) { return concat(uint32be(input.length), input); } async function concatKdf(secret, bits, value) { const iterations = Math.ceil((bits >> 3) / 32); const res = new Uint8Array(iterations * 32); for (let iter = 0; iter < iterations; iter++) { const buf = new Uint8Array(4 + secret.length + value.length); buf.set(uint32be(iter + 1)); buf.set(secret, 4); buf.set(value, 4 + secret.length); res.set(await digest_default("sha256", buf), iter * 32); } return res.slice(0, bits >> 3); } async function deriveKey(publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) { checkEncCryptoKey(publicKey, "ECDH"); checkEncCryptoKey(privateKey, "ECDH", "deriveBits"); const value = concat( lengthAndInput(encoder.encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength) ); let length; if (publicKey.algorithm.name === "X25519") { length = 256; } else { length = Math.ceil(parseInt(publicKey.algorithm.namedCurve.slice(-3), 10) / 8) << 3; } const sharedSecret = new Uint8Array( await crypto.subtle.deriveBits( { name: publicKey.algorithm.name, public: publicKey }, privateKey, length ) ); return concatKdf(sharedSecret, keyLength, value); } function allowed(key) { switch (key.algorithm.namedCurve) { case "P-256": case "P-384": case "P-521": return true; default: return key.algorithm.name === "X25519"; } } // src/lib/pbes2kw.ts function getCryptoKey2(key, alg) { if (key instanceof Uint8Array) { return crypto.subtle.importKey("raw", key, "PBKDF2", false, ["deriveBits"]); } checkEncCryptoKey(key, alg, "deriveBits"); return key; } var concatSalt = (alg, p2sInput) => concat(encoder.encode(alg), new Uint8Array([0]), p2sInput); async function deriveKey2(p2s, alg, p2c, key) { if (!(p2s instanceof Uint8Array) || p2s.length < 8) { throw new JWEInvalid("PBES2 Salt Input must be 8 or more octets"); } const salt = concatSalt(alg, p2s); const keylen = parseInt(alg.slice(13, 16), 10); const subtleAlg = { hash: `SHA-${alg.slice(8, 11)}`, iterations: p2c, name: "PBKDF2", salt }; const cryptoKey = await getCryptoKey2(key, alg); return new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen)); } async function wrap2(alg, key, cek, p2c = 2048, p2s = crypto.getRandomValues(new Uint8Array(16))) { const derived = await deriveKey2(p2s, alg, p2c, key); const encryptedKey = await wrap(alg.slice(-6), derived, cek); return { encryptedKey, p2c, p2s: encode(p2s) }; } async function unwrap2(alg, key, encryptedKey, p2c, p2s) { const derived = await deriveKey2(p2s, alg, p2c, key); return unwrap(alg.slice(-6), derived, encryptedKey); } // src/lib/check_key_length.ts var check_key_length_default = (alg, key) => { if (alg.startsWith("RS") || alg.startsWith("PS")) { const { modulusLength } = key.algorithm; if (typeof modulusLength !== "number" || modulusLength < 2048) { throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`); } } }; // src/lib/rsaes.ts var subtleAlgorithm = (alg) => { switch (alg) { case "RSA-OAEP": case "RSA-OAEP-256": case "RSA-OAEP-384": case "RSA-OAEP-512": return "RSA-OAEP"; default: throw new JOSENotSupported( `alg ${alg} is not supported either by JOSE or your javascript runtime` ); } }; async function encrypt(alg, key, cek) { checkEncCryptoKey(key, alg, "encrypt"); check_key_length_default(alg, key); return new Uint8Array(await crypto.subtle.encrypt(subtleAlgorithm(alg), key, cek)); } async function decrypt(alg, key, encryptedKey) { checkEncCryptoKey(key, alg, "decrypt"); check_key_length_default(alg, key); return new Uint8Array(await crypto.subtle.decrypt(subtleAlgorithm(alg), key, encryptedKey)); } // src/lib/cek.ts function bitLength2(alg) { switch (alg) { case "A128GCM": return 128; case "A192GCM": return 192; case "A256GCM": case "A128CBC-HS256": return 256; case "A192CBC-HS384": return 384; case "A256CBC-HS512": return 512; default: throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`); } } var cek_default = (alg) => crypto.getRandomValues(new Uint8Array(bitLength2(alg) >> 3)); // src/lib/asn1.ts var formatPEM = (b64, descriptor) => { const newlined = (b64.match(/.{1,64}/g) || []).join("\n"); return `-----BEGIN ${descriptor}----- ${newlined} -----END ${descriptor}-----`; }; var genericExport = async (keyType, keyFormat, key) => { if (isKeyObject(key)) { if (key.type !== keyType) { throw new TypeError(`key is not a ${keyType} key`); } return key.export({ format: "pem", type: keyFormat }); } if (!isCryptoKey(key)) { throw new TypeError(invalid_key_input_default(key, "CryptoKey", "KeyObject")); } if (!key.extractable) { throw new TypeError("CryptoKey is not extractable"); } if (key.type !== keyType) { throw new TypeError(`key is not a ${keyType} key`); } return formatPEM( encodeBase64(new Uint8Array(await crypto.subtle.exportKey(keyFormat, key))), `${keyType.toUpperCase()} KEY` ); }; var toSPKI = (key) => { return genericExport("public", "spki", key); }; var toPKCS8 = (key) => { return genericExport("private", "pkcs8", key); }; var findOid = (keyData, oid, from = 0) => { if (from === 0) { oid.unshift(oid.length); oid.unshift(6); } const i = keyData.indexOf(oid[0], from); if (i === -1) return false; const sub = keyData.subarray(i, i + oid.length); if (sub.length !== oid.length) return false; return sub.every((value, index) => value === oid[index]) || findOid(keyData, oid, i + 1); }; var getNamedCurve2 = (keyData) => { switch (true) { case findOid(keyData, [42, 134, 72, 206, 61, 3, 1, 7]): return "P-256"; case findOid(keyData, [43, 129, 4, 0, 34]): return "P-384"; case findOid(keyData, [43, 129, 4, 0, 35]): return "P-521"; default: return void 0; } }; var genericImport = async (replace, keyFormat, pem, alg, options) => { let algorithm; let keyUsages; const keyData = new Uint8Array( atob(pem.replace(replace, "")).split("").map((c) => c.charCodeAt(0)) ); const isPublic = keyFormat === "spki"; switch (alg) { case "PS256": case "PS384": case "PS512": algorithm = { name: "RSA-PSS", hash: `SHA-${alg.slice(-3)}` }; keyUsages = isPublic ? ["verify"] : ["sign"]; break; case "RS256": case "RS384": case "RS512": algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${alg.slice(-3)}` }; keyUsages = isPublic ? ["verify"] : ["sign"]; break; case "RSA-OAEP": case "RSA-OAEP-256": case "RSA-OAEP-384": case "RSA-OAEP-512": algorithm = { name: "RSA-OAEP", hash: `SHA-${parseInt(alg.slice(-3), 10) || 1}` }; keyUsages = isPublic ? ["encrypt", "wrapKey"] : ["decrypt", "unwrapKey"]; break; case "ES256": algorithm = { name: "ECDSA", namedCurve: "P-256" }; keyUsages = isPublic ? ["verify"] : ["sign"]; break; case "ES384": algorithm = { name: "ECDSA", namedCurve: "P-384" }; keyUsages = isPublic ? ["verify"] : ["sign"]; break; case "ES512": algorithm = { name: "ECDSA", namedCurve: "P-521" }; keyUsages = isPublic ? ["verify"] : ["sign"]; break; case "ECDH-ES": case "ECDH-ES+A128KW": case "ECDH-ES+A192KW": case "ECDH-ES+A256KW": { const namedCurve = getNamedCurve2(keyData); algorithm = namedCurve?.startsWith("P-") ? { name: "ECDH", namedCurve } : { name: "X25519" }; keyUsages = isPublic ? [] : ["deriveBits"]; break; } case "Ed25519": // Fall through case "EdDSA": algorithm = { name: "Ed25519" }; keyUsages = isPublic ? ["verify"] : ["sign"]; break; default: throw new JOSENotSupported('Invalid or unsupported "alg" (Algorithm) value'); } return crypto.subtle.importKey( keyFormat, keyData, algorithm, options?.extractable ?? (isPublic ? true : false), keyUsages ); }; var fromPKCS8 = (pem, alg, options) => { return genericImport(/(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g, "pkcs8", pem, alg, options); }; var fromSPKI = (pem, alg, options) => { return genericImport(/(?:-----(?:BEGIN|END) PUBLIC KEY-----|\s)/g, "spki", pem, alg, options); }; function getElement(seq) { const result = []; let next = 0; while (next < seq.length) { const nextPart = parseElement(seq.subarray(next)); result.push(nextPart); next += nextPart.byteLength; } return result; } function parseElement(bytes) { let position = 0; let tag2 = bytes[0] & 31; position++; if (tag2 === 31) { tag2 = 0; while (bytes[position] >= 128) { tag2 = tag2 * 128 + bytes[position] - 128; position++; } tag2 = tag2 * 128 + bytes[position] - 128; position++; } let length = 0; if (bytes[position] < 128) { length = bytes[position]; position++; } else if (length === 128) { length = 0; while (bytes[position + length] !== 0 || bytes[position + length + 1] !== 0) { if (length > bytes.byteLength) { throw new TypeError("invalid indefinite form length"); } length++; } const byteLength2 = position + length + 2; return { byteLength: byteLength2, contents: bytes.subarray(position, position + length), raw: bytes.subarray(0, byteLength2) }; } else { const numberOfDigits = bytes[position] & 127; position++; length = 0; for (let i = 0; i < numberOfDigits; i++) { length = length * 256 + bytes[position]; position++; } } const byteLength = position + length; return { byteLength, contents: bytes.subarray(position, byteLength), raw: bytes.subarray(0, byteLength) }; } function spkiFromX509(buf) { const tbsCertificate = getElement(getElement(parseElement(buf).contents)[0].contents); return encodeBase64(tbsCertificate[tbsCertificate[0].raw[0] === 160 ? 6 : 5].raw); } var createPublicKey; function getSPKI(x509) { try { createPublicKey ??= globalThis.process?.getBuiltinModule?.("node:crypto")?.createPublicKey; } catch { createPublicKey = 0; } if (createPublicKey) { try { return new createPublicKey(x509).export({ format: "pem", type: "spki" }); } catch { } } const pem = x509.replace(/(?:-----(?:BEGIN|END) CERTIFICATE-----|\s)/g, ""); const raw = decodeBase64(pem); return formatPEM(spkiFromX509(raw), "PUBLIC KEY"); } var fromX509 = (pem, alg, options) => { let spki; try { spki = getSPKI(pem); } catch (cause) { throw new TypeError("Failed to parse the X.509 certificate", { cause }); } return fromSPKI(spki, alg, options); }; // src/lib/jwk_to_key.ts function subtleMapping(jwk) { let algorithm; let keyUsages; switch (jwk.kty) { case "RSA": { switch (jwk.alg) { case "PS256": case "PS384": case "PS512": algorithm = { name: "RSA-PSS", hash: `SHA-${jwk.alg.slice(-3)}` }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "RS256": case "RS384": case "RS512": algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${jwk.alg.slice(-3)}` }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "RSA-OAEP": case "RSA-OAEP-256": case "RSA-OAEP-384": case "RSA-OAEP-512": algorithm = { name: "RSA-OAEP", hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}` }; keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"]; break; default: throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value'); } break; } case "EC": { switch (jwk.alg) { case "ES256": algorithm = { name: "ECDSA", namedCurve: "P-256" }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "ES384": algorithm = { name: "ECDSA", namedCurve: "P-384" }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "ES512": algorithm = { name: "ECDSA", namedCurve: "P-521" }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "ECDH-ES": case "ECDH-ES+A128KW": case "ECDH-ES+A192KW": case "ECDH-ES+A256KW": algorithm = { name: "ECDH", namedCurve: jwk.crv }; keyUsages = jwk.d ? ["deriveBits"] : []; break; default: throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value'); } break; } case "OKP": { switch (jwk.alg) { case "Ed25519": // Fall through case "EdDSA": algorithm = { name: "Ed25519" }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "ECDH-ES": case "ECDH-ES+A128KW": case "ECDH-ES+A192KW": case "ECDH-ES+A256KW": algorithm = { name: jwk.crv }; keyUsages = jwk.d ? ["deriveBits"] : []; break; default: throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value'); } break; } default: throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value'); } return { algorithm, keyUsages }; } var jwk_to_key_default = async (jwk) => { if (!jwk.alg) { throw new TypeError('"alg" argument is required when "jwk.alg" is not present'); } const { algorithm, keyUsages } = subtleMapping(jwk); const keyData = { ...jwk }; delete keyData.alg; delete keyData.use; return crypto.subtle.importKey( "jwk", keyData, algorithm, jwk.ext ?? (jwk.d ? false : true), jwk.key_ops ?? keyUsages ); }; // src/key/import.ts async function importSPKI(spki, alg, options) { if (typeof spki !== "string" || spki.indexOf("-----BEGIN PUBLIC KEY-----") !== 0) { throw new TypeError('"spki" must be SPKI formatted string'); } return fromSPKI(spki, alg, options); } async function importX509(x509, alg, options) { if (typeof x509 !== "string" || x509.indexOf("-----BEGIN CERTIFICATE-----") !== 0) { throw new TypeError('"x509" must be X.509 formatted string'); } return fromX509(x509, alg, options); } async function importPKCS8(pkcs8, alg, options) { if (typeof pkcs8 !== "string" || pkcs8.indexOf("-----BEGIN PRIVATE KEY-----") !== 0) { throw new TypeError('"pkcs8" must be PKCS#8 formatted string'); } return fromPKCS8(pkcs8, alg, options); } async function importJWK(jwk, alg, options) { if (!is_object_default(jwk)) { throw new TypeError("JWK must be an object"); } let ext; alg ??= jwk.alg; ext ??= options?.extractable ?? jwk.ext; switch (jwk.kty) { case "oct": if (typeof jwk.k !== "string" || !jwk.k) { throw new TypeError('missing "k" (Key Value) Parameter value'); } return decode(jwk.k); case "RSA": if ("oth" in jwk && jwk.oth !== void 0) { throw new JOSENotSupported( 'RSA JWK "oth" (Other Primes Info) Parameter value is not supported' ); } case "EC": case "OKP": return jwk_to_key_default({ ...jwk, alg, ext }); default: throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value'); } } // src/lib/encrypt.ts async function cbcEncrypt(enc, plaintext, cek, iv, aad) { if (!(cek instanceof Uint8Array)) { throw new TypeError(invalid_key_input_default(cek, "Uint8Array")); } const keySize = parseInt(enc.slice(1, 4), 10); const encKey = await crypto.subtle.importKey( "raw", cek.subarray(keySize >> 3), "AES-CBC", false, ["encrypt"] ); const macKey = await crypto.subtle.importKey( "raw", cek.subarray(0, keySize >> 3), { hash: `SHA-${keySize << 1}`, name: "HMAC" }, false, ["sign"] ); const ciphertext = new Uint8Array( await crypto.subtle.encrypt( { iv, name: "AES-CBC" }, encKey, plaintext ) ); const macData = concat(aad, iv, ciphertext, uint64be(aad.length << 3)); const tag2 = new Uint8Array( (await crypto.subtle.sign("HMAC", macKey, macData)).slice(0, keySize >> 3) ); return { ciphertext, tag: tag2, iv }; } async function gcmEncrypt(enc, plaintext, cek, iv, aad) { let encKey; if (cek instanceof Uint8Array) { encKey = await crypto.subtle.importKey("raw", cek, "AES-GCM", false, ["encrypt"]); } else { checkEncCryptoKey(cek, enc, "encrypt"); encKey = cek; } const encrypted = new Uint8Array( await crypto.subtle.encrypt( { additionalData: aad, iv, name: "AES-GCM", tagLength: 128 }, encKey, plaintext ) ); const tag2 = encrypted.slice(-16); const ciphertext = encrypted.slice(0, -16); return { ciphertext, tag: tag2, iv }; } var encrypt_default = async (enc, plaintext, cek, iv, aad) => { if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { throw new TypeError( invalid_key_input_default(cek, "CryptoKey", "KeyObject", "Uint8Array", "JSON Web Key") ); } if (iv) { check_iv_length_default(enc, iv); } else { iv = iv_default(enc); } switch (enc) { case "A128CBC-HS256": case "A192CBC-HS384": case "A256CBC-HS512": if (cek instanceof Uint8Array) { check_cek_length_default(cek, parseInt(enc.slice(-3), 10)); } return cbcEncrypt(enc, plaintext, cek, iv, aad); case "A128GCM": case "A192GCM": case "A256GCM": if (cek instanceof Uint8Array) { check_cek_length_default(cek, parseInt(enc.slice(1, 4), 10)); } return gcmEncrypt(enc, plaintext, cek, iv, aad); default: throw new JOSENotSupported("Unsupported JWE Content Encryption Algorithm"); } }; // src/lib/aesgcmkw.ts async function wrap3(alg, key, cek, iv) { const jweAlgorithm = alg.slice(0, 7); const wrapped = await encrypt_default(jweAlgorithm, cek, key, iv, new Uint8Array(0)); return { encryptedKey: wrapped.ciphertext, iv: encode(wrapped.iv), tag: encode(wrapped.tag) }; } async function unwrap3(alg, key, encryptedKey, iv, tag2) { const jweAlgorithm = alg.slice(0, 7); return decrypt_default(jweAlgorithm, key, encryptedKey, iv, tag2, new Uint8Array(0)); } // src/lib/decrypt_key_management.ts var decrypt_key_management_default = async (alg, key, encryptedKey, joseHeader, options) => { switch (alg) { case "dir": { if (encryptedKey !== void 0) throw new JWEInvalid("Encountered unexpected JWE Encrypted Key"); return key; } case "ECDH-ES": if (encryptedKey !== void 0) throw new JWEInvalid("Encountered unexpected JWE Encrypted Key"); case "ECDH-ES+A128KW": case "ECDH-ES+A192KW": case "ECDH-ES+A256KW": { if (!is_object_default(joseHeader.epk)) throw new JWEInvalid(`JOSE Header "epk" (Ephemeral Public Key) missing or invalid`); assertCryptoKey(key); if (!allowed(key)) throw new JOSENotSupported( "ECDH with the provided key is not allowed or not supported by your javascript runtime" ); const epk = await importJWK(joseHeader.epk, alg); assertCryptoKey(epk); let partyUInfo; let partyVInfo; if (joseHeader.apu !== void 0) { if (typeof joseHeader.apu !== "string") throw new JWEInvalid(`JOSE Header "apu" (Agreement PartyUInfo) invalid`); try { partyUInfo = decode(joseHeader.apu); } catch { throw new JWEInvalid("Failed to base64url decode the apu"); } } if (joseHeader.apv !== void 0) { if (typeof joseHeader.apv !== "string") throw new JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`); try { partyVInfo = decode(joseHeader.apv); } catch { throw new JWEInvalid("Failed to base64url decode the apv"); } } const sharedSecret = await deriveKey( epk, key, alg === "ECDH-ES" ? joseHeader.enc : alg, alg === "ECDH-ES" ? bitLength2(joseHeader.enc) : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo ); if (alg === "ECDH-ES") return sharedSecret; if (encryptedKey === void 0) throw new JWEInvalid("JWE Encrypted Key missing"); return unwrap(alg.slice(-6), sharedSecret, encryptedKey); } case "RSA-OAEP": case "RSA-OAEP-256": case "RSA-OAEP-384": case "RSA-OAEP-512": { if (encryptedKey === void 0) throw new JWEInvalid("JWE Encrypted Key missing"); assertCryptoKey(key); return decrypt(alg, key, encryptedKey); } case "PBES2-HS256+A128KW": case "PBES2-HS384+A192KW": case "PBES2-HS512+A256KW": { if (encryptedKey === void 0) throw new JWEInvalid("JWE Encrypted Key missing"); if (typeof joseHeader.p2c !== "number") throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) missing or invalid`); const p2cLimit = options?.maxPBES2Count || 1e4; if (joseHeader.p2c > p2cLimit) throw new JWEInvalid(`JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds`); if (typeof joseHeader.p2s !== "string") throw new JWEInvalid(`JOSE Header "p2s" (PBES2 Salt) missing or invalid`); let p2s; try { p2s = decode(joseHeader.p2s); } catch { throw new JWEInvalid("Failed to base64url decode the p2s"); } return unwrap2(alg, key, encryptedKey, joseHeader.p2c, p2s); } case "A128KW": case "A192KW": case "A256KW": { if (encryptedKey === void 0) throw new JWEInvalid("JWE Encrypted Key missing"); return unwrap(alg, key, encryptedKey); } case "A128GCMKW": case "A192GCMKW": case "A256GCMKW": { if (encryptedKey === void 0) throw new JWEInvalid("JWE Encrypted Key missing"); if (typeof joseHeader.iv !== "string") throw new JWEInvalid(`JOSE Header "iv" (Initialization Vector) missing or invalid`); if (typeof joseHeader.tag !== "string") throw new JWEInvalid(`JOSE Header "tag" (Authentication Tag) missing or invalid`); let iv; try { iv = decode(joseHeader.iv); } catch { throw new JWEInvalid("Failed to base64url decode the iv"); } let tag2; try { tag2 = decode(joseHeader.tag); } catch { throw new JWEInvalid("Failed to base64url decode the tag"); } return unwrap3(alg, key, encryptedKey, iv, tag2); } default: { throw new JOSENotSupported('Invalid or unsupported "alg" (JWE Algorithm) header value'); } } }; // src/lib/validate_crit.ts var validate_crit_default = (Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) => { if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) { throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); } if (!protectedHeader || protectedHeader.crit === void 0) { return /* @__PURE__ */ new Set(); } if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) { throw new Err( '"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present' ); } let recognized; if (recognizedOption !== void 0) { recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]); } else { recognized = recognizedDefault; } for (const parameter of protectedHeader.crit) { if (!recognized.has(parameter)) { throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); } if (joseHeader[parameter] === void 0) { throw new Err(`Extension Header Parameter "${parameter}" is missing`); } if (recognized.get(parameter) && protectedHeader[parameter] === void 0) { throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); } } return new Set(protectedHeader.crit); }; // src/lib/validate_algorithms.ts var validate_algorithms_default = (option, algorithms) => { if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== "string"))) { throw new TypeError(`"${option}" option must be an array of strings`); } if (!algorithms) { return void 0; } return new Set(algorithms); }; // src/lib/is_jwk.ts function isJWK(key) { return is_object_default(key) && typeof key.kty === "string"; } function isPrivateJWK(key) { return key.kty !== "oct" && typeof key.d === "string"; } function isPublicJWK(key) { return key.kty !== "oct" && typeof key.d === "undefined"; } function isSecretJWK(key) { return key.kty === "oct" && typeof key.k === "string"; } // src/lib/normalize_key.ts var cache; var handleJWK = async (key, jwk, alg, freeze = false) => { cache ||= /* @__PURE__ */ new WeakMap(); let cached = cache.get(key); if (cached?.[alg]) { return cached[alg]; } const cryptoKey = await jwk_to_key_default({ ...jwk, alg }); if (freeze) Object.freeze(key); if (!cached) { cache.set(key, { [alg]: cryptoKey }); } else { cached[alg] = cryptoKey; } return cryptoKey; }; var handleKeyObject = (keyObject, alg) => { cache ||= /* @__PURE__ */ new WeakMap(); let cached = cache.get(keyObject); if (cached?.[alg]) { return cached[alg]; } const isPublic = keyObject.type === "public"; const extractable = isPublic ? true : false; let cryptoKey; if (keyObject.asymmetricKeyType === "x25519") { switch (alg) { case "ECDH-ES": case "ECDH-ES+A128KW": case "ECDH-ES+A192KW": case "ECDH-ES+A256KW": break; default: throw new TypeError("given KeyObject instance cannot be used for this algorithm"); } cryptoKey = keyObject.toCryptoKey( keyObject.asymmetricKeyType, extractable, isPublic ? [] : ["deriveBits"] ); } if (keyObject.asymmetricKeyType === "ed25519") { if (alg !== "EdDSA" && alg !== "Ed25519") { throw new TypeError("given KeyObject instance cannot be used for this algorithm"); } cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [ isPublic ? "verify" : "sign" ]); } if (keyObject.