@gaonengwww/jose
Version:
JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes
315 lines (304 loc) • 9.19 kB
JavaScript
;
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/lib/encrypt.ts
var encrypt_exports = {};
__export(encrypt_exports, {
default: () => encrypt_default
});
module.exports = __toCommonJS(encrypt_exports);
// 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;
}
// src/util/errors.ts
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 JOSENotSupported = class extends JOSEError {
/** @ignore */
static code = "ERR_JOSE_NOT_SUPPORTED";
/** A unique error code for {@link JOSENotSupported}. */
code = "ERR_JOSE_NOT_SUPPORTED";
};
var JWEInvalid = class extends JOSEError {
/** @ignore */
static code = "ERR_JWE_INVALID";
/** A unique error code for {@link JWEInvalid}. */
code = "ERR_JWE_INVALID";
};
// 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 checkUsage(key, usage) {
if (usage && !key.usages.includes(usage)) {
throw new TypeError(
`CryptoKey does not support this operation, its usages must include ${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);
};
// src/lib/is_key_like.ts
function isCryptoKey(key) {
return key?.[Symbol.toStringTag] === "CryptoKey";
}
// 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 tag = new Uint8Array(
(await crypto.subtle.sign("HMAC", macKey, macData)).slice(0, keySize >> 3)
);
return { ciphertext, tag, 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 tag = encrypted.slice(-16);
const ciphertext = encrypted.slice(0, -16);
return { ciphertext, tag, 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");
}
};