@cj-tech-master/excelts 9.1.0 → 9.2.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 (147) hide show
  1. package/README.md +16 -1
  2. package/dist/browser/modules/archive/compression/crc32.js +1 -1
  3. package/dist/browser/modules/archive/crypto/aes.d.ts +0 -8
  4. package/dist/browser/modules/archive/crypto/aes.js +1 -20
  5. package/dist/browser/modules/archive/crypto/index.d.ts +2 -1
  6. package/dist/browser/modules/archive/crypto/index.js +3 -1
  7. package/dist/browser/modules/csv/parse/row-processor.d.ts +1 -1
  8. package/dist/browser/modules/csv/worker/worker-script.generated.js +1 -1
  9. package/dist/browser/modules/excel/utils/cell-matrix.js +1 -0
  10. package/dist/browser/modules/excel/utils/encryptor.browser.d.ts +4 -5
  11. package/dist/browser/modules/excel/utils/encryptor.browser.js +7 -12
  12. package/dist/browser/modules/excel/utils/encryptor.d.ts +1 -1
  13. package/dist/browser/modules/excel/utils/encryptor.js +4 -7
  14. package/dist/browser/modules/pdf/builder/document-builder.d.ts +517 -0
  15. package/dist/browser/modules/pdf/builder/document-builder.js +1493 -0
  16. package/dist/browser/modules/pdf/builder/form-appearance.d.ts +56 -0
  17. package/dist/browser/modules/pdf/builder/form-appearance.js +140 -0
  18. package/dist/browser/modules/pdf/builder/image-utils.d.ts +39 -0
  19. package/dist/browser/modules/pdf/builder/image-utils.js +129 -0
  20. package/dist/browser/modules/pdf/builder/pdf-editor.d.ts +230 -0
  21. package/dist/browser/modules/pdf/builder/pdf-editor.js +1574 -0
  22. package/dist/browser/modules/pdf/builder/resource-merger.d.ts +41 -0
  23. package/dist/browser/modules/pdf/builder/resource-merger.js +258 -0
  24. package/dist/browser/modules/pdf/core/digital-signature.d.ts +109 -0
  25. package/dist/browser/modules/pdf/core/digital-signature.js +659 -0
  26. package/dist/browser/modules/pdf/core/encryption.js +8 -7
  27. package/dist/browser/modules/pdf/core/pdf-object.d.ts +11 -0
  28. package/dist/browser/modules/pdf/core/pdf-object.js +38 -0
  29. package/dist/browser/modules/pdf/core/pdf-stream.d.ts +32 -0
  30. package/dist/browser/modules/pdf/core/pdf-stream.js +66 -0
  31. package/dist/browser/modules/pdf/core/pdf-writer.d.ts +55 -1
  32. package/dist/browser/modules/pdf/core/pdf-writer.js +271 -6
  33. package/dist/browser/modules/pdf/core/pdfa.d.ts +62 -0
  34. package/dist/browser/modules/pdf/core/pdfa.js +261 -0
  35. package/dist/browser/modules/pdf/index.d.ts +11 -0
  36. package/dist/browser/modules/pdf/index.js +9 -0
  37. package/dist/browser/modules/pdf/reader/bookmark-extractor.d.ts +35 -0
  38. package/dist/browser/modules/pdf/reader/bookmark-extractor.js +324 -0
  39. package/dist/browser/modules/pdf/reader/pdf-decrypt.js +6 -5
  40. package/dist/browser/modules/pdf/reader/pdf-reader.d.ts +17 -0
  41. package/dist/browser/modules/pdf/reader/pdf-reader.js +26 -2
  42. package/dist/browser/modules/pdf/reader/table-extractor.d.ts +69 -0
  43. package/dist/browser/modules/pdf/reader/table-extractor.js +365 -0
  44. package/dist/browser/modules/pdf/render/layout-engine.d.ts +21 -1
  45. package/dist/browser/modules/pdf/render/layout-engine.js +112 -5
  46. package/dist/browser/modules/pdf/render/page-renderer.d.ts +2 -9
  47. package/dist/browser/modules/pdf/render/page-renderer.js +62 -103
  48. package/dist/browser/modules/pdf/render/pdf-exporter.js +2 -61
  49. package/dist/browser/modules/pdf/render/style-converter.d.ts +4 -0
  50. package/dist/browser/modules/pdf/render/style-converter.js +1 -1
  51. package/dist/browser/modules/pdf/types.d.ts +14 -1
  52. package/dist/browser/modules/stream/browser/readable.js +8 -2
  53. package/dist/browser/utils/crypto.browser.d.ts +64 -0
  54. package/dist/browser/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +91 -101
  55. package/dist/browser/utils/crypto.d.ts +97 -0
  56. package/dist/browser/utils/crypto.js +209 -0
  57. package/dist/cjs/modules/archive/compression/crc32.js +1 -1
  58. package/dist/cjs/modules/archive/crypto/aes.js +2 -23
  59. package/dist/cjs/modules/archive/crypto/index.js +3 -1
  60. package/dist/cjs/modules/csv/worker/worker-script.generated.js +1 -1
  61. package/dist/cjs/modules/excel/utils/cell-matrix.js +1 -0
  62. package/dist/cjs/modules/excel/utils/encryptor.browser.js +7 -12
  63. package/dist/cjs/modules/excel/utils/encryptor.js +4 -10
  64. package/dist/cjs/modules/pdf/builder/document-builder.js +1532 -0
  65. package/dist/cjs/modules/pdf/builder/form-appearance.js +145 -0
  66. package/dist/cjs/modules/pdf/builder/image-utils.js +135 -0
  67. package/dist/cjs/modules/pdf/builder/pdf-editor.js +1612 -0
  68. package/dist/cjs/modules/pdf/builder/resource-merger.js +263 -0
  69. package/dist/cjs/modules/pdf/core/digital-signature.js +667 -0
  70. package/dist/cjs/modules/pdf/core/encryption.js +8 -7
  71. package/dist/cjs/modules/pdf/core/pdf-object.js +38 -0
  72. package/dist/cjs/modules/pdf/core/pdf-stream.js +66 -0
  73. package/dist/cjs/modules/pdf/core/pdf-writer.js +272 -6
  74. package/dist/cjs/modules/pdf/core/pdfa.js +266 -0
  75. package/dist/cjs/modules/pdf/index.js +19 -1
  76. package/dist/cjs/modules/pdf/reader/bookmark-extractor.js +327 -0
  77. package/dist/cjs/modules/pdf/reader/pdf-decrypt.js +6 -5
  78. package/dist/cjs/modules/pdf/reader/pdf-reader.js +26 -2
  79. package/dist/cjs/modules/pdf/reader/table-extractor.js +368 -0
  80. package/dist/cjs/modules/pdf/render/layout-engine.js +113 -4
  81. package/dist/cjs/modules/pdf/render/page-renderer.js +63 -105
  82. package/dist/cjs/modules/pdf/render/pdf-exporter.js +3 -62
  83. package/dist/cjs/modules/pdf/render/style-converter.js +1 -0
  84. package/dist/cjs/modules/stream/browser/readable.js +8 -2
  85. package/dist/cjs/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +95 -102
  86. package/dist/cjs/utils/crypto.js +228 -0
  87. package/dist/esm/modules/archive/compression/crc32.js +1 -1
  88. package/dist/esm/modules/archive/crypto/aes.js +1 -20
  89. package/dist/esm/modules/archive/crypto/index.js +3 -1
  90. package/dist/esm/modules/csv/worker/worker-script.generated.js +1 -1
  91. package/dist/esm/modules/excel/utils/cell-matrix.js +1 -0
  92. package/dist/esm/modules/excel/utils/encryptor.browser.js +7 -12
  93. package/dist/esm/modules/excel/utils/encryptor.js +4 -7
  94. package/dist/esm/modules/pdf/builder/document-builder.js +1493 -0
  95. package/dist/esm/modules/pdf/builder/form-appearance.js +140 -0
  96. package/dist/esm/modules/pdf/builder/image-utils.js +129 -0
  97. package/dist/esm/modules/pdf/builder/pdf-editor.js +1574 -0
  98. package/dist/esm/modules/pdf/builder/resource-merger.js +258 -0
  99. package/dist/esm/modules/pdf/core/digital-signature.js +659 -0
  100. package/dist/esm/modules/pdf/core/encryption.js +8 -7
  101. package/dist/esm/modules/pdf/core/pdf-object.js +38 -0
  102. package/dist/esm/modules/pdf/core/pdf-stream.js +66 -0
  103. package/dist/esm/modules/pdf/core/pdf-writer.js +271 -6
  104. package/dist/esm/modules/pdf/core/pdfa.js +261 -0
  105. package/dist/esm/modules/pdf/index.js +9 -0
  106. package/dist/esm/modules/pdf/reader/bookmark-extractor.js +324 -0
  107. package/dist/esm/modules/pdf/reader/pdf-decrypt.js +6 -5
  108. package/dist/esm/modules/pdf/reader/pdf-reader.js +26 -2
  109. package/dist/esm/modules/pdf/reader/table-extractor.js +365 -0
  110. package/dist/esm/modules/pdf/render/layout-engine.js +112 -5
  111. package/dist/esm/modules/pdf/render/page-renderer.js +62 -103
  112. package/dist/esm/modules/pdf/render/pdf-exporter.js +2 -61
  113. package/dist/esm/modules/pdf/render/style-converter.js +1 -1
  114. package/dist/esm/modules/stream/browser/readable.js +8 -2
  115. package/dist/esm/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +91 -101
  116. package/dist/esm/utils/crypto.js +209 -0
  117. package/dist/iife/excelts.iife.js +1248 -1074
  118. package/dist/iife/excelts.iife.js.map +1 -1
  119. package/dist/iife/excelts.iife.min.js +53 -54
  120. package/dist/types/modules/archive/crypto/aes.d.ts +0 -8
  121. package/dist/types/modules/archive/crypto/index.d.ts +2 -1
  122. package/dist/types/modules/csv/parse/row-processor.d.ts +1 -1
  123. package/dist/types/modules/excel/utils/encryptor.browser.d.ts +4 -5
  124. package/dist/types/modules/excel/utils/encryptor.d.ts +1 -1
  125. package/dist/types/modules/pdf/builder/document-builder.d.ts +517 -0
  126. package/dist/types/modules/pdf/builder/form-appearance.d.ts +56 -0
  127. package/dist/types/modules/pdf/builder/image-utils.d.ts +39 -0
  128. package/dist/types/modules/pdf/builder/pdf-editor.d.ts +230 -0
  129. package/dist/types/modules/pdf/builder/resource-merger.d.ts +41 -0
  130. package/dist/types/modules/pdf/core/digital-signature.d.ts +109 -0
  131. package/dist/types/modules/pdf/core/pdf-object.d.ts +11 -0
  132. package/dist/types/modules/pdf/core/pdf-stream.d.ts +32 -0
  133. package/dist/types/modules/pdf/core/pdf-writer.d.ts +55 -1
  134. package/dist/types/modules/pdf/core/pdfa.d.ts +62 -0
  135. package/dist/types/modules/pdf/index.d.ts +11 -0
  136. package/dist/types/modules/pdf/reader/bookmark-extractor.d.ts +35 -0
  137. package/dist/types/modules/pdf/reader/pdf-reader.d.ts +17 -0
  138. package/dist/types/modules/pdf/reader/table-extractor.d.ts +69 -0
  139. package/dist/types/modules/pdf/render/layout-engine.d.ts +21 -1
  140. package/dist/types/modules/pdf/render/page-renderer.d.ts +2 -9
  141. package/dist/types/modules/pdf/render/style-converter.d.ts +4 -0
  142. package/dist/types/modules/pdf/types.d.ts +14 -1
  143. package/dist/types/utils/crypto.browser.d.ts +64 -0
  144. package/dist/types/utils/crypto.d.ts +97 -0
  145. package/package.json +110 -111
  146. package/dist/browser/modules/pdf/core/crypto.d.ts +0 -65
  147. package/dist/types/modules/pdf/core/crypto.d.ts +0 -65
