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