pdf-parser.js 5.2.26 → 5.2.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/dist/{afm-widths-BYiX2L9D.cjs → afm-widths-BHD2HZIL.cjs} +553 -642
  2. package/dist/{afm-widths-blUDDjlI.js → afm-widths-B_IGbGky.js} +553 -642
  3. package/dist/afm-widths.cjs +1 -1
  4. package/dist/afm-widths.js +1 -1
  5. package/dist/annotations.cjs +5 -3
  6. package/dist/annotations.d.cts +2 -2
  7. package/dist/annotations.d.ts +2 -2
  8. package/dist/annotations.js +5 -3
  9. package/dist/attachments.d.cts +2 -2
  10. package/dist/attachments.d.ts +2 -2
  11. package/dist/builtin-encoding.cjs +17 -6
  12. package/dist/builtin-encoding.js +17 -6
  13. package/dist/bytes/crc32.cjs +5 -3
  14. package/dist/bytes/crc32.js +5 -3
  15. package/dist/bytes/flate.cjs +0 -1
  16. package/dist/bytes/flate.js +0 -1
  17. package/dist/cff-bounds.cjs +73 -45
  18. package/dist/cff-bounds.js +73 -45
  19. package/dist/cff.cjs +13 -6
  20. package/dist/cff.js +13 -6
  21. package/dist/cmap-table.cjs +54 -26
  22. package/dist/cmap-table.js +54 -26
  23. package/dist/cmap.cjs +5 -3
  24. package/dist/cmap.js +5 -3
  25. package/dist/content-read.d.cts +1 -1
  26. package/dist/content-read.d.ts +1 -1
  27. package/dist/content-write.cjs +21 -14
  28. package/dist/content-write.d.cts +2 -2
  29. package/dist/content-write.d.ts +2 -2
  30. package/dist/content-write.js +21 -14
  31. package/dist/crypto/aes.cjs +76 -55
  32. package/dist/crypto/aes.js +76 -55
  33. package/dist/crypto/md5.cjs +345 -149
  34. package/dist/crypto/md5.js +345 -149
  35. package/dist/crypto/rc4.cjs +5 -4
  36. package/dist/crypto/rc4.js +5 -4
  37. package/dist/crypto/sha2.cjs +92 -43
  38. package/dist/crypto/sha2.js +92 -43
  39. package/dist/document.cjs +17 -11
  40. package/dist/document.d.cts +1 -1
  41. package/dist/document.d.ts +1 -1
  42. package/dist/document.js +17 -11
  43. package/dist/{embedded-font-Bnhh4juV.d.ts → embedded-font-ByD7ZiQS.d.ts} +1 -1
  44. package/dist/{embedded-font-CEf-zBCA.d.cts → embedded-font-DgVBedw6.d.cts} +1 -1
  45. package/dist/embedded-font-write.d.cts +2 -2
  46. package/dist/embedded-font-write.d.ts +2 -2
  47. package/dist/embedded-font.cjs +4 -2
  48. package/dist/embedded-font.d.cts +1 -1
  49. package/dist/embedded-font.d.ts +1 -1
  50. package/dist/embedded-font.js +4 -2
  51. package/dist/encoding.cjs +1 -1
  52. package/dist/encoding.js +1 -1
  53. package/dist/encrypt-write.cjs +25 -21
  54. package/dist/encrypt-write.d.cts +1 -1
  55. package/dist/encrypt-write.d.ts +1 -1
  56. package/dist/encrypt-write.js +25 -21
  57. package/dist/encrypt.cjs +43 -64
  58. package/dist/encrypt.d.cts +1 -1
  59. package/dist/encrypt.d.ts +1 -1
  60. package/dist/encrypt.js +43 -64
  61. package/dist/filters.cjs +46 -26
  62. package/dist/filters.d.cts +1 -1
  63. package/dist/filters.d.ts +1 -1
  64. package/dist/filters.js +46 -26
  65. package/dist/font-face.cjs +2 -1
  66. package/dist/font-face.js +2 -1
  67. package/dist/font-read.cjs +12 -6
  68. package/dist/font-read.d.cts +1 -1
  69. package/dist/font-read.d.ts +1 -1
  70. package/dist/font-read.js +12 -6
  71. package/dist/font-registry.d.cts +3 -3
  72. package/dist/font-registry.d.ts +3 -3
  73. package/dist/font-tables.cjs +55 -28
  74. package/dist/font-tables.js +55 -28
  75. package/dist/form.cjs +13 -8
  76. package/dist/form.d.cts +2 -2
  77. package/dist/form.d.ts +2 -2
  78. package/dist/form.js +13 -8
  79. package/dist/gdef-table.cjs +6 -3
  80. package/dist/gdef-table.js +6 -3
  81. package/dist/{glyf-contours-C0epBNqP.d.ts → glyf-contours-B1PsI9oA.d.ts} +1 -1
  82. package/dist/{glyf-contours-BRpvd0rt.d.cts → glyf-contours-NHBpgks-.d.cts} +1 -1
  83. package/dist/glyf-contours.cjs +3 -1
  84. package/dist/glyf-contours.d.cts +1 -1
  85. package/dist/glyf-contours.d.ts +1 -1
  86. package/dist/glyf-contours.js +3 -1
  87. package/dist/glyf.cjs +22 -11
  88. package/dist/glyf.js +22 -11
  89. package/dist/gpos-table.cjs +37 -19
  90. package/dist/gpos-table.js +37 -19
  91. package/dist/gsub-table.cjs +40 -25
  92. package/dist/gsub-table.js +40 -25
  93. package/dist/hmtx-table.cjs +5 -3
  94. package/dist/hmtx-table.js +5 -3
  95. package/dist/image/ccitt-encode.cjs +8 -5
  96. package/dist/image/ccitt-encode.js +8 -5
  97. package/dist/image/ccitt.cjs +801 -209
  98. package/dist/image/ccitt.js +801 -209
  99. package/dist/image/jbig2-arith.cjs +340 -306
  100. package/dist/image/jbig2-arith.js +340 -306
  101. package/dist/image/jbig2-bitmap.cjs +8 -5
  102. package/dist/image/jbig2-bitmap.js +8 -5
  103. package/dist/image/jbig2-generic.cjs +240 -69
  104. package/dist/image/jbig2-generic.js +240 -69
  105. package/dist/image/jbig2-text.cjs +4 -2
  106. package/dist/image/jbig2-text.js +4 -2
  107. package/dist/image/jbig2.cjs +69 -31
  108. package/dist/image/jbig2.js +69 -31
  109. package/dist/image/jp2-boxes.cjs +52 -27
  110. package/dist/image/jp2-boxes.js +52 -27
  111. package/dist/image/jpeg-info.cjs +29 -24
  112. package/dist/image/jpeg-info.js +29 -24
  113. package/dist/image/jpeg2000-codestream.cjs +61 -32
  114. package/dist/image/jpeg2000-codestream.js +61 -32
  115. package/dist/image/jpeg2000-dwt.cjs +2 -1
  116. package/dist/image/jpeg2000-dwt.js +2 -1
  117. package/dist/image/jpeg2000-t1.cjs +21 -11
  118. package/dist/image/jpeg2000-t1.js +21 -11
  119. package/dist/image/jpeg2000-t2.cjs +12 -5
  120. package/dist/image/jpeg2000-t2.js +12 -5
  121. package/dist/image/jpeg2000-tagtree.cjs +8 -4
  122. package/dist/image/jpeg2000-tagtree.js +8 -4
  123. package/dist/image/jpeg2000.cjs +11 -6
  124. package/dist/image/jpeg2000.js +11 -6
  125. package/dist/image/png-decode.cjs +62 -39
  126. package/dist/image/png-decode.d.cts +3 -2
  127. package/dist/image/png-decode.d.ts +3 -2
  128. package/dist/image/png-decode.js +62 -39
  129. package/dist/image/png-filter.cjs +23 -15
  130. package/dist/image/png-filter.js +23 -15
  131. package/dist/images-read.cjs +41 -36
  132. package/dist/images-read.d.cts +2 -2
  133. package/dist/images-read.d.ts +2 -2
  134. package/dist/images-read.js +41 -36
  135. package/dist/index.cjs +1 -1
  136. package/dist/index.d.cts +1 -1
  137. package/dist/index.d.ts +1 -1
  138. package/dist/index.js +1 -1
  139. package/dist/interpret.cjs +68 -40
  140. package/dist/interpret.d.cts +1 -1
  141. package/dist/interpret.d.ts +1 -1
  142. package/dist/interpret.js +68 -40
  143. package/dist/lexer.cjs +86 -51
  144. package/dist/lexer.js +86 -51
  145. package/dist/math-content-write.cjs +9 -5
  146. package/dist/math-content-write.js +9 -5
  147. package/dist/math-font-write.cjs +2 -1
  148. package/dist/math-font-write.d.cts +1 -1
  149. package/dist/math-font-write.d.ts +1 -1
  150. package/dist/math-font-write.js +2 -1
  151. package/dist/math-font.cjs +16 -7
  152. package/dist/math-font.js +16 -7
  153. package/dist/math-table.cjs +25 -13
  154. package/dist/math-table.js +25 -13
  155. package/dist/matrix.cjs +3 -2
  156. package/dist/matrix.js +3 -2
  157. package/dist/measure.cjs +1 -1
  158. package/dist/measure.js +1 -1
  159. package/dist/names.cjs +7 -7
  160. package/dist/names.d.cts +2 -2
  161. package/dist/names.d.ts +2 -2
  162. package/dist/names.js +7 -7
  163. package/dist/navigation.cjs +16 -12
  164. package/dist/navigation.d.cts +4 -4
  165. package/dist/navigation.d.ts +4 -4
  166. package/dist/navigation.js +16 -12
  167. package/dist/{objects-B7HdMeWS.d.cts → objects-e2RS3-yT.d.cts} +3 -3
  168. package/dist/{objects-B7HdMeWS.d.ts → objects-e2RS3-yT.d.ts} +3 -3
  169. package/dist/objects.d.cts +1 -1
  170. package/dist/objects.d.ts +1 -1
  171. package/dist/optional-content.d.cts +2 -2
  172. package/dist/optional-content.d.ts +2 -2
  173. package/dist/ot-layout-common.cjs +22 -15
  174. package/dist/ot-layout-common.js +22 -15
  175. package/dist/parse.cjs +7 -5
  176. package/dist/parse.d.cts +1 -1
  177. package/dist/parse.d.ts +1 -1
  178. package/dist/parse.js +7 -5
  179. package/dist/pdf-text.cjs +5 -2
  180. package/dist/pdf-text.js +5 -2
  181. package/dist/predictors.cjs +14 -9
  182. package/dist/predictors.d.cts +1 -1
  183. package/dist/predictors.d.ts +1 -1
  184. package/dist/predictors.js +14 -9
  185. package/dist/raster.cjs +30 -19
  186. package/dist/raster.d.cts +8 -8
  187. package/dist/raster.d.ts +8 -8
  188. package/dist/raster.js +30 -19
  189. package/dist/read.cjs +29 -16
  190. package/dist/read.js +29 -16
  191. package/dist/serialize.cjs +6 -2
  192. package/dist/serialize.d.cts +1 -1
  193. package/dist/serialize.d.ts +1 -1
  194. package/dist/serialize.js +6 -2
  195. package/dist/sfnt-subset.cjs +25 -13
  196. package/dist/sfnt-subset.d.cts +1 -1
  197. package/dist/sfnt-subset.d.ts +1 -1
  198. package/dist/sfnt-subset.js +25 -13
  199. package/dist/sfnt.cjs +20 -10
  200. package/dist/sfnt.js +20 -10
  201. package/dist/structure.d.cts +2 -2
  202. package/dist/structure.d.ts +2 -2
  203. package/dist/text-group.cjs +0 -1
  204. package/dist/text-group.js +0 -1
  205. package/dist/text-layout.d.cts +1 -1
  206. package/dist/text-layout.d.ts +1 -1
  207. package/dist/tounicode.cjs +4 -2
  208. package/dist/tounicode.d.cts +1 -1
  209. package/dist/tounicode.d.ts +1 -1
  210. package/dist/tounicode.js +4 -2
  211. package/dist/winansi.cjs +1 -1
  212. package/dist/winansi.js +1 -1
  213. package/dist/write.cjs +20 -12
  214. package/dist/write.d.cts +1 -1
  215. package/dist/write.d.ts +1 -1
  216. package/dist/write.js +20 -12
  217. package/dist/xref.cjs +5 -2
  218. package/dist/xref.d.cts +1 -1
  219. package/dist/xref.d.ts +1 -1
  220. package/dist/xref.js +5 -2
  221. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- import { a as EmbeddedShow, c as encodeForShowEmbedded, i as EmbeddedKern, l as loadEmbeddedFace, n as EmbeddedFaceMetrics, o as NOTDEF_GLYPH_ID, r as EmbeddedFaceSubstitution, s as collectEmbeddedGlyphs, t as EmbeddedFace } from "./embedded-font-Bnhh4juV.js";