@@ -1,16 +1,15 @@
1
1
  "use strict";
2
2
  /**
3
- * Shared cryptographic primitives for PDF encryption/decryption.
3
+ * Cryptographic primitives Browser version.
4
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)
5
+ * Uses pure JavaScript for synchronous operations (SHA-256, MD5, AES-CBC, RC4)
6
+ * since Web Crypto API is async-only and cannot replace synchronous call sites.
10
7
  *
11
- * @see FIPS 197 AES
12
- * @see FIPS 180-4SHA-256
13
- * @see RFC 1321MD5
8
+ * Uses Web Crypto API for:
9
+ * - `randomBytes` (crypto.getRandomValuestruly random)
10
+ * - `rsaVerify` / `rsaSign` (SubtleCrypto hardware-accelerated)
11
+ *
12
+ * Exports the same API as `crypto.ts` (Node.js version).
14
13
  */
15
14
  Object.defineProperty(exports, "__esModule", { value: true });
16
15
  exports.aesCbcEncrypt = aesCbcEncrypt;
@@ -22,11 +21,13 @@ exports.sha256 = sha256;
22
21
  exports.md5 = md5;
23
22
  exports.rc4 = rc4;
24
23
  exports.randomBytes = randomBytes;
25
- exports.concatArrays = concatArrays;
24
+ exports.hashAsync = hashAsync;
25
+ exports.hash = hash;
26
+ exports.rsaVerify = rsaVerify;
27
+ exports.rsaSign = rsaSign;
26
28
  // =============================================================================
