UNPKG

did-jwt

Version:

Library for Signing and Verifying JWTs that use DIDs as issuers and JWEs that use DIDs as recipients

94 lines • 3.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createJWE = createJWE; exports.decryptJWE = decryptJWE; const util_js_1 = require("../util.js"); function validateJWE(jwe) { if (!(jwe.protected && jwe.iv && jwe.ciphertext && jwe.tag)) { throw new Error('bad_jwe: missing properties'); } if (jwe.recipients) { jwe.recipients.map((rec) => { if (!(rec.header && rec.encrypted_key)) { throw new Error('bad_jwe: malformed recipients'); } }); } } function encodeJWE({ ciphertext, tag, iv, protectedHeader, recipient }, aad) { const jwe = { protected: protectedHeader, iv: (0, util_js_1.bytesToBase64url)(iv ?? new Uint8Array(0)), ciphertext: (0, util_js_1.bytesToBase64url)(ciphertext), tag: (0, util_js_1.bytesToBase64url)(tag ?? new Uint8Array(0)), }; if (aad) jwe.aad = (0, util_js_1.bytesToBase64url)(aad); if (recipient) jwe.recipients = [recipient]; return jwe; } async function createJWE(cleartext, encrypters, protectedHeader = {}, aad, useSingleEphemeralKey = false) { if (encrypters[0].alg === 'dir') { if (encrypters.length > 1) throw new Error('not_supported: Can only do "dir" encryption to one key.'); const encryptionResult = await encrypters[0].encrypt(cleartext, protectedHeader, aad); return encodeJWE(encryptionResult, aad); } else { const tmpEnc = encrypters[0].enc; if (!encrypters.reduce((acc, encrypter) => acc && encrypter.enc === tmpEnc, true)) { throw new Error('invalid_argument: Incompatible encrypters passed'); } let cek; let jwe; let epk; if (useSingleEphemeralKey) { epk = encrypters[0].genEpk?.(); const alg = encrypters[0].alg; protectedHeader = { ...protectedHeader, alg, epk: epk?.publicKeyJWK }; } for (const encrypter of encrypters) { if (!cek) { const encryptionResult = await encrypter.encrypt(cleartext, protectedHeader, aad, epk); cek = encryptionResult.cek; jwe = encodeJWE(encryptionResult, aad); } else { const recipient = await encrypter.encryptCek?.(cek, epk); if (recipient) { jwe?.recipients?.push(recipient); } } } return jwe; } } async function decryptJWE(jwe, decrypter) { validateJWE(jwe); const protHeader = JSON.parse((0, util_js_1.decodeBase64url)(jwe.protected)); if (protHeader.enc !== decrypter.enc) throw new Error(`not_supported: Decrypter does not supported: '${protHeader.enc}'`); const sealed = (0, util_js_1.toSealed)(jwe.ciphertext, jwe.tag); const aad = (0, util_js_1.stringToBytes)(jwe.aad ? `${jwe.protected}.${jwe.aad}` : jwe.protected); let cleartext = null; if (protHeader.alg === 'dir' && decrypter.alg === 'dir') { cleartext = await decrypter.decrypt(sealed, (0, util_js_1.base64ToBytes)(jwe.iv), aad); } else if (!jwe.recipients || jwe.recipients.length === 0) { throw new Error('bad_jwe: missing recipients'); } else { for (let i = 0; !cleartext && i < jwe.recipients.length; i++) { const recipient = jwe.recipients[i]; Object.assign(recipient.header, protHeader); if (recipient.header.alg === decrypter.alg) { cleartext = await decrypter.decrypt(sealed, (0, util_js_1.base64ToBytes)(jwe.iv), aad, recipient); } } } if (cleartext === null) throw new Error('failure: Failed to decrypt'); return cleartext; } //# sourceMappingURL=JWE.js.map