encrypt.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.GeneralEncrypt = void 0;
  4. const encrypt_js_1 = require("../flattened/encrypt.js");
  5. const errors_js_1 = require("../../util/errors.js");
  6. const cek_js_1 = require("../../lib/cek.js");
  7. const is_disjoint_js_1 = require("../../lib/is_disjoint.js");
  8. const encrypt_key_management_js_1 = require("../../lib/encrypt_key_management.js");
  9. const base64url_js_1 = require("../../runtime/base64url.js");
  10. const validate_crit_js_1 = require("../../lib/validate_crit.js");
  11. class IndividualRecipient {
  12. constructor(enc, key, options) {
  13. this.parent = enc;
  14. this.key = key;
  15. this.options = options;
  16. }
  17. setUnprotectedHeader(unprotectedHeader) {
  18. if (this.unprotectedHeader) {
  19. throw new TypeError('setUnprotectedHeader can only be called once');
  20. }
  21. this.unprotectedHeader = unprotectedHeader;
  22. return this;
  23. }
  24. addRecipient(...args) {
  25. return this.parent.addRecipient(...args);
  26. }
  27. encrypt(...args) {
  28. return this.parent.encrypt(...args);
  29. }
  30. done() {
  31. return this.parent;
  32. }
  33. }
  34. class GeneralEncrypt {
  35. constructor(plaintext) {
  36. this._recipients = [];
  37. this._plaintext = plaintext;
  38. }
  39. addRecipient(key, options) {
  40. const recipient = new IndividualRecipient(this, key, { crit: options === null || options === void 0 ? void 0 : options.crit });
  41. this._recipients.push(recipient);
  42. return recipient;
  43. }
  44. setProtectedHeader(protectedHeader) {
  45. if (this._protectedHeader) {
  46. throw new TypeError('setProtectedHeader can only be called once');
  47. }
  48. this._protectedHeader = protectedHeader;
  49. return this;
  50. }
  51. setSharedUnprotectedHeader(sharedUnprotectedHeader) {
  52. if (this._unprotectedHeader) {
  53. throw new TypeError('setSharedUnprotectedHeader can only be called once');
  54. }
  55. this._unprotectedHeader = sharedUnprotectedHeader;
  56. return this;
  57. }
  58. setAdditionalAuthenticatedData(aad) {
  59. this._aad = aad;
  60. return this;
  61. }
  62. async encrypt(options) {
  63. var _a, _b, _c;
  64. if (!this._recipients.length) {
  65. throw new errors_js_1.JWEInvalid('at least one recipient must be added');
  66. }
  67. options = { deflateRaw: options === null || options === void 0 ? void 0 : options.deflateRaw };
  68. if (this._recipients.length === 1) {
  69. const [recipient] = this._recipients;
  70. const flattened = await new encrypt_js_1.FlattenedEncrypt(this._plaintext)
  71. .setAdditionalAuthenticatedData(this._aad)
  72. .setProtectedHeader(this._protectedHeader)
  73. .setSharedUnprotectedHeader(this._unprotectedHeader)
  74. .setUnprotectedHeader(recipient.unprotectedHeader)
  75. .encrypt(recipient.key, { ...recipient.options, ...options });
  76. let jwe = {
  77. ciphertext: flattened.ciphertext,
  78. iv: flattened.iv,
  79. recipients: [{}],
  80. tag: flattened.tag,
  81. };
  82. if (flattened.aad)
  83. jwe.aad = flattened.aad;
  84. if (flattened.protected)
  85. jwe.protected = flattened.protected;
  86. if (flattened.unprotected)
  87. jwe.unprotected = flattened.unprotected;
  88. if (flattened.encrypted_key)
  89. jwe.recipients[0].encrypted_key = flattened.encrypted_key;
  90. if (flattened.header)
  91. jwe.recipients[0].header = flattened.header;
  92. return jwe;
  93. }
  94. let enc;
  95. for (let i = 0; i < this._recipients.length; i++) {
  96. const recipient = this._recipients[i];
  97. if (!(0, is_disjoint_js_1.default)(this._protectedHeader, this._unprotectedHeader, recipient.unprotectedHeader)) {
  98. throw new errors_js_1.JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint');
  99. }
  100. const joseHeader = {
  101. ...this._protectedHeader,
  102. ...this._unprotectedHeader,
  103. ...recipient.unprotectedHeader,
  104. };
  105. const { alg } = joseHeader;
  106. if (typeof alg !== 'string' || !alg) {
  107. throw new errors_js_1.JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid');
  108. }
  109. if (alg === 'dir' || alg === 'ECDH-ES') {
  110. throw new errors_js_1.JWEInvalid('"dir" and "ECDH-ES" alg may only be used with a single recipient');
  111. }
  112. if (typeof joseHeader.enc !== 'string' || !joseHeader.enc) {
  113. throw new errors_js_1.JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid');
  114. }
  115. if (!enc) {
  116. enc = joseHeader.enc;
  117. }
  118. else if (enc !== joseHeader.enc) {
  119. throw new errors_js_1.JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter must be the same for all recipients');
  120. }
  121. (0, validate_crit_js_1.default)(errors_js_1.JWEInvalid, new Map(), recipient.options.crit, this._protectedHeader, joseHeader);
  122. if (joseHeader.zip !== undefined) {
  123. if (!this._protectedHeader || !this._protectedHeader.zip) {
  124. throw new errors_js_1.JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected');
  125. }
  126. }
  127. }
  128. const cek = (0, cek_js_1.default)(enc);
  129. let jwe = {
  130. ciphertext: '',
  131. iv: '',
  132. recipients: [],
  133. tag: '',
  134. };
  135. for (let i = 0; i < this._recipients.length; i++) {
  136. const recipient = this._recipients[i];
  137. const target = {};
  138. jwe.recipients.push(target);
  139. const joseHeader = {
  140. ...this._protectedHeader,
  141. ...this._unprotectedHeader,
  142. ...recipient.unprotectedHeader,
  143. };
  144. const p2c = joseHeader.alg.startsWith('PBES2') ? 2048 + i : undefined;
  145. if (i === 0) {
  146. const flattened = await new encrypt_js_1.FlattenedEncrypt(this._plaintext)
  147. .setAdditionalAuthenticatedData(this._aad)
  148. .setContentEncryptionKey(cek)
  149. .setProtectedHeader(this._protectedHeader)
  150. .setSharedUnprotectedHeader(this._unprotectedHeader)
  151. .setUnprotectedHeader(recipient.unprotectedHeader)
  152. .setKeyManagementParameters({ p2c })
  153. .encrypt(recipient.key, {
  154. ...recipient.options,
  155. ...options,
  156. [encrypt_js_1.unprotected]: true,
  157. });
  158. jwe.ciphertext = flattened.ciphertext;
  159. jwe.iv = flattened.iv;
  160. jwe.tag = flattened.tag;
  161. if (flattened.aad)
  162. jwe.aad = flattened.aad;
  163. if (flattened.protected)
  164. jwe.protected = flattened.protected;
  165. if (flattened.unprotected)
  166. jwe.unprotected = flattened.unprotected;
  167. target.encrypted_key = flattened.encrypted_key;
  168. if (flattened.header)
  169. target.header = flattened.header;
  170. continue;
  171. }
  172. const { encryptedKey, parameters } = await (0, encrypt_key_management_js_1.default)(((_a = recipient.unprotectedHeader) === null || _a === void 0 ? void 0 : _a.alg) ||
  173. ((_b = this._protectedHeader) === null || _b === void 0 ? void 0 : _b.alg) ||
  174. ((_c = this._unprotectedHeader) === null || _c === void 0 ? void 0 : _c.alg), enc, recipient.key, cek, { p2c });
  175. target.encrypted_key = (0, base64url_js_1.encode)(encryptedKey);
  176. if (recipient.unprotectedHeader || parameters)
  177. target.header = { ...recipient.unprotectedHeader, ...parameters };
  178. }
  179. return jwe;
  180. }
  181. }
  182. exports.GeneralEncrypt = GeneralEncrypt;