1
+ import { a as EmbeddedShow, c as encodeForShowEmbedded, i as EmbeddedKern, l as loadEmbeddedFace, n as EmbeddedFaceMetrics, o as NOTDEF_GLYPH_ID, r as EmbeddedFaceSubstitution, s as collectEmbeddedGlyphs, t as EmbeddedFace } from "./embedded-font-ByD7ZiQS.js";
2
2
  export { EmbeddedFace, EmbeddedFaceMetrics, EmbeddedFaceSubstitution, EmbeddedKern, EmbeddedShow, NOTDEF_GLYPH_ID, collectEmbeddedGlyphs, encodeForShowEmbedded, loadEmbeddedFace };
@@ -110,6 +110,8 @@ function parseHhea(font) {
110
110
  };
111
111
  }
112
112
  const CID_BYTE_LENGTH = 2;
113
+ const BITS_PER_BYTE = 8;
114
+ const BYTE_MASK = 255;
113
115
  function encodeForShowEmbedded(text, face) {
114
116
  const resolvedGlyphIds = [];
115
117
  const substitutions = [];
@@ -136,8 +138,8 @@ function encodeForShowEmbedded(text, face) {
136
138
  }
137
139
  const codes = new Uint8Array(shownGlyphIds.length * CID_BYTE_LENGTH);
138
140
  shownGlyphIds.forEach((glyphId, index) => {
139
- codes[index * CID_BYTE_LENGTH] = glyphId >> 8 & 255;
140
- codes[index * CID_BYTE_LENGTH + 1] = glyphId & 255;
141
+ codes[index * CID_BYTE_LENGTH] = glyphId >> BITS_PER_BYTE & BYTE_MASK;
142
+ codes[index * CID_BYTE_LENGTH + 1] = glyphId & BYTE_MASK;
141
143
  });
142
144
  return {
143
145
  codes,
package/dist/encoding.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_afm_widths = require("./afm-widths-BYiX2L9D.cjs");
2
+ const require_afm_widths = require("./afm-widths-BHD2HZIL.cjs");
3
3
  exports.MACROMAN_GLYPH_NAMES = require_afm_widths.MACROMAN_GLYPH_NAMES;
4
4
  exports.STANDARD_GLYPH_NAMES = require_afm_widths.STANDARD_GLYPH_NAMES;
5
5
  exports.SYMBOL_GLYPH_NAMES = require_afm_widths.SYMBOL_GLYPH_NAMES;
package/dist/encoding.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as SYMBOL_GLYPH_NAMES, c as glyphNameToUnicode, d as standardGlyphName, f as symbolGlyphName, i as STANDARD_GLYPH_NAMES, l as macRomanGlyphName, m as zapfDingbatsGlyphName, o as WINANSI_GLYPH_NAMES, p as winAnsiGlyphName, r as MACROMAN_GLYPH_NAMES, s as ZAPFDINGBATS_GLYPH_NAMES, u as namedEncodingGlyphName } from "./afm-widths-blUDDjlI.js";
1
+ import { a as SYMBOL_GLYPH_NAMES, c as glyphNameToUnicode, d as standardGlyphName, f as symbolGlyphName, i as STANDARD_GLYPH_NAMES, l as macRomanGlyphName, m as zapfDingbatsGlyphName, o as WINANSI_GLYPH_NAMES, p as winAnsiGlyphName, r as MACROMAN_GLYPH_NAMES, s as ZAPFDINGBATS_GLYPH_NAMES, u as namedEncodingGlyphName } from "./afm-widths-B_IGbGky.js";
2
2
  export { MACROMAN_GLYPH_NAMES, STANDARD_GLYPH_NAMES, SYMBOL_GLYPH_NAMES, WINANSI_GLYPH_NAMES, ZAPFDINGBATS_GLYPH_NAMES, glyphNameToUnicode, macRomanGlyphName, namedEncodingGlyphName, standardGlyphName, symbolGlyphName, winAnsiGlyphName, zapfDingbatsGlyphName };
@@ -15,6 +15,8 @@ var PdfEncryptionError = class extends Error {
15
15
  };
16
16
  const RC4_128_KEY_BYTES = 16;
17
17
  const R6_PASSWORD_MAX_BYTES = 127;
18
+ const BITS_PER_BYTE = 8;
19
+ const MAX_PERMISSION_BITS = 32;
18
20
  const RESERVED_BIT_7_AND_8 = 192;
19
21
  const DEPRECATED_ALWAYS_ONE_BIT_10 = 512;
20
22
  const SCHEME_SPECS = {
@@ -43,11 +45,12 @@ const SCHEME_SPECS = {
43
45
  method: "aes"
44
46
  }
45
47
  };
48
+ const MAX_PRINTABLE_ASCII = 127;
46
49
  function legacyPasswordBytes(password) {
47
50
  const bytes = new Uint8Array(password.length);
48
51
  for (let i = 0; i < password.length; i++) {
49
52
  const code = password.charCodeAt(i);
50
- if (code > 127) throw new PdfEncryptionError(`password contains character code ${String(code)}, outside the printable-ASCII range this writer supports for the rc4-40/rc4-128/aes-128 schemes; use a plain-ASCII password, or the aes-256 scheme, whose revision-6 passwords are Unicode`);
53
+ if (code > MAX_PRINTABLE_ASCII) throw new PdfEncryptionError(`password contains character code ${String(code)}, outside the printable-ASCII range this writer supports for the rc4-40/rc4-128/aes-128 schemes; use a plain-ASCII password, or the aes-256 scheme, whose revision-6 passwords are Unicode`);
51
54
  bytes[i] = code;
52
55
  }
53
56
  return bytes;
@@ -66,15 +69,16 @@ function permissionsToP(permissions) {
66
69
  p |= DEPRECATED_ALWAYS_ONE_BIT_10;
67
70
  if (permissions?.assemble ?? true) p |= 1024;
68
71
  if (permissions?.printHighRes ?? true) p |= 2048;
69
- for (let bit = 13; bit <= 32; bit++) p |= 1 << bit - 1;
72
+ for (let bit = 13; bit <= MAX_PERMISSION_BITS; bit++) p |= 1 << bit - 1;
70
73
  return p;
71
74
  }
75
+ const ITERATED_REVISION_MIN = 3;
72
76
  function computeLegacyOwnerValue(ownerPassword, userPassword, revision, keyBytes) {
73
77
  let digest = require_crypto_md5.md5(require_encrypt.padOrTruncatePassword(ownerPassword));
74
- if (revision >= 3) for (let i = 0; i < 50; i++) digest = require_crypto_md5.md5(digest);
78
+ if (revision >= ITERATED_REVISION_MIN) for (let i = 0; i < 50; i++) digest = require_crypto_md5.md5(digest);
75
79
  const ownerKey = digest.subarray(0, keyBytes);
76
80
  let value = require_crypto_rc4.rc4(ownerKey, require_encrypt.padOrTruncatePassword(userPassword));
77
- if (revision >= 3) for (let i = 1; i <= 19; i++) {
81
+ if (revision >= ITERATED_REVISION_MIN) for (let i = 1; i <= 19; i++) {
78
82
  const roundKey = Uint8Array.from(ownerKey, (byte) => byte ^ i);
79
83
  value = require_crypto_rc4.rc4(roundKey, value);
80
84
  }
@@ -125,9 +129,9 @@ function buildLegacyEncryptor(spec, options, fileId) {
125
129
  ["O", require_objects.pdfHexString(owner)],
126
130
  ["U", require_objects.pdfHexString(user)],
127
131
  ["P", require_objects.pdfNum(p)],
128
- ["Length", require_objects.pdfNum(spec.keyBytes * 8)]
132
+ ["Length", require_objects.pdfNum(spec.keyBytes * BITS_PER_BYTE)]
129
133
  ]);
130
- if (spec.v === 4) {
134
+ if (spec.v === SCHEME_SPECS["aes-128"].v) {
131
135
  entries.set("CF", require_objects.pdfDict({ StdCF: require_objects.pdfDict({
132
136
  AuthEvent: require_objects.pdfName("DocOpen"),
133
137
  CFM: require_objects.pdfName("AESV2"),
@@ -166,21 +170,21 @@ function buildAes256Encryptor(spec, options) {
166
170
  ]);
167
171
  const ownerIntermediateKey = require_encrypt.hardenedHash(ownerPassword, ownerKeySalt, u, spec.r);
168
172
  const oe = require_crypto_aes.aesCbcEncrypt(ownerIntermediateKey, require_encrypt.ZERO_IV, fileKey);
173
+ const PERMS_P_BYTES = 4;
174
+ const PERMS_SIGN_EXTENSION_BYTES = new Uint8Array(PERMS_P_BYTES).fill(255);
175
+ const PERMS_METADATA_FLAG_OFFSET = 8;
176
+ const ENCRYPT_METADATA_TRUE_ASCII = 84;
177
+ const ENCRYPT_METADATA_FALSE_ASCII = 70;
178
+ const ADB_MARKER_OFFSET = 9;
179
+ const ADB_MARKER_BYTES = Uint8Array.from("adb", (c) => c.charCodeAt(0));
180
+ const PERMS_RANDOM_BYTES = 4;
181
+ const PERMS_RANDOM_OFFSET = ADB_MARKER_OFFSET + ADB_MARKER_BYTES.length;
169
182
  const permsBlock = /* @__PURE__ */ new Uint8Array(16);
170
183
  permsBlock.set(require_encrypt.permissionsBytes(p), 0);
171
- permsBlock.set([
172
- 255,
173
- 255,
174
- 255,
175
- 255
176
- ], 4);
177
- permsBlock[8] = encryptMetadata ? 84 : 70;
178
- permsBlock.set([
179
- 97,
180
- 100,
181
- 98
182
- ], 9);
183
- permsBlock.set(require_crypto_random.randomBytes(4), 12);
184
+ permsBlock.set(PERMS_SIGN_EXTENSION_BYTES, PERMS_P_BYTES);
185
+ permsBlock[PERMS_METADATA_FLAG_OFFSET] = encryptMetadata ? ENCRYPT_METADATA_TRUE_ASCII : ENCRYPT_METADATA_FALSE_ASCII;
186
+ permsBlock.set(ADB_MARKER_BYTES, ADB_MARKER_OFFSET);
187
+ permsBlock.set(require_crypto_random.randomBytes(PERMS_RANDOM_BYTES), PERMS_RANDOM_OFFSET);
184
188
  const perms = require_crypto_aes.aesCbcEncrypt(fileKey, require_encrypt.ZERO_IV, permsBlock);
185
189
  const entries = /* @__PURE__ */ new Map([
186
190
  ["Filter", require_objects.pdfName("Standard")],
@@ -192,7 +196,7 @@ function buildAes256Encryptor(spec, options) {
192
196
  ["UE", require_objects.pdfHexString(ue)],
193
197
  ["P", require_objects.pdfNum(p)],
194
198
  ["Perms", require_objects.pdfHexString(perms)],
195
- ["Length", require_objects.pdfNum(spec.keyBytes * 8)],
199
+ ["Length", require_objects.pdfNum(spec.keyBytes * BITS_PER_BYTE)],
196
200
  ["CF", require_objects.pdfDict({ StdCF: require_objects.pdfDict({
197
201
  AuthEvent: require_objects.pdfName("DocOpen"),
198
202
  CFM: require_objects.pdfName("AESV3"),
@@ -207,7 +211,7 @@ function buildAes256Encryptor(spec, options) {
207
211
  function createStandardEncryptor(options, fileId) {
208
212
  const scheme = options.scheme ?? "aes-256";
209
213
  const spec = SCHEME_SPECS[scheme];
210
- return spec.v === 5 ? buildAes256Encryptor(spec, options) : buildLegacyEncryptor(spec, options, fileId);
214
+ return spec.v === SCHEME_SPECS["aes-256"].v ? buildAes256Encryptor(spec, options) : buildLegacyEncryptor(spec, options, fileId);
211
215
  }
212
216
  function encryptIndirectObject(value, num, gen, encryptor) {
213
217
  if (value.kind === "string") return {
@@ -1,4 +1,4 @@
1
- import { n as PdfDict, r as PdfObject } from "./objects-B7HdMeWS.cjs";
1
+ import { n as PdfDict, r as PdfObject } from "./objects-e2RS3-yT.cjs";
2
2
  //#region src/encrypt-write.d.ts
3
3
  declare class PdfEncryptionError extends Error {
4
4
  constructor(message: string);
@@ -1,4 +1,4 @@
1
- import { n as PdfDict, r as PdfObject } from "./objects-B7HdMeWS.js";
1
+ import { n as PdfDict, r as PdfObject } from "./objects-e2RS3-yT.js";
2
2
  //#region src/encrypt-write.d.ts
3
3
  declare class PdfEncryptionError extends Error {
4
4
  constructor(message: string);
@@ -14,6 +14,8 @@ var PdfEncryptionError = class extends Error {
14
14
  };
15
15
  const RC4_128_KEY_BYTES = 16;
16
16
  const R6_PASSWORD_MAX_BYTES = 127;
17
+ const BITS_PER_BYTE = 8;
18
+ const MAX_PERMISSION_BITS = 32;
17
19
  const RESERVED_BIT_7_AND_8 = 192;
18
20
  const DEPRECATED_ALWAYS_ONE_BIT_10 = 512;
19
21
  const SCHEME_SPECS = {
@@ -42,11 +44,12 @@ const SCHEME_SPECS = {
42
44
  method: "aes"
43
45
  }
44
46
  };
47
+ const MAX_PRINTABLE_ASCII = 127;
45
48
  function legacyPasswordBytes(password) {
46
49
  const bytes = new Uint8Array(password.length);
47
50
  for (let i = 0; i < password.length; i++) {
48
51
  const code = password.charCodeAt(i);
49
- if (code > 127) throw new PdfEncryptionError(`password contains character code ${String(code)}, outside the printable-ASCII range this writer supports for the rc4-40/rc4-128/aes-128 schemes; use a plain-ASCII password, or the aes-256 scheme, whose revision-6 passwords are Unicode`);
52
+ if (code > MAX_PRINTABLE_ASCII) throw new PdfEncryptionError(`password contains character code ${String(code)}, outside the printable-ASCII range this writer supports for the rc4-40/rc4-128/aes-128 schemes; use a plain-ASCII password, or the aes-256 scheme, whose revision-6 passwords are Unicode`);
50
53
  bytes[i] = code;
51
54
  }
52
55
  return bytes;
@@ -65,15 +68,16 @@ function permissionsToP(permissions) {
65
68
  p |= DEPRECATED_ALWAYS_ONE_BIT_10;
66
69
  if (permissions?.assemble ?? true) p |= 1024;
67
70
  if (permissions?.printHighRes ?? true) p |= 2048;
68
- for (let bit = 13; bit <= 32; bit++) p |= 1 << bit - 1;
71
+ for (let bit = 13; bit <= MAX_PERMISSION_BITS; bit++) p |= 1 << bit - 1;
69
72
  return p;
70
73
  }
74
+ const ITERATED_REVISION_MIN = 3;
71
75
  function computeLegacyOwnerValue(ownerPassword, userPassword, revision, keyBytes) {
72
76
  let digest = md5(padOrTruncatePassword(ownerPassword));
73
- if (revision >= 3) for (let i = 0; i < 50; i++) digest = md5(digest);
77
+ if (revision >= ITERATED_REVISION_MIN) for (let i = 0; i < 50; i++) digest = md5(digest);
74
78
  const ownerKey = digest.subarray(0, keyBytes);
75
79
  let value = rc4(ownerKey, padOrTruncatePassword(userPassword));
76
- if (revision >= 3) for (let i = 1; i <= 19; i++) {
80
+ if (revision >= ITERATED_REVISION_MIN) for (let i = 1; i <= 19; i++) {
77
81
  const roundKey = Uint8Array.from(ownerKey, (byte) => byte ^ i);
78
82
  value = rc4(roundKey, value);
79
83
  }
@@ -124,9 +128,9 @@ function buildLegacyEncryptor(spec, options, fileId) {
124
128
  ["O", pdfHexString(owner)],
125
129
  ["U", pdfHexString(user)],
126
130
  ["P", pdfNum(p)],
127
- ["Length", pdfNum(spec.keyBytes * 8)]
131
+ ["Length", pdfNum(spec.keyBytes * BITS_PER_BYTE)]
128
132
  ]);
129
- if (spec.v === 4) {
133
+ if (spec.v === SCHEME_SPECS["aes-128"].v) {
130
134
  entries.set("CF", pdfDict({ StdCF: pdfDict({
131
135
  AuthEvent: pdfName("DocOpen"),
132
136
  CFM: pdfName("AESV2"),
@@ -165,21 +169,21 @@ function buildAes256Encryptor(spec, options) {
165
169
  ]);
166
170
  const ownerIntermediateKey = hardenedHash(ownerPassword, ownerKeySalt, u, spec.r);
167
171
  const oe = aesCbcEncrypt(ownerIntermediateKey, ZERO_IV, fileKey);
172
+ const PERMS_P_BYTES = 4;
173
+ const PERMS_SIGN_EXTENSION_BYTES = new Uint8Array(PERMS_P_BYTES).fill(255);
174
+ const PERMS_METADATA_FLAG_OFFSET = 8;
175
+ const ENCRYPT_METADATA_TRUE_ASCII = 84;
176
+ const ENCRYPT_METADATA_FALSE_ASCII = 70;
177
+ const ADB_MARKER_OFFSET = 9;
178
+ const ADB_MARKER_BYTES = Uint8Array.from("adb", (c) => c.charCodeAt(0));
179
+ const PERMS_RANDOM_BYTES = 4;
180
+ const PERMS_RANDOM_OFFSET = ADB_MARKER_OFFSET + ADB_MARKER_BYTES.length;
168
181
  const permsBlock = /* @__PURE__ */ new Uint8Array(16);
169
182
  permsBlock.set(permissionsBytes(p), 0);
170
- permsBlock.set([
171
- 255,
172
- 255,
173
- 255,
174
- 255
175
- ], 4);
176
- permsBlock[8] = encryptMetadata ? 84 : 70;
177
- permsBlock.set([
178
- 97,
179
- 100,
180
- 98
181
- ], 9);
182
- permsBlock.set(randomBytes(4), 12);
183
+ permsBlock.set(PERMS_SIGN_EXTENSION_BYTES, PERMS_P_BYTES);
184
+ permsBlock[PERMS_METADATA_FLAG_OFFSET] = encryptMetadata ? ENCRYPT_METADATA_TRUE_ASCII : ENCRYPT_METADATA_FALSE_ASCII;
185
+ permsBlock.set(ADB_MARKER_BYTES, ADB_MARKER_OFFSET);
186
+ permsBlock.set(randomBytes(PERMS_RANDOM_BYTES), PERMS_RANDOM_OFFSET);
183
187
  const perms = aesCbcEncrypt(fileKey, ZERO_IV, permsBlock);
184
188
  const entries = /* @__PURE__ */ new Map([
185
189
  ["Filter", pdfName("Standard")],
@@ -191,7 +195,7 @@ function buildAes256Encryptor(spec, options) {
191
195
  ["UE", pdfHexString(ue)],
192
196
  ["P", pdfNum(p)],
193
197
  ["Perms", pdfHexString(perms)],
194
- ["Length", pdfNum(spec.keyBytes * 8)],
198
+ ["Length", pdfNum(spec.keyBytes * BITS_PER_BYTE)],
195
199
  ["CF", pdfDict({ StdCF: pdfDict({
196
200
  AuthEvent: pdfName("DocOpen"),
197
201
  CFM: pdfName("AESV3"),
@@ -206,7 +210,7 @@ function buildAes256Encryptor(spec, options) {
206
210
  function createStandardEncryptor(options, fileId) {
207
211
  const scheme = options.scheme ?? "aes-256";
208
212
  const spec = SCHEME_SPECS[scheme];
209
- return spec.v === 5 ? buildAes256Encryptor(spec, options) : buildLegacyEncryptor(spec, options, fileId);
213
+ return spec.v === SCHEME_SPECS["aes-256"].v ? buildAes256Encryptor(spec, options) : buildLegacyEncryptor(spec, options, fileId);
210
214
  }
211
215
  function encryptIndirectObject(value, num, gen, encryptor) {
212
216
  if (value.kind === "string") return {
package/dist/encrypt.cjs CHANGED
@@ -7,46 +7,18 @@ const require_crypto_md5 = require("./crypto/md5.cjs");
7
7
  const require_crypto_rc4 = require("./crypto/rc4.cjs");
8
8
  const require_crypto_sha2 = require("./crypto/sha2.cjs");
9
9
  //#region src/encrypt.ts
10
- const PASSWORD_PADDING = new Uint8Array([
11
- 40,
12
- 191,
13
- 78,
14
- 94,
15
- 78,
16
- 117,
17
- 138,
18
- 65,
19
- 100,
20
- 0,
21
- 78,
22
- 86,
23
- 255,
24
- 250,
25
- 1,
26
- 8,
27
- 46,
28
- 46,
29
- 0,
30
- 182,
31
- 208,
32
- 104,
33
- 62,
34
- 128,
35
- 47,
36
- 12,
37
- 169,
38
- 254,
39
- 100,
40
- 83,
41
- 105,
42
- 122
43
- ]);
44
- const AES_OBJECT_KEY_SALT = new Uint8Array([
45
- 115,
46
- 65,
47
- 108,
48
- 84
49
- ]);
10
+ const HEX_RADIX = 16;
11
+ const HEX_CHARS_PER_BYTE = 2;
12
+ function bytesFromHex(hex) {
13
+ const bytes = new Uint8Array(hex.length / HEX_CHARS_PER_BYTE);
14
+ for (let i = 0; i < bytes.length; i++) {
15
+ const start = i * HEX_CHARS_PER_BYTE;
16
+ bytes[i] = parseInt(hex.substring(start, start + HEX_CHARS_PER_BYTE), HEX_RADIX);
17
+ }
18
+ return bytes;
19
+ }
20
+ const PASSWORD_PADDING = bytesFromHex("28bf4e5e4e758a4164004e56fffa01082e2e00b6d0683e802f0ca9fe6453697a");
21
+ const AES_OBJECT_KEY_SALT = new TextEncoder().encode("sAlT");
50
22
  const MD5_DIGEST_BYTES = 16;
51
23
  const OBJECT_KEY_EXTRA_BYTES = 5;
52
24
  const LEGACY_KEY_ITERATIONS = 50;
@@ -60,6 +32,9 @@ const RC4_40_KEY_BYTES = 5;
60
32
  const AESV2_KEY_BYTES = 16;
61
33
  const DEFAULT_KEY_BITS = 40;
62
34
  const BITS_PER_BYTE = 8;
35
+ const BYTE_MASK = 255;
36
+ const UINT32_BYTE_2_SHIFT = 16;
37
+ const UINT32_BYTE_3_SHIFT = 24;
63
38
  const MAX_RC4_KEY_BYTES = 16;
64
39
  const ZERO_IV = /* @__PURE__ */ new Uint8Array(16);
65
40
  function requireStringBytes(dict, key) {
@@ -74,10 +49,10 @@ function bytesEqual(a, b, length) {
74
49
  function permissionsBytes(p) {
75
50
  const unsigned = Math.trunc(p) >>> 0;
76
51
  return new Uint8Array([
77
- unsigned & 255,
78
- unsigned >>> 8 & 255,
79
- unsigned >>> 16 & 255,
80
- unsigned >>> 24 & 255
52
+ unsigned & BYTE_MASK,
53
+ unsigned >>> BITS_PER_BYTE & BYTE_MASK,
54
+ unsigned >>> UINT32_BYTE_2_SHIFT & BYTE_MASK,
55
+ unsigned >>> UINT32_BYTE_3_SHIFT & BYTE_MASK
81
56
  ]);
82
57
  }
83
58
  function padOrTruncatePassword(password) {
@@ -85,6 +60,9 @@ function padOrTruncatePassword(password) {
85
60
  padded.set(password.subarray(0, PASSWORD_PADDING.length));
86
61
  return padded;
87
62
  }
63
+ const METADATA_FLAG_MIN_REVISION = 4;
64
+ const METADATA_NOT_ENCRYPTED_FLAG_BYTES = 4;
65
+ const ITERATED_REVISION_MIN = 3;
88
66
  function computeLegacyFileKeyFromPaddedPassword(paddedPassword, owner, permissions, fileId, revision, keyBytes, encryptMetadata) {
89
67
  const parts = [
90
68
  paddedPassword,
@@ -92,14 +70,9 @@ function computeLegacyFileKeyFromPaddedPassword(paddedPassword, owner, permissio
92
70
  permissionsBytes(permissions),
93
71
  fileId
94
72
  ];
95
- if (revision >= 4 && !encryptMetadata) parts.push(new Uint8Array([
96
- 255,
97
- 255,
98
- 255,
99
- 255
100
- ]));
73
+ if (revision >= METADATA_FLAG_MIN_REVISION && !encryptMetadata) parts.push(new Uint8Array(METADATA_NOT_ENCRYPTED_FLAG_BYTES).fill(BYTE_MASK));
101
74
  let digest = require_crypto_md5.md5(require_bytes_writer.concatBytes(parts));
102
- if (revision >= 3) for (let i = 0; i < 50; i++) digest = require_crypto_md5.md5(digest.subarray(0, keyBytes));
75
+ if (revision >= ITERATED_REVISION_MIN) for (let i = 0; i < 50; i++) digest = require_crypto_md5.md5(digest.subarray(0, keyBytes));
103
76
  return digest.subarray(0, keyBytes);
104
77
  }
105
78
  function computeLegacyFileKey(encryptDict, fileId, revision, keyBytes, encryptMetadata) {
@@ -120,13 +93,16 @@ function legacyUserPasswordVerifies(encryptDict, fileId, revision, fileKey) {
120
93
  const storedUser = requireStringBytes(encryptDict, "U");
121
94
  return bytesEqual(legacyUserValueCore(fileKey, fileId, revision), storedUser, revision === 2 ? PASSWORD_PADDING.length : 16);
122
95
  }
96
+ const HARDENED_HASH_SHA256_ONLY_REVISION = 5;
97
+ const STANDARD_AESV3_REVISION = 6;
98
+ const HASH_SELECTOR_MODULUS = 3;
123
99
  function hardenedHash(password, salt, userData, revision) {
124
100
  let k = require_crypto_sha2.sha256(require_bytes_writer.concatBytes([
125
101
  password,
126
102
  salt,
127
103
  userData
128
104
  ]));
129
- if (revision === 5) return k;
105
+ if (revision === HARDENED_HASH_SHA256_ONLY_REVISION) return k;
130
106
  let e;
131
107
  let round = 0;
132
108
  do {
@@ -140,7 +116,7 @@ function hardenedHash(password, salt, userData, revision) {
140
116
  e = require_crypto_aes.aesCbcEncrypt(k.subarray(0, 16), k.subarray(16, 32), k1);
141
117
  let sum = 0;
142
118
  for (let i = 0; i < 16; i++) sum += e[i];
143
- const selector = sum % 3;
119
+ const selector = sum % HASH_SELECTOR_MODULUS;
144
120
  k = selector === 0 ? require_crypto_sha2.sha256(e) : selector === 1 ? require_crypto_sha2.sha384(e) : require_crypto_sha2.sha512(e);
145
121
  round++;
146
122
  } while (round < R6_MINIMUM_ROUNDS || e[e.length - 1] > round - R6_TERMINATION_MARGIN);
@@ -180,14 +156,17 @@ function cryptFilterKeyBytes(encryptDict, declaredBits) {
180
156
  if (declared === void 0) return Math.floor(declaredBits / BITS_PER_BYTE);
181
157
  return declared >= DEFAULT_KEY_BITS ? Math.floor(declared / BITS_PER_BYTE) : declared;
182
158
  }
159
+ const V5_HANDLER_VERSION = 5;
160
+ const V4_HANDLER_VERSION = 4;
161
+ const LEGACY_MAX_REVISION = 4;
183
162
  function setUpHandler(encryptDict, fileId) {
184
163
  const version = require_objects.asNumber(require_objects.dictGet(encryptDict, "V")) ?? 0;
185
164
  const revision = require_objects.asNumber(require_objects.dictGet(encryptDict, "R")) ?? 0;
186
165
  const declaredBits = require_objects.asNumber(require_objects.dictGet(encryptDict, "Length")) ?? DEFAULT_KEY_BITS;
187
166
  const encryptMetadataEntry = require_objects.dictGet(encryptDict, "EncryptMetadata");
188
167
  const encryptMetadata = encryptMetadataEntry?.kind === "bool" ? encryptMetadataEntry.value : true;
189
- if (version === 5) {
190
- if (revision !== 5 && revision !== 6) throw new require_diagnostics.PdfEncryptedError(`/V 5 encryption with an unsupported revision /R ${String(revision)}`);
168
+ if (version === V5_HANDLER_VERSION) {
169
+ if (revision !== HARDENED_HASH_SHA256_ONLY_REVISION && revision !== STANDARD_AESV3_REVISION) throw new require_diagnostics.PdfEncryptedError(`/V 5 encryption with an unsupported revision /R ${String(revision)}`);
191
170
  return {
192
171
  fileKey: computeAesV3FileKey(encryptDict, revision),
193
172
  streamMethod: methodFromCryptFilterName(encryptDict, "StmF"),
@@ -196,10 +175,10 @@ function setUpHandler(encryptDict, fileId) {
196
175
  encryptMetadata
197
176
  };
198
177
  }
199
- if (version !== 1 && version !== 2 && version !== 4) throw new require_diagnostics.PdfEncryptedError(`unsupported standard security handler version /V ${String(version)}`);
200
- if (revision < 2 || revision > 4) throw new require_diagnostics.PdfEncryptedError(`unsupported standard security handler revision /R ${String(revision)}`);
201
- const streamMethod = version === 4 ? methodFromCryptFilterName(encryptDict, "StmF") : "rc4";
202
- const stringMethod = version === 4 ? methodFromCryptFilterName(encryptDict, "StrF") : "rc4";
178
+ if (version !== 1 && version !== 2 && version !== V4_HANDLER_VERSION) throw new require_diagnostics.PdfEncryptedError(`unsupported standard security handler version /V ${String(version)}`);
179
+ if (revision < 2 || revision > LEGACY_MAX_REVISION) throw new require_diagnostics.PdfEncryptedError(`unsupported standard security handler revision /R ${String(revision)}`);
180
+ const streamMethod = version === V4_HANDLER_VERSION ? methodFromCryptFilterName(encryptDict, "StmF") : "rc4";
181
+ const stringMethod = version === V4_HANDLER_VERSION ? methodFromCryptFilterName(encryptDict, "StrF") : "rc4";
203
182
  const keyBytes = version === 1 ? 5 : version === 2 ? Math.floor(declaredBits / BITS_PER_BYTE) : cryptFilterKeyBytes(encryptDict, declaredBits);
204
183
  if (keyBytes < 5 || keyBytes > MAX_RC4_KEY_BYTES) throw new require_diagnostics.PdfEncryptedError(`the /Encrypt dictionary declares a ${String(keyBytes * BITS_PER_BYTE)}-bit file key, outside the 40-128 bit range /V ${String(version)} permits`);
205
184
  const fileKey = computeLegacyFileKey(encryptDict, fileId, revision, keyBytes, encryptMetadata);
@@ -214,11 +193,11 @@ function setUpHandler(encryptDict, fileId) {
214
193
  }
215
194
  function objectKey(fileKey, num, gen, method) {
216
195
  const extra = new Uint8Array(OBJECT_KEY_EXTRA_BYTES);
217
- extra[0] = num & 255;
218
- extra[1] = num >>> 8 & 255;
219
- extra[2] = num >>> 16 & 255;
220
- extra[3] = gen & 255;
221
- extra[4] = gen >>> 8 & 255;
196
+ extra[0] = num & BYTE_MASK;
197
+ extra[1] = num >>> BITS_PER_BYTE & BYTE_MASK;
198
+ extra[2] = num >>> UINT32_BYTE_2_SHIFT & BYTE_MASK;
199
+ extra[3] = gen & BYTE_MASK;
200
+ extra[4] = gen >>> BITS_PER_BYTE & BYTE_MASK;
222
201
  return require_crypto_md5.md5(require_bytes_writer.concatBytes(method === "aes" ? [
223
202
  fileKey,
224
203
  extra,
@@ -1,5 +1,5 @@
1
1
  import { PdfDiagnosticSink } from "./diagnostics.cjs";
2
- import { n as PdfDict } from "./objects-B7HdMeWS.cjs";
2
+ import { n as PdfDict } from "./objects-e2RS3-yT.cjs";
3
3
  //#region src/encrypt.d.ts
4
4
  type CipherMethod = "identity" | "rc4" | "aes";
5
5
  interface PdfDecryptor {
package/dist/encrypt.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PdfDiagnosticSink } from "./diagnostics.js";
2
- import { n as PdfDict } from "./objects-B7HdMeWS.js";
2
+ import { n as PdfDict } from "./objects-e2RS3-yT.js";
3
3
  //#region src/encrypt.d.ts
4
4
  type CipherMethod = "identity" | "rc4" | "aes";
5
5
  interface PdfDecryptor {
package/dist/encrypt.js CHANGED
@@ -6,46 +6,18 @@ import { md5 } from "./crypto/md5.js";
6
6
  import { rc4 } from "./crypto/rc4.js";
7
7
  import { sha256, sha384, sha512 } from "./crypto/sha2.js";
8
8
  //#region src/encrypt.ts
9
- const PASSWORD_PADDING = new Uint8Array([
10
- 40,
11
- 191,
12
- 78,
13
- 94,
14
- 78,
15
- 117,
16
- 138,
17
- 65,
18
- 100,
19
- 0,
20
- 78,
21
- 86,
22
- 255,
23
- 250,
24
- 1,
25
- 8,
26
- 46,
27
- 46,
28
- 0,
29
- 182,
30
- 208,
31
- 104,
32
- 62,
33
- 128,
34
- 47,
35
- 12,
36
- 169,
37
- 254,
38
- 100,
39
- 83,
40
- 105,
41
- 122
42
- ]);
43
- const AES_OBJECT_KEY_SALT = new Uint8Array([
44
- 115,
45
- 65,
46
- 108,
47
- 84
48
- ]);
9
+ const HEX_RADIX = 16;
10
+ const HEX_CHARS_PER_BYTE = 2;
11
+ function bytesFromHex(hex) {
12
+ const bytes = new Uint8Array(hex.length / HEX_CHARS_PER_BYTE);
13
+ for (let i = 0; i < bytes.length; i++) {
14
+ const start = i * HEX_CHARS_PER_BYTE;
15
+ bytes[i] = parseInt(hex.substring(start, start + HEX_CHARS_PER_BYTE), HEX_RADIX);
16
+ }
17
+ return bytes;
18
+ }
19
+ const PASSWORD_PADDING = bytesFromHex("28bf4e5e4e758a4164004e56fffa01082e2e00b6d0683e802f0ca9fe6453697a");
20
+ const AES_OBJECT_KEY_SALT = new TextEncoder().encode("sAlT");
49
21
  const MD5_DIGEST_BYTES = 16;
50
22
  const OBJECT_KEY_EXTRA_BYTES = 5;
51
23
  const LEGACY_KEY_ITERATIONS = 50;
@@ -59,6 +31,9 @@ const RC4_40_KEY_BYTES = 5;
59
31
  const AESV2_KEY_BYTES = 16;
60
32
  const DEFAULT_KEY_BITS = 40;
61
33
  const BITS_PER_BYTE = 8;
34
+ const BYTE_MASK = 255;
35
+ const UINT32_BYTE_2_SHIFT = 16;
36
+ const UINT32_BYTE_3_SHIFT = 24;
62
37
  const MAX_RC4_KEY_BYTES = 16;
63
38
  const ZERO_IV = /* @__PURE__ */ new Uint8Array(16);
64
39
  function requireStringBytes(dict, key) {
@@ -73,10 +48,10 @@ function bytesEqual(a, b, length) {
73
48
  function permissionsBytes(p) {
74
49
  const unsigned = Math.trunc(p) >>> 0;
75
50
  return new Uint8Array([
76
- unsigned & 255,
77
- unsigned >>> 8 & 255,
78
- unsigned >>> 16 & 255,
79
- unsigned >>> 24 & 255
51
+ unsigned & BYTE_MASK,
52
+ unsigned >>> BITS_PER_BYTE & BYTE_MASK,
53
+ unsigned >>> UINT32_BYTE_2_SHIFT & BYTE_MASK,
54
+ unsigned >>> UINT32_BYTE_3_SHIFT & BYTE_MASK
80
55
  ]);
81
56
  }
82
57
  function padOrTruncatePassword(password) {
@@ -84,6 +59,9 @@ function padOrTruncatePassword(password) {
84
59
  padded.set(password.subarray(0, PASSWORD_PADDING.length));
85
60
  return padded;
86
61
  }
62
+ const METADATA_FLAG_MIN_REVISION = 4;
63
+ const METADATA_NOT_ENCRYPTED_FLAG_BYTES = 4;
64
+ const ITERATED_REVISION_MIN = 3;
87
65
  function computeLegacyFileKeyFromPaddedPassword(paddedPassword, owner, permissions, fileId, revision, keyBytes, encryptMetadata) {
88
66
  const parts = [
89
67
  paddedPassword,
@@ -91,14 +69,9 @@ function computeLegacyFileKeyFromPaddedPassword(paddedPassword, owner, permissio
91
69
  permissionsBytes(permissions),
92
70
  fileId
93
71
  ];
94
- if (revision >= 4 && !encryptMetadata) parts.push(new Uint8Array([
95
- 255,
96
- 255,
97
- 255,
98
- 255
99
- ]));
72
+ if (revision >= METADATA_FLAG_MIN_REVISION && !encryptMetadata) parts.push(new Uint8Array(METADATA_NOT_ENCRYPTED_FLAG_BYTES).fill(BYTE_MASK));
100
73
  let digest = md5(concatBytes(parts));
101
- if (revision >= 3) for (let i = 0; i < 50; i++) digest = md5(digest.subarray(0, keyBytes));
74
+ if (revision >= ITERATED_REVISION_MIN) for (let i = 0; i < 50; i++) digest = md5(digest.subarray(0, keyBytes));
102
75
  return digest.subarray(0, keyBytes);
103
76
  }
104
77
  function computeLegacyFileKey(encryptDict, fileId, revision, keyBytes, encryptMetadata) {
@@ -119,13 +92,16 @@ function legacyUserPasswordVerifies(encryptDict, fileId, revision, fileKey) {
119
92
  const storedUser = requireStringBytes(encryptDict, "U");
120
93
  return bytesEqual(legacyUserValueCore(fileKey, fileId, revision), storedUser, revision === 2 ? PASSWORD_PADDING.length : 16);
121
94
  }
95
+ const HARDENED_HASH_SHA256_ONLY_REVISION = 5;
96
+ const STANDARD_AESV3_REVISION = 6;
97
+ const HASH_SELECTOR_MODULUS = 3;
122
98
  function hardenedHash(password, salt, userData, revision) {
123
99
  let k = sha256(concatBytes([
124
100
  password,
125
101
  salt,
126
102
  userData
127
103
  ]));
128
- if (revision === 5) return k;
104
+ if (revision === HARDENED_HASH_SHA256_ONLY_REVISION) return k;
129
105
  let e;
130
106
  let round = 0;
131
107
  do {
@@ -139,7 +115,7 @@ function hardenedHash(password, salt, userData, revision) {
139
115
  e = aesCbcEncrypt(k.subarray(0, 16), k.subarray(16, 32), k1);
140
116
  let sum = 0;
141
117
  for (let i = 0; i < 16; i++) sum += e[i];
142
- const selector = sum % 3;
118
+ const selector = sum % HASH_SELECTOR_MODULUS;
143
119
  k = selector === 0 ? sha256(e) : selector === 1 ? sha384(e) : sha512(e);
144
120
  round++;
145
121
  } while (round < R6_MINIMUM_ROUNDS || e[e.length - 1] > round - R6_TERMINATION_MARGIN);
@@ -179,14 +155,17 @@ function cryptFilterKeyBytes(encryptDict, declaredBits) {
179
155
  if (declared === void 0) return Math.floor(declaredBits / BITS_PER_BYTE);
180
156
  return declared >= DEFAULT_KEY_BITS ? Math.floor(declared / BITS_PER_BYTE) : declared;
181
157
  }
158
+ const V5_HANDLER_VERSION = 5;
159
+ const V4_HANDLER_VERSION = 4;
160
+ const LEGACY_MAX_REVISION = 4;
182
161
  function setUpHandler(encryptDict, fileId) {
183
162
  const version = asNumber(dictGet(encryptDict, "V")) ?? 0;
184
163
  const revision = asNumber(dictGet(encryptDict, "R")) ?? 0;
185
164
  const declaredBits = asNumber(dictGet(encryptDict, "Length")) ?? DEFAULT_KEY_BITS;
186
165
  const encryptMetadataEntry = dictGet(encryptDict, "EncryptMetadata");
187
166
  const encryptMetadata = encryptMetadataEntry?.kind === "bool" ? encryptMetadataEntry.value : true;
188
- if (version === 5) {
189
- if (revision !== 5 && revision !== 6) throw new PdfEncryptedError(`/V 5 encryption with an unsupported revision /R ${String(revision)}`);
167
+ if (version === V5_HANDLER_VERSION) {
168
+ if (revision !== HARDENED_HASH_SHA256_ONLY_REVISION && revision !== STANDARD_AESV3_REVISION) throw new PdfEncryptedError(`/V 5 encryption with an unsupported revision /R ${String(revision)}`);
190
169
  return {
191
170
  fileKey: computeAesV3FileKey(encryptDict, revision),
192
171
  streamMethod: methodFromCryptFilterName(encryptDict, "StmF"),
@@ -195,10 +174,10 @@ function setUpHandler(encryptDict, fileId) {
195
174
  encryptMetadata
196
175
  };
197
176
  }
198
- if (version !== 1 && version !== 2 && version !== 4) throw new PdfEncryptedError(`unsupported standard security handler version /V ${String(version)}`);
199
- if (revision < 2 || revision > 4) throw new PdfEncryptedError(`unsupported standard security handler revision /R ${String(revision)}`);
200
- const streamMethod = version === 4 ? methodFromCryptFilterName(encryptDict, "StmF") : "rc4";
201
- const stringMethod = version === 4 ? methodFromCryptFilterName(encryptDict, "StrF") : "rc4";
177
+ if (version !== 1 && version !== 2 && version !== V4_HANDLER_VERSION) throw new PdfEncryptedError(`unsupported standard security handler version /V ${String(version)}`);
178
+ if (revision < 2 || revision > LEGACY_MAX_REVISION) throw new PdfEncryptedError(`unsupported standard security handler revision /R ${String(revision)}`);
179
+ const streamMethod = version === V4_HANDLER_VERSION ? methodFromCryptFilterName(encryptDict, "StmF") : "rc4";
180
+ const stringMethod = version === V4_HANDLER_VERSION ? methodFromCryptFilterName(encryptDict, "StrF") : "rc4";
202
181
  const keyBytes = version === 1 ? 5 : version === 2 ? Math.floor(declaredBits / BITS_PER_BYTE) : cryptFilterKeyBytes(encryptDict, declaredBits);
203
182
  if (keyBytes < 5 || keyBytes > MAX_RC4_KEY_BYTES) throw new PdfEncryptedError(`the /Encrypt dictionary declares a ${String(keyBytes * BITS_PER_BYTE)}-bit file key, outside the 40-128 bit range /V ${String(version)} permits`);
204
183
  const fileKey = computeLegacyFileKey(encryptDict, fileId, revision, keyBytes, encryptMetadata);
@@ -213,11 +192,11 @@ function setUpHandler(encryptDict, fileId) {
213
192
  }
214
193
  function objectKey(fileKey, num, gen, method) {
215
194
  const extra = new Uint8Array(OBJECT_KEY_EXTRA_BYTES);
216
- extra[0] = num & 255;
217
- extra[1] = num >>> 8 & 255;
218
- extra[2] = num >>> 16 & 255;
219
- extra[3] = gen & 255;
220
- extra[4] = gen >>> 8 & 255;
195
+ extra[0] = num & BYTE_MASK;
196
+ extra[1] = num >>> BITS_PER_BYTE & BYTE_MASK;
197
+ extra[2] = num >>> UINT32_BYTE_2_SHIFT & BYTE_MASK;
198
+ extra[3] = gen & BYTE_MASK;
199
+ extra[4] = gen >>> BITS_PER_BYTE & BYTE_MASK;
221
200
  return md5(concatBytes(method === "aes" ? [
222
201
  fileKey,
223
202
  extra,