@cj-tech-master/excelts 8.0.0 → 8.1.0

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 (106) hide show
  1. package/README.md +14 -1
  2. package/README_zh.md +6 -0
  3. package/dist/browser/modules/archive/zip/stream.d.ts +4 -0
  4. package/dist/browser/modules/archive/zip/stream.js +53 -0
  5. package/dist/browser/modules/pdf/core/crypto.d.ts +65 -0
  6. package/dist/browser/modules/pdf/core/crypto.js +637 -0
  7. package/dist/browser/modules/pdf/core/encryption.d.ts +23 -20
  8. package/dist/browser/modules/pdf/core/encryption.js +88 -261
  9. package/dist/browser/modules/pdf/core/pdf-writer.d.ts +6 -4
  10. package/dist/browser/modules/pdf/core/pdf-writer.js +19 -10
  11. package/dist/browser/modules/pdf/index.d.ts +23 -2
  12. package/dist/browser/modules/pdf/index.js +21 -3
  13. package/dist/browser/modules/pdf/reader/annotation-extractor.d.ts +63 -0
  14. package/dist/browser/modules/pdf/reader/annotation-extractor.js +155 -0
  15. package/dist/browser/modules/pdf/reader/cmap-parser.d.ts +70 -0
  16. package/dist/browser/modules/pdf/reader/cmap-parser.js +321 -0
  17. package/dist/browser/modules/pdf/reader/content-interpreter.d.ts +57 -0
  18. package/dist/browser/modules/pdf/reader/content-interpreter.js +715 -0
  19. package/dist/browser/modules/pdf/reader/font-decoder.d.ts +58 -0
  20. package/dist/browser/modules/pdf/reader/font-decoder.js +1513 -0
  21. package/dist/browser/modules/pdf/reader/form-extractor.d.ts +48 -0
  22. package/dist/browser/modules/pdf/reader/form-extractor.js +355 -0
  23. package/dist/browser/modules/pdf/reader/image-extractor.d.ts +55 -0
  24. package/dist/browser/modules/pdf/reader/image-extractor.js +220 -0
  25. package/dist/browser/modules/pdf/reader/metadata-reader.d.ts +56 -0
  26. package/dist/browser/modules/pdf/reader/metadata-reader.js +275 -0
  27. package/dist/browser/modules/pdf/reader/pdf-decrypt.d.ts +26 -0
  28. package/dist/browser/modules/pdf/reader/pdf-decrypt.js +443 -0
  29. package/dist/browser/modules/pdf/reader/pdf-document.d.ts +191 -0
  30. package/dist/browser/modules/pdf/reader/pdf-document.js +818 -0
  31. package/dist/browser/modules/pdf/reader/pdf-parser.d.ts +65 -0
  32. package/dist/browser/modules/pdf/reader/pdf-parser.js +285 -0
  33. package/dist/browser/modules/pdf/reader/pdf-reader.d.ts +143 -0
  34. package/dist/browser/modules/pdf/reader/pdf-reader.js +200 -0
  35. package/dist/browser/modules/pdf/reader/pdf-tokenizer.d.ts +101 -0
  36. package/dist/browser/modules/pdf/reader/pdf-tokenizer.js +543 -0
  37. package/dist/browser/modules/pdf/reader/reader-utils.d.ts +15 -0
  38. package/dist/browser/modules/pdf/reader/reader-utils.js +27 -0
  39. package/dist/browser/modules/pdf/reader/stream-filters.d.ts +20 -0
  40. package/dist/browser/modules/pdf/reader/stream-filters.js +456 -0
  41. package/dist/browser/modules/pdf/reader/text-reconstruction.d.ts +44 -0
  42. package/dist/browser/modules/pdf/reader/text-reconstruction.js +463 -0
  43. package/dist/cjs/modules/archive/zip/stream.js +53 -0
  44. package/dist/cjs/modules/pdf/core/crypto.js +649 -0
  45. package/dist/cjs/modules/pdf/core/encryption.js +88 -263
  46. package/dist/cjs/modules/pdf/core/pdf-writer.js +19 -10
  47. package/dist/cjs/modules/pdf/index.js +23 -4
  48. package/dist/cjs/modules/pdf/reader/annotation-extractor.js +158 -0
  49. package/dist/cjs/modules/pdf/reader/cmap-parser.js +326 -0
  50. package/dist/cjs/modules/pdf/reader/content-interpreter.js +718 -0
  51. package/dist/cjs/modules/pdf/reader/font-decoder.js +1518 -0
  52. package/dist/cjs/modules/pdf/reader/form-extractor.js +358 -0
  53. package/dist/cjs/modules/pdf/reader/image-extractor.js +223 -0
  54. package/dist/cjs/modules/pdf/reader/metadata-reader.js +278 -0
  55. package/dist/cjs/modules/pdf/reader/pdf-decrypt.js +447 -0
  56. package/dist/cjs/modules/pdf/reader/pdf-document.js +822 -0
  57. package/dist/cjs/modules/pdf/reader/pdf-parser.js +301 -0
  58. package/dist/cjs/modules/pdf/reader/pdf-reader.js +203 -0
  59. package/dist/cjs/modules/pdf/reader/pdf-tokenizer.js +517 -0
  60. package/dist/cjs/modules/pdf/reader/reader-utils.js +30 -0
  61. package/dist/cjs/modules/pdf/reader/stream-filters.js +459 -0
  62. package/dist/cjs/modules/pdf/reader/text-reconstruction.js +467 -0
  63. package/dist/esm/modules/archive/zip/stream.js +53 -0
  64. package/dist/esm/modules/pdf/core/crypto.js +637 -0
  65. package/dist/esm/modules/pdf/core/encryption.js +88 -261
  66. package/dist/esm/modules/pdf/core/pdf-writer.js +19 -10
  67. package/dist/esm/modules/pdf/index.js +21 -3
  68. package/dist/esm/modules/pdf/reader/annotation-extractor.js +155 -0
  69. package/dist/esm/modules/pdf/reader/cmap-parser.js +321 -0
  70. package/dist/esm/modules/pdf/reader/content-interpreter.js +715 -0
  71. package/dist/esm/modules/pdf/reader/font-decoder.js +1513 -0
  72. package/dist/esm/modules/pdf/reader/form-extractor.js +355 -0
  73. package/dist/esm/modules/pdf/reader/image-extractor.js +220 -0
  74. package/dist/esm/modules/pdf/reader/metadata-reader.js +275 -0
  75. package/dist/esm/modules/pdf/reader/pdf-decrypt.js +443 -0
  76. package/dist/esm/modules/pdf/reader/pdf-document.js +818 -0
  77. package/dist/esm/modules/pdf/reader/pdf-parser.js +285 -0
  78. package/dist/esm/modules/pdf/reader/pdf-reader.js +200 -0
  79. package/dist/esm/modules/pdf/reader/pdf-tokenizer.js +543 -0
  80. package/dist/esm/modules/pdf/reader/reader-utils.js +27 -0
  81. package/dist/esm/modules/pdf/reader/stream-filters.js +456 -0
  82. package/dist/esm/modules/pdf/reader/text-reconstruction.js +463 -0
  83. package/dist/iife/excelts.iife.js +703 -267
  84. package/dist/iife/excelts.iife.js.map +1 -1
  85. package/dist/iife/excelts.iife.min.js +35 -35
  86. package/dist/types/modules/archive/zip/stream.d.ts +4 -0
  87. package/dist/types/modules/pdf/core/crypto.d.ts +65 -0
  88. package/dist/types/modules/pdf/core/encryption.d.ts +23 -20
  89. package/dist/types/modules/pdf/core/pdf-writer.d.ts +6 -4
  90. package/dist/types/modules/pdf/index.d.ts +23 -2
  91. package/dist/types/modules/pdf/reader/annotation-extractor.d.ts +63 -0
  92. package/dist/types/modules/pdf/reader/cmap-parser.d.ts +70 -0
  93. package/dist/types/modules/pdf/reader/content-interpreter.d.ts +57 -0
  94. package/dist/types/modules/pdf/reader/font-decoder.d.ts +58 -0
  95. package/dist/types/modules/pdf/reader/form-extractor.d.ts +48 -0
  96. package/dist/types/modules/pdf/reader/image-extractor.d.ts +55 -0
  97. package/dist/types/modules/pdf/reader/metadata-reader.d.ts +56 -0
  98. package/dist/types/modules/pdf/reader/pdf-decrypt.d.ts +26 -0
  99. package/dist/types/modules/pdf/reader/pdf-document.d.ts +191 -0
  100. package/dist/types/modules/pdf/reader/pdf-parser.d.ts +65 -0
  101. package/dist/types/modules/pdf/reader/pdf-reader.d.ts +143 -0
  102. package/dist/types/modules/pdf/reader/pdf-tokenizer.d.ts +101 -0
  103. package/dist/types/modules/pdf/reader/reader-utils.d.ts +15 -0
  104. package/dist/types/modules/pdf/reader/stream-filters.d.ts +20 -0
  105. package/dist/types/modules/pdf/reader/text-reconstruction.d.ts +44 -0
  106. package/package.json +1 -1