27
29
  // AES S-Box & Constants
28
30
  // =============================================================================
29
- /** AES S-Box */
30
31
  const SBOX = new Uint8Array([
31
32
  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
32
33
  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
@@ -45,23 +46,19 @@ const SBOX = new Uint8Array([
45
46
  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
46
47
  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
47
48
  ]);
48
- /** Inverse S-Box for decryption */
49
49
  const INV_SBOX = new Uint8Array(256);
50
50
  /* @__PURE__ */ (() => {
51
51
  for (let i = 0; i < 256; i++) {
52
52
  INV_SBOX[SBOX[i]] = i;
53
53
  }
54
54
  })();
55
- /** AES round constants */
56
55
  const RCON = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
57
56
  // =============================================================================
58
57
  // AES Helpers
59
58
  // =============================================================================
60
- /** GF(2^8) multiplication by 2 */
61
59
  function gf2(a) {
62
60
  return a < 128 ? a << 1 : (a << 1) ^ 0x11b;
63
61
  }
64
- /** GF(2^8) multiplication */
65
62
  function gfMul(a, b) {
66
63
  let result = 0;
67
64
  let aa = a;
@@ -75,9 +72,6 @@ function gfMul(a, b) {
75
72
  }
76
73
  return result;
77
74
  }
78
- /**
79
- * AES key expansion. Supports AES-128 (16-byte key) and AES-256 (32-byte key).
80
- */
81
75
  function aesKeyExpansion(key) {
82
76
  const nk = key.length / 4;
83
77
  const nr = nk + 6;
@@ -109,50 +103,38 @@ function aesKeyExpansion(key) {
109
103
  return w;
110
104
  }
111
105
  // =============================================================================
112
- // AES Encrypt Block
106
+ // AES Block Encrypt / Decrypt
113
107
  // =============================================================================
114
- /**
115
- * Encrypt a single AES block (16 bytes).
116
- * State layout: column-major per FIPS 197 §3.4.
117
- */
118
108
  function aesEncryptBlock(block, roundKeys) {
119
109
  const nr = roundKeys.length / 4 - 1;
120
110
  const state = new Uint8Array(16);
121
111
  state.set(block);
122
- // Initial AddRoundKey
123
112
  for (let c = 0; c < 4; c++) {
124
113
  for (let r = 0; r < 4; r++) {
125
114
  state[4 * c + r] ^= roundKeys[c][r];
126
115
  }
127
116
  }
128
- // Rounds 1 to nr-1
129
117
  for (let round = 1; round < nr; round++) {
130
- // SubBytes
131
118
  for (let i = 0; i < 16; i++) {
132
119
  state[i] = SBOX[state[i]];
133
120
  }
134
- // ShiftRows: row r shifts left by r
135
121
  let tmp;
136
- // Row 1: shift left by 1
137
122
  tmp = state[1];
138
123
  state[1] = state[5];
139
124
  state[5] = state[9];
140
125
  state[9] = state[13];
141
126
  state[13] = tmp;
142
- // Row 2: shift left by 2
143
127
  tmp = state[2];
144
128
  state[2] = state[10];
145
129
  state[10] = tmp;
146
130
  tmp = state[6];
147
131
  state[6] = state[14];
148
132
  state[14] = tmp;
149
- // Row 3: shift left by 3
150
133
  tmp = state[15];
151
134
  state[15] = state[11];
152
135
  state[11] = state[7];
153
136
  state[7] = state[3];
154
137
  state[3] = tmp;
155
- // MixColumns
156
138
  for (let c = 0; c < 4; c++) {
157
139
  const s0 = state[4 * c];
158
140
  const s1 = state[4 * c + 1];
@@ -163,7 +145,6 @@ function aesEncryptBlock(block, roundKeys) {
163
145
  state[4 * c + 2] = s0 ^ s1 ^ gf2(s2) ^ gf2(s3) ^ s3;
164
146
  state[4 * c + 3] = gf2(s0) ^ s0 ^ s1 ^ s2 ^ gf2(s3);
165
147
  }
166
- // AddRoundKey
167
148
  const keyOffset = round * 4;
168
149
  for (let c = 0; c < 4; c++) {
169
150
  for (let r = 0; r < 4; r++) {
@@ -171,7 +152,6 @@ function aesEncryptBlock(block, roundKeys) {
171
152
  }
172
153
  }
173
154
  }
174
- // Final round (no MixColumns)
175
155
  for (let i = 0; i < 16; i++) {
176
156
  state[i] = SBOX[state[i]];
177
157
  }
@@ -199,25 +179,16 @@ function aesEncryptBlock(block, roundKeys) {
199
179
  }
200
180
  return state;
201
181
  }
202
- // =============================================================================
203
- // AES Decrypt Block
204
- // =============================================================================
205
- /**
206
- * Decrypt a single AES block (16 bytes).
207
- */
208
182
  function aesDecryptBlock(block, roundKeys) {
209
183
  const nr = roundKeys.length / 4 - 1;
210
184
  const state = new Uint8Array(16);
211
185
  state.set(block);
212
- // Initial AddRoundKey
213
186
  for (let c = 0; c < 4; c++) {
214
187
  for (let r = 0; r < 4; r++) {
215
188
  state[4 * c + r] ^= roundKeys[nr * 4 + c][r];
216
189
  }
217
190
  }
218
- // Rounds nr-1 down to 1
219
191
  for (let round = nr - 1; round >= 1; round--) {
220
- // InvShiftRows
221
192
  let tmp;
222
193
  tmp = state[13];
223
194
  state[13] = state[9];
@@ -235,18 +206,15 @@ function aesDecryptBlock(block, roundKeys) {
235
206
  state[7] = state[11];
236
207
  state[11] = state[15];
237
208
  state[15] = tmp;
238
- // InvSubBytes
239
209
  for (let i = 0; i < 16; i++) {
240
210
  state[i] = INV_SBOX[state[i]];
241
211
  }
242
- // AddRoundKey
243
212
  const keyOffset = round * 4;
244
213
  for (let c = 0; c < 4; c++) {
245
214
  for (let r = 0; r < 4; r++) {
246
215
  state[4 * c + r] ^= roundKeys[keyOffset + c][r];
247
216
  }
248
217
  }
249
- // InvMixColumns
250
218
  for (let c = 0; c < 4; c++) {
251
219
  const s0 = state[4 * c];
252
220
  const s1 = state[4 * c + 1];
@@ -258,7 +226,6 @@ function aesDecryptBlock(block, roundKeys) {
258
226
  state[4 * c + 3] = gfMul(s0, 11) ^ gfMul(s1, 13) ^ gfMul(s2, 9) ^ gfMul(s3, 14);
259
227
  }
260
228
  }
261
- // Final round (no InvMixColumns)
262
229
  let tmp2;
263
230
  tmp2 = state[13];
264
231
  state[13] = state[9];
@@ -289,12 +256,7 @@ function aesDecryptBlock(block, roundKeys) {
289
256
  // =============================================================================
290
257
  // AES-CBC Public API
291
258
  // =============================================================================
292
- /**
293
- * AES-CBC encryption with PKCS#7 padding.
294
- * Supports AES-128 (16-byte key) and AES-256 (32-byte key).
295
- */
296
259
  function aesCbcEncrypt(plaintext, key, iv) {
297
- // PKCS#7 padding
298
260
  const padLen = 16 - (plaintext.length % 16);
299
261
  const padded = new Uint8Array(plaintext.length + padLen);
300
262
  padded.set(plaintext);
@@ -306,7 +268,6 @@ function aesCbcEncrypt(plaintext, key, iv) {
306
268
  const output = new Uint8Array(padded.length);
307
269
  let prevBlock = iv;
308
270
  for (let b = 0; b < numBlocks; b++) {
309
- // XOR plaintext block with previous ciphertext (or IV)
310
271
  const block = new Uint8Array(16);
311
272
  for (let i = 0; i < 16; i++) {
312
273
  block[i] = padded[b * 16 + i] ^ prevBlock[i];
@@ -317,10 +278,6 @@ function aesCbcEncrypt(plaintext, key, iv) {
317
278
  }
318
279
  return output;
319
280
  }
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
281
  function aesCbcDecrypt(ciphertext, key, iv) {
325
282
  const roundKeys = aesKeyExpansion(key);
326
283
  const numBlocks = ciphertext.length / 16;
@@ -334,7 +291,6 @@ function aesCbcDecrypt(ciphertext, key, iv) {
334
291
  }
335
292
  prevBlock = block;
336
293
  }
337
- // Remove PKCS#7 padding
338
294
  if (output.length > 0) {
339
295
  const padLen = output[output.length - 1];
340
296
  if (padLen > 0 && padLen <= 16) {
@@ -352,10 +308,6 @@ function aesCbcDecrypt(ciphertext, key, iv) {
352
308
  }
353
309
  return output;
354
310
  }
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
311
  function aesCbcDecryptRaw(ciphertext, key, iv) {
360
312
  const roundKeys = aesKeyExpansion(key);
361
313
  const numBlocks = ciphertext.length / 16;
@@ -371,13 +323,6 @@ function aesCbcDecryptRaw(ciphertext, key, iv) {
371
323
  }
372
324
  return output;
373
325
  }
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
326
  function aesCbcEncryptRaw(plaintext, key, iv) {
382
327
  if (plaintext.length % 16 !== 0) {
383
328
  throw new Error("aesCbcEncryptRaw: plaintext length must be a multiple of 16");
@@ -397,10 +342,6 @@ function aesCbcEncryptRaw(plaintext, key, iv) {
397
342
  }
398
343
  return output;
399
344
  }
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
345
  function aesEcbEncrypt(block, key) {
405
346
  const roundKeys = aesKeyExpansion(key);
406
347
  return aesEncryptBlock(block, roundKeys);
@@ -408,11 +349,9 @@ function aesEcbEncrypt(block, key) {
408
349
  // =============================================================================
409
350
  // SHA-256
410
351
  // =============================================================================
411
- /** SHA-256 initial hash values */
412
352
  const SHA256_H = new Uint32Array([
413
353
  0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
414
354
  ]);
415
- /** SHA-256 round constants */
416
355
  const SHA256_K = new Uint32Array([
417
356
  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
418
357
  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
@@ -426,10 +365,6 @@ const SHA256_K = new Uint32Array([
426
365
  function rotr32(x, n) {
427
366
  return ((x >>> n) | (x << (32 - n))) >>> 0;
428
367
  }
429
- /**
430
- * SHA-256 hash function.
431
- * @returns 32-byte digest
432
- */
433
368
  function sha256(input) {
434
369
  const msgLen = input.length;
435
370
  const paddedLen = Math.ceil((msgLen + 9) / 64) * 64;
@@ -504,7 +439,7 @@ function sha256(input) {
504
439
  return result;
505
440
  }
506
441
  // =============================================================================
507
- // MD5 (for legacy PDF reading)
442
+ // MD5
508
443
  // =============================================================================
509
444
  function rotl(x, n) {
510
445
  return ((x << n) | (x >>> (32 - n))) >>> 0;
@@ -524,10 +459,6 @@ const MD5_K = new Uint32Array([
524
459
  0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
525
460
  0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
526
461
  ]);
527
- /**
528
- * MD5 hash function (RFC 1321).
529
- * @returns 16-byte digest
530
- */
531
462
  function md5(input) {
532
463
  const msgLen = input.length;
533
464
  const bitLen = msgLen * 8;
@@ -590,11 +521,11 @@ function md5(input) {
590
521
  return digest;
591
522
  }
592
523
  // =============================================================================
593
- // RC4 (for legacy PDF reading only)
524
+ // RC4 (legacy)
594
525
  // =============================================================================
595
526
  /**
596
527
  * RC4 stream cipher.
597
- * @deprecated Only used for reading legacy encrypted PDFs. Writer uses AES-256.
528
+ * @deprecated Only used for reading legacy encrypted PDFs.
598
529
  */
599
530
  function rc4(key, data) {
600
531
  const s = new Uint8Array(256);
@@ -618,32 +549,94 @@ function rc4(key, data) {
618
549
  return result;
619
550
  }
620
551
  // =============================================================================
621
- // Random bytes (for IV generation)
552
+ // Random bytes
622
553
  // =============================================================================
623
554
  /**
624
- * Generate pseudo-random bytes.
625
- * Uses Math.random adequate for PDF IVs but not cryptographically secure.
555
+ * Generate cryptographically secure random bytes.
556
+ * Uses crypto.getRandomValues (available in all modern browsers).
626
557
  */
627
558
  function randomBytes(length) {
628
559
  const bytes = new Uint8Array(length);
629
- for (let i = 0; i < length; i++) {
630
- bytes[i] = (Math.random() * 256) | 0;
631
- }
560
+ globalThis.crypto.getRandomValues(bytes);
632
561
  return bytes;
633
562
  }
563
+ // =============================================================================
564
+ // Generic hash (async in browser — Web Crypto API)
565
+ // =============================================================================
566
+ /**
567
+ * Compute a hash digest using Web Crypto API.
568
+ *
569
+ * NOTE: In the browser, this is async. The Node.js version is sync.
570
+ * For callers that need sync hashing, use `sha256()` or `md5()` directly.
571
+ *
572
+ * @param algorithm - Hash algorithm name (e.g., "SHA-256", "SHA-512", "SHA-1").
573
+ * @param data - Data to hash
574
+ * @returns The digest bytes
575
+ */
576
+ async function hashAsync(algorithm, data) {
577
+ const buf = await globalThis.crypto.subtle.digest(normalizeAlgorithmForWebCrypto(algorithm), data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
578
+ return new Uint8Array(buf);
579
+ }
580
+ /**
581
+ * Normalize a hash algorithm name to the format Web Crypto API expects.
582
+ * Accepts: "sha256", "SHA-256", "sha-256", "SHA256" → "SHA-256"
583
+ */
584
+ function normalizeAlgorithmForWebCrypto(algorithm) {
585
+ const lower = algorithm.toLowerCase().replace(/-/g, "");
586
+ switch (lower) {
587
+ case "sha1":
588
+ return "SHA-1";
589
+ case "sha256":
590
+ return "SHA-256";
591
+ case "sha384":
592
+ return "SHA-384";
593
+ case "sha512":
594
+ return "SHA-512";
595
+ default:
596
+ // Pass through for any other algorithm — let Web Crypto validate
597
+ return algorithm;
598
+ }
599
+ }
634
600
  /**
635
- * Concatenate multiple Uint8Arrays.
601
+ * Compute a hash digest synchronously (pure JS — SHA-256 and MD5 only).
602
+ *
603
+ * @param algorithm - "SHA-256" or "MD5" (case-insensitive, hyphens optional)
604
+ * @param data - Data to hash
605
+ * @returns The digest bytes
606
+ * @throws If algorithm is not SHA-256 or MD5
636
607
  */
637
- function concatArrays(...arrays) {
638
- let totalLen = 0;
639
- for (const arr of arrays) {
640
- totalLen += arr.length;
608
+ function hash(algorithm, data) {
609
+ const algo = algorithm.toLowerCase().replace(/-/g, "");
610
+ if (algo === "sha256") {
611
+ return sha256(data);
641
612
  }
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;
613
+ if (algo === "md5") {
614
+ return md5(data);
647
615
  }
648
- return result;
616
+ throw new Error(`hash: unsupported algorithm "${algorithm}" in browser sync mode. Use hashAsync() for other algorithms.`);
617
+ }
618
+ // =============================================================================
619
+ // RSA signature operations (async — Web Crypto API)
620
+ // =============================================================================
621
+ /**
622
+ * Verify an RSA PKCS#1 v1.5 signature.
623
+ *
624
+ * @param publicKeyDer - DER-encoded SubjectPublicKeyInfo
625
+ * @param signature - The signature bytes
626
+ * @param data - The signed data (will be hashed with SHA-256)
627
+ */
628
+ async function rsaVerify(publicKeyDer, signature, data) {
629
+ const key = await globalThis.crypto.subtle.importKey("spki", publicKeyDer.buffer.slice(publicKeyDer.byteOffset, publicKeyDer.byteOffset + publicKeyDer.byteLength), { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["verify"]);
630
+ return globalThis.crypto.subtle.verify("RSASSA-PKCS1-v1_5", key, signature.buffer.slice(signature.byteOffset, signature.byteOffset + signature.byteLength), data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
631
+ }
632
+ /**
633
+ * Create an RSA PKCS#1 v1.5 signature.
634
+ *
635
+ * @param privateKeyDer - DER-encoded PKCS#8 private key
636
+ * @param data - The data to sign (will be hashed with SHA-256)
637
+ */
638
+ async function rsaSign(privateKeyDer, data) {
639
+ const key = await globalThis.crypto.subtle.importKey("pkcs8", privateKeyDer.buffer.slice(privateKeyDer.byteOffset, privateKeyDer.byteOffset + privateKeyDer.byteLength), { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["sign"]);
640
+ const sig = await globalThis.crypto.subtle.sign("RSASSA-PKCS1-v1_5", key, data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
641
+ return new Uint8Array(sig);
649
642
  }
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ /**
3
+ * Cryptographic primitives — Node.js version.
4
+ *
5
+ * Uses `node:crypto` for maximum performance where possible.
6
+ * Pure JS fallbacks for operations where `node:crypto` would be inconvenient
7
+ * (e.g., AES-CBC with specific PDF padding semantics).
8
+ *
9
+ * The browser counterpart (`crypto.browser.ts`) provides the same API using
10
+ * pure JS implementations for synchronous ops and Web Crypto for async ops.
11
+ *
12
+ * Shared by: PDF (encryption/decryption), Archive (via re-export if needed),
13
+ * and digital signature infrastructure.
14
+ *
15
+ * @see FIPS 197 — AES
16
+ * @see FIPS 180-4 — SHA-256
17
+ * @see RFC 1321 — MD5
18
+ * @see RFC 2104 — HMAC
19
+ */
20
+ var __importDefault = (this && this.__importDefault) || function (mod) {
21
+ return (mod && mod.__esModule) ? mod : { "default": mod };
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.sha256 = sha256;
25
+ exports.hmacSha256 = hmacSha256;
26
+ exports.md5 = md5;
27
+ exports.aesCbcEncrypt = aesCbcEncrypt;
28
+ exports.aesCbcDecrypt = aesCbcDecrypt;
29
+ exports.aesCbcDecryptRaw = aesCbcDecryptRaw;
30
+ exports.aesCbcEncryptRaw = aesCbcEncryptRaw;
31
+ exports.aesEcbEncrypt = aesEcbEncrypt;
32
+ exports.rc4 = rc4;
33
+ exports.randomBytes = randomBytes;
34
+ exports.hash = hash;
35
+ exports.hashAsync = hashAsync;
36
+ exports.rsaVerify = rsaVerify;
37
+ exports.rsaSign = rsaSign;
38
+ const node_crypto_1 = __importDefault(require("node:crypto"));
39
+ // =============================================================================
40
+ // SHA-256
41
+ // =============================================================================
42
+ /**
43
+ * SHA-256 hash function.
44
+ * @returns 32-byte digest
45
+ */
46
+ function sha256(input) {
47
+ return new Uint8Array(node_crypto_1.default.createHash("sha256").update(input).digest());
48
+ }
49
+ // =============================================================================
50
+ // Generic hash
51
+ // =============================================================================
52
+ /**
53
+ * HMAC-SHA256 (RFC 2104).
54
+ * @returns 32-byte MAC
55
+ */
56
+ function hmacSha256(key, message) {
57
+ return new Uint8Array(node_crypto_1.default.createHmac("sha256", key).update(message).digest());
58
+ }
59
+ // =============================================================================
60
+ // MD5
61
+ // =============================================================================
62
+ /**
63
+ * MD5 hash function (RFC 1321).
64
+ * @returns 16-byte digest
65
+ */
66
+ function md5(input) {
67
+ return new Uint8Array(node_crypto_1.default.createHash("md5").update(input).digest());
68
+ }
69
+ // =============================================================================
70
+ // AES-CBC
71
+ // =============================================================================
72
+ /**
73
+ * AES-CBC encryption with PKCS#7 padding.
74
+ * Supports AES-128 (16-byte key) and AES-256 (32-byte key).
75
+ */
76
+ function aesCbcEncrypt(plaintext, key, iv) {
77
+ const algo = key.length === 16 ? "aes-128-cbc" : "aes-256-cbc";
78
+ const cipher = node_crypto_1.default.createCipheriv(algo, key, iv);
79
+ return new Uint8Array(Buffer.concat([cipher.update(plaintext), cipher.final()]));
80
+ }
81
+ /**
82
+ * AES-CBC decryption with PKCS#7 padding removal.
83
+ * Supports AES-128 (16-byte key) and AES-256 (32-byte key).
84
+ */
85
+ function aesCbcDecrypt(ciphertext, key, iv) {
86
+ const algo = key.length === 16 ? "aes-128-cbc" : "aes-256-cbc";
87
+ const decipher = node_crypto_1.default.createDecipheriv(algo, key, iv);
88
+ try {
89
+ return new Uint8Array(Buffer.concat([decipher.update(ciphertext), decipher.final()]));
90
+ }
91
+ catch {
92
+ // Invalid padding — return raw decrypted data without padding removal
93
+ // (matches pure JS behavior for NIST test vectors and PDF key derivation)
94
+ const decipher2 = node_crypto_1.default.createDecipheriv(algo, key, iv);
95
+ decipher2.setAutoPadding(false);
96
+ return new Uint8Array(Buffer.concat([decipher2.update(ciphertext), decipher2.final()]));
97
+ }
98
+ }
99
+ /**
100
+ * AES-CBC decryption WITHOUT PKCS#7 padding removal.
101
+ * Used for key derivation where the output length is known.
102
+ */
103
+ function aesCbcDecryptRaw(ciphertext, key, iv) {
104
+ const algo = key.length === 16 ? "aes-128-cbc" : "aes-256-cbc";
105
+ const decipher = node_crypto_1.default.createDecipheriv(algo, key, iv);
106
+ decipher.setAutoPadding(false);
107
+ return new Uint8Array(Buffer.concat([decipher.update(ciphertext), decipher.final()]));
108
+ }
109
+ /**
110
+ * AES-CBC encryption WITHOUT PKCS#7 padding.
111
+ * Used when the plaintext is already block-aligned.
112
+ *
113
+ * @throws if plaintext length is not a multiple of 16.
114
+ */
115
+ function aesCbcEncryptRaw(plaintext, key, iv) {
116
+ if (plaintext.length % 16 !== 0) {
117
+ throw new Error("aesCbcEncryptRaw: plaintext length must be a multiple of 16");
118
+ }
119
+ const algo = key.length === 16 ? "aes-128-cbc" : "aes-256-cbc";
120
+ const cipher = node_crypto_1.default.createCipheriv(algo, key, iv);
121
+ cipher.setAutoPadding(false);
122
+ return new Uint8Array(Buffer.concat([cipher.update(plaintext), cipher.final()]));
123
+ }
124
+ /**
125
+ * AES-ECB encryption of a single 16-byte block (no padding, no IV).
126
+ */
127
+ function aesEcbEncrypt(block, key) {
128
+ const algo = key.length === 16 ? "aes-128-ecb" : "aes-256-ecb";
129
+ const cipher = node_crypto_1.default.createCipheriv(algo, key, null);
130
+ cipher.setAutoPadding(false);
131
+ return new Uint8Array(Buffer.concat([cipher.update(block), cipher.final()]));
132
+ }
133
+ // =============================================================================
134
+ // RC4 (legacy)
135
+ // =============================================================================
136
+ /**
137
+ * RC4 stream cipher.
138
+ * @deprecated Only used for reading legacy encrypted PDFs.
139
+ */
140
+ function rc4(key, data) {
141
+ // Node's crypto doesn't expose RC4 in modern versions, use pure JS
142
+ const s = new Uint8Array(256);
143
+ for (let i = 0; i < 256; i++) {
144
+ s[i] = i;
145
+ }
146
+ let j = 0;
147
+ for (let i = 0; i < 256; i++) {
148
+ j = (j + s[i] + key[i % key.length]) & 0xff;
149
+ [s[i], s[j]] = [s[j], s[i]];
150
+ }
151
+ const result = new Uint8Array(data.length);
152
+ let ii = 0;
153
+ let jj = 0;
154
+ for (let k = 0; k < data.length; k++) {
155
+ ii = (ii + 1) & 0xff;
156
+ jj = (jj + s[ii]) & 0xff;
157
+ [s[ii], s[jj]] = [s[jj], s[ii]];
158
+ result[k] = data[k] ^ s[(s[ii] + s[jj]) & 0xff];
159
+ }
160
+ return result;
161
+ }
162
+ // =============================================================================
163
+ // Random bytes
164
+ // =============================================================================
165
+ /**
166
+ * Generate cryptographically secure random bytes.
167
+ */
168
+ function randomBytes(length) {
169
+ return new Uint8Array(node_crypto_1.default.randomBytes(length));
170
+ }
171
+ // =============================================================================
172
+ // Generic hash
173
+ // =============================================================================
174
+ /**
175
+ * Compute a hash digest using any algorithm supported by the platform.
176
+ *
177
+ * @param algorithm - Hash algorithm name (e.g., "SHA-256", "SHA-512", "SHA-1", "MD5").
178
+ * Normalized internally: hyphens removed, lowercased.
179
+ * @param data - Data to hash
180
+ * @returns The digest bytes
181
+ */
182
+ function hash(algorithm, data) {
183
+ const algo = algorithm.toLowerCase().replace(/-/g, "");
184
+ return new Uint8Array(node_crypto_1.default.createHash(algo).update(data).digest());
185
+ }
186
+ /**
187
+ * Async version of `hash()` — same behavior, but returns a Promise for API
188
+ * parity with the browser version.
189
+ */
190
+ async function hashAsync(algorithm, data) {
191
+ return hash(algorithm, data);
192
+ }
193
+ // =============================================================================
194
+ // RSA signature operations (async — for digital signatures)
195
+ // =============================================================================
196
+ /**
197
+ * Verify an RSA PKCS#1 v1.5 signature.
198
+ *
199
+ * @param publicKeyDer - DER-encoded SubjectPublicKeyInfo
200
+ * @param signature - The signature bytes
201
+ * @param data - The signed data (will be hashed with SHA-256)
202
+ */
203
+ async function rsaVerify(publicKeyDer, signature, data) {
204
+ const key = node_crypto_1.default.createPublicKey({
205
+ key: Buffer.from(publicKeyDer),
206
+ format: "der",
207
+ type: "spki"
208
+ });
209
+ const verifier = node_crypto_1.default.createVerify("SHA256");
210
+ verifier.update(data);
211
+ return verifier.verify(key, signature);
212
+ }
213
+ /**
214
+ * Create an RSA PKCS#1 v1.5 signature.
215
+ *
216
+ * @param privateKeyDer - DER-encoded PKCS#8 private key
217
+ * @param data - The data to sign (will be hashed with SHA-256)
218
+ */
219
+ async function rsaSign(privateKeyDer, data) {
220
+ const key = node_crypto_1.default.createPrivateKey({
221
+ key: Buffer.from(privateKeyDer),
222
+ format: "der",
223
+ type: "pkcs8"
224
+ });
225
+ const signer = node_crypto_1.default.createSign("SHA256");
226
+ signer.update(data);
227
+ return new Uint8Array(signer.sign(key));
228
+ }
@@ -45,7 +45,7 @@ export function ensureZlibSync() {
45
45
  return;
46
46
  }
47
47
  try {
48
- // eslint-disable-next-line @typescript-eslint/no-require-imports
48
+ // oxlint-disable-next-line typescript/no-require-imports
49
49
  _zlib = require("zlib");
50
50
  _zlibInitStarted = true;
51
51
  }