@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,20 +1,18 @@
1
1
  /**
2
- * Shared cryptographic primitives for PDF encryption/decryption.
2
+ * Cryptographic primitives Browser version.
3
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)
4
+ * Uses pure JavaScript for synchronous operations (SHA-256, MD5, AES-CBC, RC4)
5
+ * since Web Crypto API is async-only and cannot replace synchronous call sites.
9
6
  *
10
- * @see FIPS 197 AES
11
- * @see FIPS 180-4SHA-256
12
- * @see RFC 1321MD5
7
+ * Uses Web Crypto API for:
8
+ * - `randomBytes` (crypto.getRandomValuestruly random)
9
+ * - `rsaVerify` / `rsaSign` (SubtleCrypto hardware-accelerated)
10
+ *
11
+ * Exports the same API as `crypto.ts` (Node.js version).
13
12
  */
14
13
  // =============================================================================
15
14
  // AES S-Box & Constants
16
15
  // =============================================================================
17
- /** AES S-Box */
18
16
  const SBOX = new Uint8Array([
19
17
  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
20
18
  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
@@ -33,23 +31,19 @@ const SBOX = new Uint8Array([
33
31
  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
34
32
  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
35
33
  ]);
36
- /** Inverse S-Box for decryption */
37
34
  const INV_SBOX = new Uint8Array(256);
38
35
  /* @__PURE__ */ (() => {
39
36
  for (let i = 0; i < 256; i++) {
40
37
  INV_SBOX[SBOX[i]] = i;
41
38
  }
42
39
  })();
43
- /** AES round constants */
44
40
  const RCON = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
45
41
  // =============================================================================
46
42
  // AES Helpers
47
43
  // =============================================================================
48
- /** GF(2^8) multiplication by 2 */
49
44
  function gf2(a) {
50
45
  return a < 128 ? a << 1 : (a << 1) ^ 0x11b;
51
46
  }
52
- /** GF(2^8) multiplication */
53
47
  function gfMul(a, b) {
54
48
  let result = 0;
55
49
  let aa = a;
@@ -63,9 +57,6 @@ function gfMul(a, b) {
63
57
  }
64
58
  return result;
65
59
  }
66
- /**
67
- * AES key expansion. Supports AES-128 (16-byte key) and AES-256 (32-byte key).
68
- */
69
60
  function aesKeyExpansion(key) {
70
61
  const nk = key.length / 4;
71
62
  const nr = nk + 6;
@@ -97,50 +88,38 @@ function aesKeyExpansion(key) {
97
88
  return w;
98
89
  }
99
90
  // =============================================================================
100
- // AES Encrypt Block
91
+ // AES Block Encrypt / Decrypt
101
92
  // =============================================================================
102
- /**
103
- * Encrypt a single AES block (16 bytes).
104
- * State layout: column-major per FIPS 197 §3.4.
105
- */
106
93
  function aesEncryptBlock(block, roundKeys) {
107
94
  const nr = roundKeys.length / 4 - 1;
108
95
  const state = new Uint8Array(16);
109
96
  state.set(block);
110
- // Initial AddRoundKey
111
97
  for (let c = 0; c < 4; c++) {
112
98
  for (let r = 0; r < 4; r++) {
113
99
  state[4 * c + r] ^= roundKeys[c][r];
114
100
  }
115
101
  }
116
- // Rounds 1 to nr-1
117
102
  for (let round = 1; round < nr; round++) {
118
- // SubBytes
119
103
  for (let i = 0; i < 16; i++) {
120
104
  state[i] = SBOX[state[i]];
121
105
  }
122
- // ShiftRows: row r shifts left by r
123
106
  let tmp;
124
- // Row 1: shift left by 1
125
107
  tmp = state[1];
126
108
  state[1] = state[5];
127
109
  state[5] = state[9];
128
110
  state[9] = state[13];
129
111
  state[13] = tmp;
130
- // Row 2: shift left by 2
131
112
  tmp = state[2];
132
113
  state[2] = state[10];
133
114
  state[10] = tmp;
134
115
  tmp = state[6];
135
116
  state[6] = state[14];
136
117
  state[14] = tmp;
137
- // Row 3: shift left by 3
138
118
  tmp = state[15];
139
119
  state[15] = state[11];
140
120
  state[11] = state[7];
141
121
  state[7] = state[3];
142
122
  state[3] = tmp;
143
- // MixColumns
144
123
  for (let c = 0; c < 4; c++) {
145
124
  const s0 = state[4 * c];
146
125
  const s1 = state[4 * c + 1];
@@ -151,7 +130,6 @@ function aesEncryptBlock(block, roundKeys) {
151
130
  state[4 * c + 2] = s0 ^ s1 ^ gf2(s2) ^ gf2(s3) ^ s3;
152
131
  state[4 * c + 3] = gf2(s0) ^ s0 ^ s1 ^ s2 ^ gf2(s3);
153
132
  }
154
- // AddRoundKey
155
133
  const keyOffset = round * 4;
156
134
  for (let c = 0; c < 4; c++) {
157
135
  for (let r = 0; r < 4; r++) {
@@ -159,7 +137,6 @@ function aesEncryptBlock(block, roundKeys) {
159
137
  }
160
138
  }
161
139
  }
162
- // Final round (no MixColumns)
163
140
  for (let i = 0; i < 16; i++) {
164
141
  state[i] = SBOX[state[i]];
165
142
  }
@@ -187,25 +164,16 @@ function aesEncryptBlock(block, roundKeys) {
187
164
  }
188
165
  return state;
189
166
  }
190
- // =============================================================================
191
- // AES Decrypt Block
192
- // =============================================================================
193
- /**
194
- * Decrypt a single AES block (16 bytes).
195
- */
196
167
  function aesDecryptBlock(block, roundKeys) {
197
168
  const nr = roundKeys.length / 4 - 1;
198
169
  const state = new Uint8Array(16);
199
170
  state.set(block);
200
- // Initial AddRoundKey
201
171
  for (let c = 0; c < 4; c++) {
202
172
  for (let r = 0; r < 4; r++) {
203
173
  state[4 * c + r] ^= roundKeys[nr * 4 + c][r];
204
174
  }
205
175
  }
206
- // Rounds nr-1 down to 1
207
176
  for (let round = nr - 1; round >= 1; round--) {
208
- // InvShiftRows
209
177
  let tmp;
210
178
  tmp = state[13];
211
179
  state[13] = state[9];
@@ -223,18 +191,15 @@ function aesDecryptBlock(block, roundKeys) {
223
191
  state[7] = state[11];
224
192
  state[11] = state[15];
225
193
  state[15] = tmp;
226
- // InvSubBytes
227
194
  for (let i = 0; i < 16; i++) {
228
195
  state[i] = INV_SBOX[state[i]];
229
196
  }
230
- // AddRoundKey
231
197
  const keyOffset = round * 4;
232
198
  for (let c = 0; c < 4; c++) {
233
199
  for (let r = 0; r < 4; r++) {
234
200
  state[4 * c + r] ^= roundKeys[keyOffset + c][r];
235
201
  }
236
202
  }
237
- // InvMixColumns
238
203
  for (let c = 0; c < 4; c++) {
239
204
  const s0 = state[4 * c];
240
205
  const s1 = state[4 * c + 1];
@@ -246,7 +211,6 @@ function aesDecryptBlock(block, roundKeys) {
246
211
  state[4 * c + 3] = gfMul(s0, 11) ^ gfMul(s1, 13) ^ gfMul(s2, 9) ^ gfMul(s3, 14);
247
212
  }
248
213
  }
249
- // Final round (no InvMixColumns)
250
214
  let tmp2;
251
215
  tmp2 = state[13];
252
216
  state[13] = state[9];
@@ -277,12 +241,7 @@ function aesDecryptBlock(block, roundKeys) {
277
241
  // =============================================================================
278
242
  // AES-CBC Public API
279
243
  // =============================================================================
280
- /**
281
- * AES-CBC encryption with PKCS#7 padding.
282
- * Supports AES-128 (16-byte key) and AES-256 (32-byte key).
283
- */
284
244
  export function aesCbcEncrypt(plaintext, key, iv) {
285
- // PKCS#7 padding
286
245
  const padLen = 16 - (plaintext.length % 16);
287
246
  const padded = new Uint8Array(plaintext.length + padLen);
288
247
  padded.set(plaintext);
@@ -294,7 +253,6 @@ export function aesCbcEncrypt(plaintext, key, iv) {
294
253
  const output = new Uint8Array(padded.length);
295
254
  let prevBlock = iv;
296
255
  for (let b = 0; b < numBlocks; b++) {
297
- // XOR plaintext block with previous ciphertext (or IV)
298
256
  const block = new Uint8Array(16);
299
257
  for (let i = 0; i < 16; i++) {
300
258
  block[i] = padded[b * 16 + i] ^ prevBlock[i];
@@ -305,10 +263,6 @@ export function aesCbcEncrypt(plaintext, key, iv) {
305
263
  }
306
264
  return output;
307
265
  }
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
266
  export function aesCbcDecrypt(ciphertext, key, iv) {
313
267
  const roundKeys = aesKeyExpansion(key);
314
268
  const numBlocks = ciphertext.length / 16;
@@ -322,7 +276,6 @@ export function aesCbcDecrypt(ciphertext, key, iv) {
322
276
  }
323
277
  prevBlock = block;
324
278
  }
325
- // Remove PKCS#7 padding
326
279
  if (output.length > 0) {
327
280
  const padLen = output[output.length - 1];
328
281
  if (padLen > 0 && padLen <= 16) {
@@ -340,10 +293,6 @@ export function aesCbcDecrypt(ciphertext, key, iv) {
340
293
  }
341
294
  return output;
342
295
  }
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
296
  export function aesCbcDecryptRaw(ciphertext, key, iv) {
348
297
  const roundKeys = aesKeyExpansion(key);
349
298
  const numBlocks = ciphertext.length / 16;
@@ -359,13 +308,6 @@ export function aesCbcDecryptRaw(ciphertext, key, iv) {
359
308
  }
360
309
  return output;
361
310
  }
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
311
  export function aesCbcEncryptRaw(plaintext, key, iv) {
370
312
  if (plaintext.length % 16 !== 0) {
371
313
  throw new Error("aesCbcEncryptRaw: plaintext length must be a multiple of 16");
@@ -385,10 +327,6 @@ export function aesCbcEncryptRaw(plaintext, key, iv) {
385
327
  }
386
328
  return output;
387
329
  }
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
330
  export function aesEcbEncrypt(block, key) {
393
331
  const roundKeys = aesKeyExpansion(key);
394
332
  return aesEncryptBlock(block, roundKeys);
@@ -396,11 +334,9 @@ export function aesEcbEncrypt(block, key) {
396
334
  // =============================================================================
397
335
  // SHA-256
398
336
  // =============================================================================
399
- /** SHA-256 initial hash values */
400
337
  const SHA256_H = new Uint32Array([
401
338
  0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
402
339
  ]);
403
- /** SHA-256 round constants */
404
340
  const SHA256_K = new Uint32Array([
405
341
  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
406
342
  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
@@ -414,10 +350,6 @@ const SHA256_K = new Uint32Array([
414
350
  function rotr32(x, n) {
415
351
  return ((x >>> n) | (x << (32 - n))) >>> 0;
416
352
  }
417
- /**
418
- * SHA-256 hash function.
419
- * @returns 32-byte digest
420
- */
421
353
  export function sha256(input) {
422
354
  const msgLen = input.length;
423
355
  const paddedLen = Math.ceil((msgLen + 9) / 64) * 64;
@@ -492,7 +424,7 @@ export function sha256(input) {
492
424
  return result;
493
425
  }
494
426
  // =============================================================================
495
- // MD5 (for legacy PDF reading)
427
+ // MD5
496
428
  // =============================================================================
497
429
  function rotl(x, n) {
498
430
  return ((x << n) | (x >>> (32 - n))) >>> 0;
@@ -512,10 +444,6 @@ const MD5_K = new Uint32Array([
512
444
  0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
513
445
  0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
514
446
  ]);
515
- /**
516
- * MD5 hash function (RFC 1321).
517
- * @returns 16-byte digest
518
- */
519
447
  export function md5(input) {
520
448
  const msgLen = input.length;
521
449
  const bitLen = msgLen * 8;
@@ -578,11 +506,11 @@ export function md5(input) {
578
506
  return digest;
579
507
  }
580
508
  // =============================================================================
581
- // RC4 (for legacy PDF reading only)
509
+ // RC4 (legacy)
582
510
  // =============================================================================
583
511
  /**
584
512
  * RC4 stream cipher.
585
- * @deprecated Only used for reading legacy encrypted PDFs. Writer uses AES-256.
513
+ * @deprecated Only used for reading legacy encrypted PDFs.
586
514
  */
587
515
  export function rc4(key, data) {
588
516
  const s = new Uint8Array(256);
@@ -606,32 +534,94 @@ export function rc4(key, data) {
606
534
  return result;
607
535
  }
608
536
  // =============================================================================
609
- // Random bytes (for IV generation)
537
+ // Random bytes
610
538
  // =============================================================================
611
539
  /**
612
- * Generate pseudo-random bytes.
613
- * Uses Math.random adequate for PDF IVs but not cryptographically secure.
540
+ * Generate cryptographically secure random bytes.
541
+ * Uses crypto.getRandomValues (available in all modern browsers).
614
542
  */
615
543
  export function randomBytes(length) {
616
544
  const bytes = new Uint8Array(length);
617
- for (let i = 0; i < length; i++) {
618
- bytes[i] = (Math.random() * 256) | 0;
619
- }
545
+ globalThis.crypto.getRandomValues(bytes);
620
546
  return bytes;
621
547
  }
548
+ // =============================================================================
549
+ // Generic hash (async in browser — Web Crypto API)
550
+ // =============================================================================
551
+ /**
552
+ * Compute a hash digest using Web Crypto API.
553
+ *
554
+ * NOTE: In the browser, this is async. The Node.js version is sync.
555
+ * For callers that need sync hashing, use `sha256()` or `md5()` directly.
556
+ *
557
+ * @param algorithm - Hash algorithm name (e.g., "SHA-256", "SHA-512", "SHA-1").
558
+ * @param data - Data to hash
559
+ * @returns The digest bytes
560
+ */
561
+ export async function hashAsync(algorithm, data) {
562
+ const buf = await globalThis.crypto.subtle.digest(normalizeAlgorithmForWebCrypto(algorithm), data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
563
+ return new Uint8Array(buf);
564
+ }
565
+ /**
566
+ * Normalize a hash algorithm name to the format Web Crypto API expects.
567
+ * Accepts: "sha256", "SHA-256", "sha-256", "SHA256" → "SHA-256"
568
+ */
569
+ function normalizeAlgorithmForWebCrypto(algorithm) {
570
+ const lower = algorithm.toLowerCase().replace(/-/g, "");
571
+ switch (lower) {
572
+ case "sha1":
573
+ return "SHA-1";
574
+ case "sha256":
575
+ return "SHA-256";
576
+ case "sha384":
577
+ return "SHA-384";
578
+ case "sha512":
579
+ return "SHA-512";
580
+ default:
581
+ // Pass through for any other algorithm — let Web Crypto validate
582
+ return algorithm;
583
+ }
584
+ }
622
585
  /**
623
- * Concatenate multiple Uint8Arrays.
586
+ * Compute a hash digest synchronously (pure JS — SHA-256 and MD5 only).
587
+ *
588
+ * @param algorithm - "SHA-256" or "MD5" (case-insensitive, hyphens optional)
589
+ * @param data - Data to hash
590
+ * @returns The digest bytes
591
+ * @throws If algorithm is not SHA-256 or MD5
624
592
  */
625
- export function concatArrays(...arrays) {
626
- let totalLen = 0;
627
- for (const arr of arrays) {
628
- totalLen += arr.length;
593
+ export function hash(algorithm, data) {
594
+ const algo = algorithm.toLowerCase().replace(/-/g, "");
595
+ if (algo === "sha256") {
596
+ return sha256(data);
629
597
  }
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;
598
+ if (algo === "md5") {
599
+ return md5(data);
635
600
  }
636
- return result;
601
+ throw new Error(`hash: unsupported algorithm "${algorithm}" in browser sync mode. Use hashAsync() for other algorithms.`);
602
+ }
603
+ // =============================================================================
604
+ // RSA signature operations (async — Web Crypto API)
605
+ // =============================================================================
606
+ /**
607
+ * Verify an RSA PKCS#1 v1.5 signature.
608
+ *
609
+ * @param publicKeyDer - DER-encoded SubjectPublicKeyInfo
610
+ * @param signature - The signature bytes
611
+ * @param data - The signed data (will be hashed with SHA-256)
612
+ */
613
+ export async function rsaVerify(publicKeyDer, signature, data) {
614
+ 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"]);
615
+ 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));
616
+ }
617
+ /**
618
+ * Create an RSA PKCS#1 v1.5 signature.
619
+ *
620
+ * @param privateKeyDer - DER-encoded PKCS#8 private key
621
+ * @param data - The data to sign (will be hashed with SHA-256)
622
+ */
623
+ export async function rsaSign(privateKeyDer, data) {
624
+ 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"]);
625
+ const sig = await globalThis.crypto.subtle.sign("RSASSA-PKCS1-v1_5", key, data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
626
+ return new Uint8Array(sig);
637
627
  }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Cryptographic primitives — Node.js version.
3
+ *
4
+ * Uses `node:crypto` for maximum performance where possible.
5
+ * Pure JS fallbacks for operations where `node:crypto` would be inconvenient
6
+ * (e.g., AES-CBC with specific PDF padding semantics).
7
+ *
8
+ * The browser counterpart (`crypto.browser.ts`) provides the same API using
9
+ * pure JS implementations for synchronous ops and Web Crypto for async ops.
10
+ *
11
+ * Shared by: PDF (encryption/decryption), Archive (via re-export if needed),
12
+ * and digital signature infrastructure.
13
+ *
14
+ * @see FIPS 197 — AES
15
+ * @see FIPS 180-4 — SHA-256
16
+ * @see RFC 1321 — MD5
17
+ * @see RFC 2104 — HMAC
18
+ */
19
+ /**
20
+ * SHA-256 hash function.
21
+ * @returns 32-byte digest
22
+ */
23
+ export declare function sha256(input: Uint8Array): Uint8Array;
24
+ /**
25
+ * HMAC-SHA256 (RFC 2104).
26
+ * @returns 32-byte MAC
27
+ */
28
+ export declare function hmacSha256(key: Uint8Array, message: Uint8Array): Uint8Array;
29
+ /**
30
+ * MD5 hash function (RFC 1321).
31
+ * @returns 16-byte digest
32
+ */
33
+ export declare function md5(input: Uint8Array): Uint8Array;
34
+ /**
35
+ * AES-CBC encryption with PKCS#7 padding.
36
+ * Supports AES-128 (16-byte key) and AES-256 (32-byte key).
37
+ */
38
+ export declare function aesCbcEncrypt(plaintext: Uint8Array, key: Uint8Array, iv: Uint8Array): Uint8Array;
39
+ /**
40
+ * AES-CBC decryption with PKCS#7 padding removal.
41
+ * Supports AES-128 (16-byte key) and AES-256 (32-byte key).
42
+ */
43
+ export declare function aesCbcDecrypt(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array): Uint8Array;
44
+ /**
45
+ * AES-CBC decryption WITHOUT PKCS#7 padding removal.
46
+ * Used for key derivation where the output length is known.
47
+ */
48
+ export declare function aesCbcDecryptRaw(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array): Uint8Array;
49
+ /**
50
+ * AES-CBC encryption WITHOUT PKCS#7 padding.
51
+ * Used when the plaintext is already block-aligned.
52
+ *
53
+ * @throws if plaintext length is not a multiple of 16.
54
+ */
55
+ export declare function aesCbcEncryptRaw(plaintext: Uint8Array, key: Uint8Array, iv: Uint8Array): Uint8Array;
56
+ /**
57
+ * AES-ECB encryption of a single 16-byte block (no padding, no IV).
58
+ */
59
+ export declare function aesEcbEncrypt(block: Uint8Array, key: Uint8Array): Uint8Array;
60
+ /**
61
+ * RC4 stream cipher.
62
+ * @deprecated Only used for reading legacy encrypted PDFs.
63
+ */
64
+ export declare function rc4(key: Uint8Array, data: Uint8Array): Uint8Array;
65
+ /**
66
+ * Generate cryptographically secure random bytes.
67
+ */
68
+ export declare function randomBytes(length: number): Uint8Array;
69
+ /**
70
+ * Compute a hash digest using any algorithm supported by the platform.
71
+ *
72
+ * @param algorithm - Hash algorithm name (e.g., "SHA-256", "SHA-512", "SHA-1", "MD5").
73
+ * Normalized internally: hyphens removed, lowercased.
74
+ * @param data - Data to hash
75
+ * @returns The digest bytes
76
+ */
77
+ export declare function hash(algorithm: string, data: Uint8Array): Uint8Array;
78
+ /**
79
+ * Async version of `hash()` — same behavior, but returns a Promise for API
80
+ * parity with the browser version.
81
+ */
82
+ export declare function hashAsync(algorithm: string, data: Uint8Array): Promise<Uint8Array>;
83
+ /**
84
+ * Verify an RSA PKCS#1 v1.5 signature.
85
+ *
86
+ * @param publicKeyDer - DER-encoded SubjectPublicKeyInfo
87
+ * @param signature - The signature bytes
88
+ * @param data - The signed data (will be hashed with SHA-256)
89
+ */
90
+ export declare function rsaVerify(publicKeyDer: Uint8Array, signature: Uint8Array, data: Uint8Array): Promise<boolean>;
91
+ /**
92
+ * Create an RSA PKCS#1 v1.5 signature.
93
+ *
94
+ * @param privateKeyDer - DER-encoded PKCS#8 private key
95
+ * @param data - The data to sign (will be hashed with SHA-256)
96
+ */
97
+ export declare function rsaSign(privateKeyDer: Uint8Array, data: Uint8Array): Promise<Uint8Array>;