123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- import { FlattenedEncrypt, unprotected } from '../flattened/encrypt.js';
- import { JWEInvalid } from '../../util/errors.js';
- import generateCek from '../../lib/cek.js';
- import isDisjoint from '../../lib/is_disjoint.js';
- import encryptKeyManagement from '../../lib/encrypt_key_management.js';
- import { encode as base64url } from '../../runtime/base64url.js';
- import validateCrit from '../../lib/validate_crit.js';
- class IndividualRecipient {
- constructor(enc, key, options) {
- this.parent = enc;
- this.key = key;
- this.options = options;
- }
- setUnprotectedHeader(unprotectedHeader) {
- if (this.unprotectedHeader) {
- throw new TypeError('setUnprotectedHeader can only be called once');
- }
- this.unprotectedHeader = unprotectedHeader;
- return this;
- }
- addRecipient(...args) {
- return this.parent.addRecipient(...args);
- }
- encrypt(...args) {
- return this.parent.encrypt(...args);
- }
- done() {
- return this.parent;
- }
- }
- export class GeneralEncrypt {
- constructor(plaintext) {
- this._recipients = [];
- this._plaintext = plaintext;
- }
- addRecipient(key, options) {
- const recipient = new IndividualRecipient(this, key, { crit: options === null || options === void 0 ? void 0 : options.crit });
- this._recipients.push(recipient);
- return recipient;
- }
- setProtectedHeader(protectedHeader) {
- if (this._protectedHeader) {
- throw new TypeError('setProtectedHeader can only be called once');
- }
- this._protectedHeader = protectedHeader;
- return this;
- }
- setSharedUnprotectedHeader(sharedUnprotectedHeader) {
- if (this._unprotectedHeader) {
- throw new TypeError('setSharedUnprotectedHeader can only be called once');
- }
- this._unprotectedHeader = sharedUnprotectedHeader;
- return this;
- }
- setAdditionalAuthenticatedData(aad) {
- this._aad = aad;
- return this;
- }
- async encrypt(options) {
- var _a, _b, _c;
- if (!this._recipients.length) {
- throw new JWEInvalid('at least one recipient must be added');
- }
- options = { deflateRaw: options === null || options === void 0 ? void 0 : options.deflateRaw };
- if (this._recipients.length === 1) {
- const [recipient] = this._recipients;
- const flattened = await new FlattenedEncrypt(this._plaintext)
- .setAdditionalAuthenticatedData(this._aad)
- .setProtectedHeader(this._protectedHeader)
- .setSharedUnprotectedHeader(this._unprotectedHeader)
- .setUnprotectedHeader(recipient.unprotectedHeader)
- .encrypt(recipient.key, { ...recipient.options, ...options });
- let jwe = {
- ciphertext: flattened.ciphertext,
- iv: flattened.iv,
- recipients: [{}],
- tag: flattened.tag,
- };
- if (flattened.aad)
- jwe.aad = flattened.aad;
- if (flattened.protected)
- jwe.protected = flattened.protected;
- if (flattened.unprotected)
- jwe.unprotected = flattened.unprotected;
- if (flattened.encrypted_key)
- jwe.recipients[0].encrypted_key = flattened.encrypted_key;
- if (flattened.header)
- jwe.recipients[0].header = flattened.header;
- return jwe;
- }
- let enc;
- for (let i = 0; i < this._recipients.length; i++) {
- const recipient = this._recipients[i];
- if (!isDisjoint(this._protectedHeader, this._unprotectedHeader, recipient.unprotectedHeader)) {
- throw new JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint');
- }
- const joseHeader = {
- ...this._protectedHeader,
- ...this._unprotectedHeader,
- ...recipient.unprotectedHeader,
- };
- const { alg } = joseHeader;
- if (typeof alg !== 'string' || !alg) {
- throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid');
- }
- if (alg === 'dir' || alg === 'ECDH-ES') {
- throw new JWEInvalid('"dir" and "ECDH-ES" alg may only be used with a single recipient');
- }
- if (typeof joseHeader.enc !== 'string' || !joseHeader.enc) {
- throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid');
- }
- if (!enc) {
- enc = joseHeader.enc;
- }
- else if (enc !== joseHeader.enc) {
- throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter must be the same for all recipients');
- }
- validateCrit(JWEInvalid, new Map(), recipient.options.crit, this._protectedHeader, joseHeader);
- if (joseHeader.zip !== undefined) {
- if (!this._protectedHeader || !this._protectedHeader.zip) {
- throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected');
- }
- }
- }
- const cek = generateCek(enc);
- let jwe = {
- ciphertext: '',
- iv: '',
- recipients: [],
- tag: '',
- };
- for (let i = 0; i < this._recipients.length; i++) {
- const recipient = this._recipients[i];
- const target = {};
- jwe.recipients.push(target);
- const joseHeader = {
- ...this._protectedHeader,
- ...this._unprotectedHeader,
- ...recipient.unprotectedHeader,
- };
- const p2c = joseHeader.alg.startsWith('PBES2') ? 2048 + i : undefined;
- if (i === 0) {
- const flattened = await new FlattenedEncrypt(this._plaintext)
- .setAdditionalAuthenticatedData(this._aad)
- .setContentEncryptionKey(cek)
- .setProtectedHeader(this._protectedHeader)
- .setSharedUnprotectedHeader(this._unprotectedHeader)
- .setUnprotectedHeader(recipient.unprotectedHeader)
- .setKeyManagementParameters({ p2c })
- .encrypt(recipient.key, {
- ...recipient.options,
- ...options,
- [unprotected]: true,
- });
- jwe.ciphertext = flattened.ciphertext;
- jwe.iv = flattened.iv;
- jwe.tag = flattened.tag;
- if (flattened.aad)
- jwe.aad = flattened.aad;
- if (flattened.protected)
- jwe.protected = flattened.protected;
- if (flattened.unprotected)
- jwe.unprotected = flattened.unprotected;
- target.encrypted_key = flattened.encrypted_key;
- if (flattened.header)
- target.header = flattened.header;
- continue;
- }
- const { encryptedKey, parameters } = await encryptKeyManagement(((_a = recipient.unprotectedHeader) === null || _a === void 0 ? void 0 : _a.alg) ||
- ((_b = this._protectedHeader) === null || _b === void 0 ? void 0 : _b.alg) ||
- ((_c = this._unprotectedHeader) === null || _c === void 0 ? void 0 : _c.alg), enc, recipient.key, cek, { p2c });
- target.encrypted_key = base64url(encryptedKey);
- if (recipient.unprotectedHeader || parameters)
- target.header = { ...recipient.unprotectedHeader, ...parameters };
- }
- return jwe;
- }
- }
|