@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
JavaScript
"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.