@@ -0,0 +1,649 @@
1
+ "use strict";
2
+ /**
3
+ * Shared cryptographic primitives for PDF encryption/decryption.
4
+ *
5
+ * Zero-dependency, pure JavaScript implementations of:
6
+ * - AES (128/256-bit) CBC encrypt and decrypt
7
+ * - SHA-256
8
+ * - MD5
9
+ * - RC4 (for reading legacy PDFs only)
10
+ *
11
+ * @see FIPS 197 — AES
12
+ * @see FIPS 180-4 — SHA-256
13
+ * @see RFC 1321 — MD5
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.aesCbcEncrypt = aesCbcEncrypt;
17
+ exports.aesCbcDecrypt = aesCbcDecrypt;
18
+ exports.aesCbcDecryptRaw = aesCbcDecryptRaw;
19
+ exports.aesCbcEncryptRaw = aesCbcEncryptRaw;
20
+ exports.aesEcbEncrypt = aesEcbEncrypt;
21
+ exports.sha256 = sha256;
22
+ exports.md5 = md5;
23
+ exports.rc4 = rc4;
24
+ exports.randomBytes = randomBytes;
25
+ exports.concatArrays = concatArrays;
26
+ // =============================================================================
27
+ // AES S-Box & Constants
28
+ // =============================================================================
29
+ /** AES S-Box */
30
+ const SBOX = new Uint8Array([
31
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
32
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
33
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
34
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
35
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
36
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
37
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
38
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
39
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
40
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
41
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
42
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
43
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
44
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
45
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
46
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
47
+ ]);
48
+ /** Inverse S-Box for decryption */
49
+ const INV_SBOX = new Uint8Array(256);
50
+ /* @__PURE__ */ (() => {
51
+ for (let i = 0; i < 256; i++) {
52
+ INV_SBOX[SBOX[i]] = i;
53
+ }
54
+ })();
55
+ /** AES round constants */
56
+ const RCON = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
57
+ // =============================================================================
58
+ // AES Helpers
59
+ // =============================================================================
60
+ /** GF(2^8) multiplication by 2 */
61
+ function gf2(a) {
62
+ return a < 128 ? a << 1 : (a << 1) ^ 0x11b;
63
+ }
64
+ /** GF(2^8) multiplication */
65
+ function gfMul(a, b) {
66
+ let result = 0;
67
+ let aa = a;
68
+ let bb = b;
69
+ while (bb > 0) {
70
+ if (bb & 1) {
71
+ result ^= aa;
72
+ }
73
+ aa = gf2(aa);
74
+ bb >>= 1;
75
+ }
76
+ return result;
77
+ }
78
+ /**
79
+ * AES key expansion. Supports AES-128 (16-byte key) and AES-256 (32-byte key).
80
+ */
81
+ function aesKeyExpansion(key) {
82
+ const nk = key.length / 4;
83
+ const nr = nk + 6;
84
+ const w = [];
85
+ for (let i = 0; i < nk; i++) {
86
+ w.push(new Uint8Array([key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]]));
87
+ }
88
+ for (let i = nk; i < 4 * (nr + 1); i++) {
89
+ const temp = new Uint8Array(w[i - 1]);
90
+ if (i % nk === 0) {
91
+ const t0 = temp[0];
92
+ temp[0] = SBOX[temp[1]] ^ RCON[i / nk - 1];
93
+ temp[1] = SBOX[temp[2]];
94
+ temp[2] = SBOX[temp[3]];
95
+ temp[3] = SBOX[t0];
96
+ }
97
+ else if (nk > 6 && i % nk === 4) {
98
+ temp[0] = SBOX[temp[0]];
99
+ temp[1] = SBOX[temp[1]];
100
+ temp[2] = SBOX[temp[2]];
101
+ temp[3] = SBOX[temp[3]];
102
+ }
103
+ const word = new Uint8Array(4);
104
+ for (let j = 0; j < 4; j++) {
105
+ word[j] = w[i - nk][j] ^ temp[j];
106
+ }
107
+ w.push(word);
108
+ }
109
+ return w;
110
+ }
111
+ // =============================================================================
112
+ // AES Encrypt Block
113
+ // =============================================================================
114
+ /**
115
+ * Encrypt a single AES block (16 bytes).
116
+ * State layout: column-major per FIPS 197 §3.4.
117
+ */
118
+ function aesEncryptBlock(block, roundKeys) {
119
+ const nr = roundKeys.length / 4 - 1;
120
+ const state = new Uint8Array(16);
121
+ state.set(block);
122
+ // Initial AddRoundKey
123
+ for (let c = 0; c < 4; c++) {
124
+ for (let r = 0; r < 4; r++) {
125
+ state[4 * c + r] ^= roundKeys[c][r];
126
+ }
127
+ }
128
+ // Rounds 1 to nr-1
129
+ for (let round = 1; round < nr; round++) {
130
+ // SubBytes
131
+ for (let i = 0; i < 16; i++) {
132
+ state[i] = SBOX[state[i]];
133
+ }
134
+ // ShiftRows: row r shifts left by r
135
+ let tmp;
136
+ // Row 1: shift left by 1
137
+ tmp = state[1];
138
+ state[1] = state[5];
139
+ state[5] = state[9];
140
+ state[9] = state[13];
141
+ state[13] = tmp;
142
+ // Row 2: shift left by 2
143
+ tmp = state[2];
144
+ state[2] = state[10];
145
+ state[10] = tmp;
146
+ tmp = state[6];
147
+ state[6] = state[14];
148
+ state[14] = tmp;
149
+ // Row 3: shift left by 3
150
+ tmp = state[15];
151
+ state[15] = state[11];
152
+ state[11] = state[7];
153
+ state[7] = state[3];
154
+ state[3] = tmp;
155
+ // MixColumns
156
+ for (let c = 0; c < 4; c++) {
157
+ const s0 = state[4 * c];
158
+ const s1 = state[4 * c + 1];
159
+ const s2 = state[4 * c + 2];
160
+ const s3 = state[4 * c + 3];
161
+ state[4 * c] = gf2(s0) ^ gf2(s1) ^ s1 ^ s2 ^ s3;
162
+ state[4 * c + 1] = s0 ^ gf2(s1) ^ gf2(s2) ^ s2 ^ s3;
163
+ state[4 * c + 2] = s0 ^ s1 ^ gf2(s2) ^ gf2(s3) ^ s3;
164
+ state[4 * c + 3] = gf2(s0) ^ s0 ^ s1 ^ s2 ^ gf2(s3);
165
+ }
166
+ // AddRoundKey
167
+ const keyOffset = round * 4;
168
+ for (let c = 0; c < 4; c++) {
169
+ for (let r = 0; r < 4; r++) {
170
+ state[4 * c + r] ^= roundKeys[keyOffset + c][r];
171
+ }
172
+ }
173
+ }
174
+ // Final round (no MixColumns)
175
+ for (let i = 0; i < 16; i++) {
176
+ state[i] = SBOX[state[i]];
177
+ }
178
+ let tmp;
179
+ tmp = state[1];
180
+ state[1] = state[5];
181
+ state[5] = state[9];
182
+ state[9] = state[13];
183
+ state[13] = tmp;
184
+ tmp = state[2];
185
+ state[2] = state[10];
186
+ state[10] = tmp;
187
+ tmp = state[6];
188
+ state[6] = state[14];
189
+ state[14] = tmp;
190
+ tmp = state[15];
191
+ state[15] = state[11];
192
+ state[11] = state[7];
193
+ state[7] = state[3];
194
+ state[3] = tmp;
195
+ for (let c = 0; c < 4; c++) {
196
+ for (let r = 0; r < 4; r++) {
197
+ state[4 * c + r] ^= roundKeys[nr * 4 + c][r];
198
+ }
199
+ }
200
+ return state;
201
+ }
202
+ // =============================================================================
203
+ // AES Decrypt Block
204
+ // =============================================================================
205
+ /**
206
+ * Decrypt a single AES block (16 bytes).
207
+ */
208
+ function aesDecryptBlock(block, roundKeys) {
209
+ const nr = roundKeys.length / 4 - 1;
210
+ const state = new Uint8Array(16);
211
+ state.set(block);
212
+ // Initial AddRoundKey
213
+ for (let c = 0; c < 4; c++) {
214
+ for (let r = 0; r < 4; r++) {
215
+ state[4 * c + r] ^= roundKeys[nr * 4 + c][r];
216
+ }
217
+ }
218
+ // Rounds nr-1 down to 1
219
+ for (let round = nr - 1; round >= 1; round--) {
220
+ // InvShiftRows
221
+ let tmp;
222
+ tmp = state[13];
223
+ state[13] = state[9];
224
+ state[9] = state[5];
225
+ state[5] = state[1];
226
+ state[1] = tmp;
227
+ tmp = state[2];
228
+ state[2] = state[10];
229
+ state[10] = tmp;
230
+ tmp = state[6];
231
+ state[6] = state[14];
232
+ state[14] = tmp;
233
+ tmp = state[3];
234
+ state[3] = state[7];
235
+ state[7] = state[11];
236
+ state[11] = state[15];
237
+ state[15] = tmp;
238
+ // InvSubBytes
239
+ for (let i = 0; i < 16; i++) {
240
+ state[i] = INV_SBOX[state[i]];
241
+ }
242
+ // AddRoundKey
243
+ const keyOffset = round * 4;
244
+ for (let c = 0; c < 4; c++) {
245
+ for (let r = 0; r < 4; r++) {
246
+ state[4 * c + r] ^= roundKeys[keyOffset + c][r];
247
+ }
248
+ }
249
+ // InvMixColumns
250
+ for (let c = 0; c < 4; c++) {
251
+ const s0 = state[4 * c];
252
+ const s1 = state[4 * c + 1];
253
+ const s2 = state[4 * c + 2];
254
+ const s3 = state[4 * c + 3];
255
+ state[4 * c] = gfMul(s0, 14) ^ gfMul(s1, 11) ^ gfMul(s2, 13) ^ gfMul(s3, 9);
256
+ state[4 * c + 1] = gfMul(s0, 9) ^ gfMul(s1, 14) ^ gfMul(s2, 11) ^ gfMul(s3, 13);
257
+ state[4 * c + 2] = gfMul(s0, 13) ^ gfMul(s1, 9) ^ gfMul(s2, 14) ^ gfMul(s3, 11);
258
+ state[4 * c + 3] = gfMul(s0, 11) ^ gfMul(s1, 13) ^ gfMul(s2, 9) ^ gfMul(s3, 14);
259
+ }
260
+ }
261
+ // Final round (no InvMixColumns)
262
+ let tmp2;
263
+ tmp2 = state[13];
264
+ state[13] = state[9];
265
+ state[9] = state[5];
266
+ state[5] = state[1];
267
+ state[1] = tmp2;
268
+ tmp2 = state[2];
269
+ state[2] = state[10];
270
+ state[10] = tmp2;
271
+ tmp2 = state[6];
272
+ state[6] = state[14];
273
+ state[14] = tmp2;
274
+ tmp2 = state[3];
275
+ state[3] = state[7];
276
+ state[7] = state[11];
277
+ state[11] = state[15];
278
+ state[15] = tmp2;
279
+ for (let i = 0; i < 16; i++) {
280
+ state[i] = INV_SBOX[state[i]];
281
+ }
282
+ for (let c = 0; c < 4; c++) {
283
+ for (let r = 0; r < 4; r++) {
284
+ state[4 * c + r] ^= roundKeys[c][r];
285
+ }
286
+ }
287
+ return state;
288
+ }
289
+ // =============================================================================
290
+ // AES-CBC Public API
291
+ // =============================================================================
292
+ /**
293
+ * AES-CBC encryption with PKCS#7 padding.
294
+ * Supports AES-128 (16-byte key) and AES-256 (32-byte key).
295
+ */
296
+ function aesCbcEncrypt(plaintext, key, iv) {
297
+ // PKCS#7 padding
298
+ const padLen = 16 - (plaintext.length % 16);
299
+ const padded = new Uint8Array(plaintext.length + padLen);
300
+ padded.set(plaintext);
301
+ for (let i = plaintext.length; i < padded.length; i++) {
302
+ padded[i] = padLen;
303
+ }
304
+ const roundKeys = aesKeyExpansion(key);
305
+ const numBlocks = padded.length / 16;
306
+ const output = new Uint8Array(padded.length);
307
+ let prevBlock = iv;
308
+ for (let b = 0; b < numBlocks; b++) {
309
+ // XOR plaintext block with previous ciphertext (or IV)
310
+ const block = new Uint8Array(16);
311
+ for (let i = 0; i < 16; i++) {
312
+ block[i] = padded[b * 16 + i] ^ prevBlock[i];
313
+ }
314
+ const encrypted = aesEncryptBlock(block, roundKeys);
315
+ output.set(encrypted, b * 16);
316
+ prevBlock = encrypted;
317
+ }
318
+ return output;
319
+ }
320
+ /**
321
+ * AES-CBC decryption with PKCS#7 padding removal.
322
+ * Supports AES-128 (16-byte key) and AES-256 (32-byte key).
323
+ */
324
+ function aesCbcDecrypt(ciphertext, key, iv) {
325
+ const roundKeys = aesKeyExpansion(key);
326
+ const numBlocks = ciphertext.length / 16;
327
+ const output = new Uint8Array(ciphertext.length);
328
+ let prevBlock = iv;
329
+ for (let b = 0; b < numBlocks; b++) {
330
+ const block = ciphertext.subarray(b * 16, (b + 1) * 16);
331
+ const decrypted = aesDecryptBlock(block, roundKeys);
332
+ for (let i = 0; i < 16; i++) {
333
+ output[b * 16 + i] = decrypted[i] ^ prevBlock[i];
334
+ }
335
+ prevBlock = block;
336
+ }
337
+ // Remove PKCS#7 padding
338
+ if (output.length > 0) {
339
+ const padLen = output[output.length - 1];
340
+ if (padLen > 0 && padLen <= 16) {
341
+ let validPadding = true;
342
+ for (let i = 0; i < padLen; i++) {
343
+ if (output[output.length - 1 - i] !== padLen) {
344
+ validPadding = false;
345
+ break;
346
+ }
347
+ }
348
+ if (validPadding) {
349
+ return output.subarray(0, output.length - padLen);
350
+ }
351
+ }
352
+ }
353
+ return output;
354
+ }
355
+ /**
356
+ * AES-CBC decryption WITHOUT PKCS#7 padding removal.
357
+ * Used for key derivation in V=5 where the output length is known.
358
+ */
359
+ function aesCbcDecryptRaw(ciphertext, key, iv) {
360
+ const roundKeys = aesKeyExpansion(key);
361
+ const numBlocks = ciphertext.length / 16;
362
+ const output = new Uint8Array(ciphertext.length);
363
+ let prevBlock = iv;
364
+ for (let b = 0; b < numBlocks; b++) {
365
+ const block = ciphertext.subarray(b * 16, (b + 1) * 16);
366
+ const decrypted = aesDecryptBlock(block, roundKeys);
367
+ for (let i = 0; i < 16; i++) {
368
+ output[b * 16 + i] = decrypted[i] ^ prevBlock[i];
369
+ }
370
+ prevBlock = block;
371
+ }
372
+ return output;
373
+ }
374
+ /**
375
+ * AES-CBC encryption WITHOUT PKCS#7 padding.
376
+ * Used when the plaintext is already block-aligned (e.g., encrypting
377
+ * the 32-byte file encryption key in V=5).
378
+ *
379
+ * @throws if plaintext length is not a multiple of 16.
380
+ */
381
+ function aesCbcEncryptRaw(plaintext, key, iv) {
382
+ if (plaintext.length % 16 !== 0) {
383
+ throw new Error("aesCbcEncryptRaw: plaintext length must be a multiple of 16");
384
+ }
385
+ const roundKeys = aesKeyExpansion(key);
386
+ const numBlocks = plaintext.length / 16;
387
+ const output = new Uint8Array(plaintext.length);
388
+ let prevBlock = iv;
389
+ for (let b = 0; b < numBlocks; b++) {
390
+ const block = new Uint8Array(16);
391
+ for (let i = 0; i < 16; i++) {
392
+ block[i] = plaintext[b * 16 + i] ^ prevBlock[i];
393
+ }
394
+ const encrypted = aesEncryptBlock(block, roundKeys);
395
+ output.set(encrypted, b * 16);
396
+ prevBlock = encrypted;
397
+ }
398
+ return output;
399
+ }
400
+ /**
401
+ * AES-ECB encryption of a single 16-byte block (no padding, no IV).
402
+ * Used for the /Perms value in V=5 encryption.
403
+ */
404
+ function aesEcbEncrypt(block, key) {
405
+ const roundKeys = aesKeyExpansion(key);
406
+ return aesEncryptBlock(block, roundKeys);
407
+ }
408
+ // =============================================================================
409
+ // SHA-256
410
+ // =============================================================================
411
+ /** SHA-256 initial hash values */
412
+ const SHA256_H = new Uint32Array([
413
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
414
+ ]);
415
+ /** SHA-256 round constants */
416
+ const SHA256_K = new Uint32Array([
417
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
418
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
419
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
420
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
421
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
422
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
423
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
424
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
425
+ ]);
426
+ function rotr32(x, n) {
427
+ return ((x >>> n) | (x << (32 - n))) >>> 0;
428
+ }
429
+ /**
430
+ * SHA-256 hash function.
431
+ * @returns 32-byte digest
432
+ */
433
+ function sha256(input) {
434
+ const msgLen = input.length;
435
+ const paddedLen = Math.ceil((msgLen + 9) / 64) * 64;
436
+ const padded = new Uint8Array(paddedLen);
437
+ padded.set(input);
438
+ padded[msgLen] = 0x80;
439
+ const bitLen = msgLen * 8;
440
+ const view = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);
441
+ view.setUint32(paddedLen - 8, 0, false);
442
+ view.setUint32(paddedLen - 4, bitLen, false);
443
+ let h0 = SHA256_H[0];
444
+ let h1 = SHA256_H[1];
445
+ let h2 = SHA256_H[2];
446
+ let h3 = SHA256_H[3];
447
+ let h4 = SHA256_H[4];
448
+ let h5 = SHA256_H[5];
449
+ let h6 = SHA256_H[6];
450
+ let h7 = SHA256_H[7];
451
+ const w = new Uint32Array(64);
452
+ for (let offset = 0; offset < paddedLen; offset += 64) {
453
+ for (let i = 0; i < 16; i++) {
454
+ w[i] = view.getUint32(offset + i * 4, false);
455
+ }
456
+ for (let i = 16; i < 64; i++) {
457
+ const s0 = rotr32(w[i - 15], 7) ^ rotr32(w[i - 15], 18) ^ (w[i - 15] >>> 3);
458
+ const s1 = rotr32(w[i - 2], 17) ^ rotr32(w[i - 2], 19) ^ (w[i - 2] >>> 10);
459
+ w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
460
+ }
461
+ let a = h0;
462
+ let b = h1;
463
+ let c = h2;
464
+ let d = h3;
465
+ let e = h4;
466
+ let f = h5;
467
+ let g = h6;
468
+ let h = h7;
469
+ for (let i = 0; i < 64; i++) {
470
+ const S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);
471
+ const ch = (e & f) ^ (~e & g);
472
+ const temp1 = (h + S1 + ch + SHA256_K[i] + w[i]) >>> 0;
473
+ const S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);
474
+ const maj = (a & b) ^ (a & c) ^ (b & c);
475
+ const temp2 = (S0 + maj) >>> 0;
476
+ h = g;
477
+ g = f;
478
+ f = e;
479
+ e = (d + temp1) >>> 0;
480
+ d = c;
481
+ c = b;
482
+ b = a;
483
+ a = (temp1 + temp2) >>> 0;
484
+ }
485
+ h0 = (h0 + a) >>> 0;
486
+ h1 = (h1 + b) >>> 0;
487
+ h2 = (h2 + c) >>> 0;
488
+ h3 = (h3 + d) >>> 0;
489
+ h4 = (h4 + e) >>> 0;
490
+ h5 = (h5 + f) >>> 0;
491
+ h6 = (h6 + g) >>> 0;
492
+ h7 = (h7 + h) >>> 0;
493
+ }
494
+ const result = new Uint8Array(32);
495
+ const resultView = new DataView(result.buffer);
496
+ resultView.setUint32(0, h0, false);
497
+ resultView.setUint32(4, h1, false);
498
+ resultView.setUint32(8, h2, false);
499
+ resultView.setUint32(12, h3, false);
500
+ resultView.setUint32(16, h4, false);
501
+ resultView.setUint32(20, h5, false);
502
+ resultView.setUint32(24, h6, false);
503
+ resultView.setUint32(28, h7, false);
504
+ return result;
505
+ }
506
+ // =============================================================================
507
+ // MD5 (for legacy PDF reading)
508
+ // =============================================================================
509
+ function rotl(x, n) {
510
+ return ((x << n) | (x >>> (32 - n))) >>> 0;
511
+ }
512
+ const MD5_S = [
513
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14,
514
+ 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6,
515
+ 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
516
+ ];
517
+ const MD5_K = new Uint32Array([
518
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
519
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
520
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
521
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
522
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
523
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
524
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
525
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
526
+ ]);
527
+ /**
528
+ * MD5 hash function (RFC 1321).
529
+ * @returns 16-byte digest
530
+ */
531
+ function md5(input) {
532
+ const msgLen = input.length;
533
+ const bitLen = msgLen * 8;
534
+ const padLen = ((56 - ((msgLen + 1) % 64) + 64) % 64) + 1;
535
+ const padded = new Uint8Array(msgLen + padLen + 8);
536
+ padded.set(input);
537
+ padded[msgLen] = 0x80;
538
+ const view = new DataView(padded.buffer);
539
+ view.setUint32(padded.length - 8, bitLen >>> 0, true);
540
+ view.setUint32(padded.length - 4, 0, true);
541
+ let a0 = 0x67452301;
542
+ let b0 = 0xefcdab89;
543
+ let c0 = 0x98badcfe;
544
+ let d0 = 0x10325476;
545
+ for (let i = 0; i < padded.length; i += 64) {
546
+ const M = new Uint32Array(16);
547
+ for (let j = 0; j < 16; j++) {
548
+ M[j] = view.getUint32(i + j * 4, true);
549
+ }
550
+ let A = a0;
551
+ let B = b0;
552
+ let C = c0;
553
+ let D = d0;
554
+ for (let j = 0; j < 64; j++) {
555
+ let F;
556
+ let g;
557
+ if (j < 16) {
558
+ F = (B & C) | (~B & D);
559
+ g = j;
560
+ }
561
+ else if (j < 32) {
562
+ F = (D & B) | (~D & C);
563
+ g = (5 * j + 1) % 16;
564
+ }
565
+ else if (j < 48) {
566
+ F = B ^ C ^ D;
567
+ g = (3 * j + 5) % 16;
568
+ }
569
+ else {
570
+ F = C ^ (B | ~D);
571
+ g = (7 * j) % 16;
572
+ }
573
+ F = (F + A + MD5_K[j] + M[g]) >>> 0;
574
+ A = D;
575
+ D = C;
576
+ C = B;
577
+ B = (B + rotl(F, MD5_S[j])) >>> 0;
578
+ }
579
+ a0 = (a0 + A) >>> 0;
580
+ b0 = (b0 + B) >>> 0;
581
+ c0 = (c0 + C) >>> 0;
582
+ d0 = (d0 + D) >>> 0;
583
+ }
584
+ const digest = new Uint8Array(16);
585
+ const dv = new DataView(digest.buffer);
586
+ dv.setUint32(0, a0, true);
587
+ dv.setUint32(4, b0, true);
588
+ dv.setUint32(8, c0, true);
589
+ dv.setUint32(12, d0, true);
590
+ return digest;
591
+ }
592
+ // =============================================================================
593
+ // RC4 (for legacy PDF reading only)
594
+ // =============================================================================
595
+ /**
596
+ * RC4 stream cipher.
597
+ * @deprecated Only used for reading legacy encrypted PDFs. Writer uses AES-256.
598
+ */
599
+ function rc4(key, data) {
600
+ const s = new Uint8Array(256);
601
+ for (let i = 0; i < 256; i++) {
602
+ s[i] = i;
603
+ }
604
+ let j = 0;
605
+ for (let i = 0; i < 256; i++) {
606
+ j = (j + s[i] + key[i % key.length]) & 0xff;
607
+ [s[i], s[j]] = [s[j], s[i]];
608
+ }
609
+ const result = new Uint8Array(data.length);
610
+ let ii = 0;
611
+ let jj = 0;
612
+ for (let k = 0; k < data.length; k++) {
613
+ ii = (ii + 1) & 0xff;
614
+ jj = (jj + s[ii]) & 0xff;
615
+ [s[ii], s[jj]] = [s[jj], s[ii]];
616
+ result[k] = data[k] ^ s[(s[ii] + s[jj]) & 0xff];
617
+ }
618
+ return result;
619
+ }
620
+ // =============================================================================
621
+ // Random bytes (for IV generation)
622
+ // =============================================================================
623
+ /**
624
+ * Generate pseudo-random bytes.
625
+ * Uses Math.random — adequate for PDF IVs but not cryptographically secure.
626
+ */
627
+ function randomBytes(length) {
628
+ const bytes = new Uint8Array(length);
629
+ for (let i = 0; i < length; i++) {
630
+ bytes[i] = (Math.random() * 256) | 0;
631
+ }
632
+ return bytes;
633
+ }
634
+ /**
635
+ * Concatenate multiple Uint8Arrays.
636
+ */
637
+ function concatArrays(...arrays) {
638
+ let totalLen = 0;
639
+ for (const arr of arrays) {
640
+ totalLen += arr.length;
641
+ }
642
+ const result = new Uint8Array(totalLen);
643
+ let offset = 0;
644
+ for (const arr of arrays) {
645
+ result.set(arr, offset);
646
+ offset += arr.length;
647
+ }
648
+ return result;
649
+ }