@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.
- package/README.md +16 -1
- package/dist/browser/modules/archive/compression/crc32.js +1 -1
- package/dist/browser/modules/archive/crypto/aes.d.ts +0 -8
- package/dist/browser/modules/archive/crypto/aes.js +1 -20
- package/dist/browser/modules/archive/crypto/index.d.ts +2 -1
- package/dist/browser/modules/archive/crypto/index.js +3 -1
- package/dist/browser/modules/csv/parse/row-processor.d.ts +1 -1
- package/dist/browser/modules/csv/worker/worker-script.generated.js +1 -1
- package/dist/browser/modules/excel/utils/cell-matrix.js +1 -0
- package/dist/browser/modules/excel/utils/encryptor.browser.d.ts +4 -5
- package/dist/browser/modules/excel/utils/encryptor.browser.js +7 -12
- package/dist/browser/modules/excel/utils/encryptor.d.ts +1 -1
- package/dist/browser/modules/excel/utils/encryptor.js +4 -7
- package/dist/browser/modules/pdf/builder/document-builder.d.ts +517 -0
- package/dist/browser/modules/pdf/builder/document-builder.js +1493 -0
- package/dist/browser/modules/pdf/builder/form-appearance.d.ts +56 -0
- package/dist/browser/modules/pdf/builder/form-appearance.js +140 -0
- package/dist/browser/modules/pdf/builder/image-utils.d.ts +39 -0
- package/dist/browser/modules/pdf/builder/image-utils.js +129 -0
- package/dist/browser/modules/pdf/builder/pdf-editor.d.ts +230 -0
- package/dist/browser/modules/pdf/builder/pdf-editor.js +1574 -0
- package/dist/browser/modules/pdf/builder/resource-merger.d.ts +41 -0
- package/dist/browser/modules/pdf/builder/resource-merger.js +258 -0
- package/dist/browser/modules/pdf/core/digital-signature.d.ts +109 -0
- package/dist/browser/modules/pdf/core/digital-signature.js +659 -0
- package/dist/browser/modules/pdf/core/encryption.js +8 -7
- package/dist/browser/modules/pdf/core/pdf-object.d.ts +11 -0
- package/dist/browser/modules/pdf/core/pdf-object.js +38 -0
- package/dist/browser/modules/pdf/core/pdf-stream.d.ts +32 -0
- package/dist/browser/modules/pdf/core/pdf-stream.js +66 -0
- package/dist/browser/modules/pdf/core/pdf-writer.d.ts +55 -1
- package/dist/browser/modules/pdf/core/pdf-writer.js +271 -6
- package/dist/browser/modules/pdf/core/pdfa.d.ts +62 -0
- package/dist/browser/modules/pdf/core/pdfa.js +261 -0
- package/dist/browser/modules/pdf/index.d.ts +11 -0
- package/dist/browser/modules/pdf/index.js +9 -0
- package/dist/browser/modules/pdf/reader/bookmark-extractor.d.ts +35 -0
- package/dist/browser/modules/pdf/reader/bookmark-extractor.js +324 -0
- package/dist/browser/modules/pdf/reader/pdf-decrypt.js +6 -5
- package/dist/browser/modules/pdf/reader/pdf-reader.d.ts +17 -0
- package/dist/browser/modules/pdf/reader/pdf-reader.js +26 -2
- package/dist/browser/modules/pdf/reader/table-extractor.d.ts +69 -0
- package/dist/browser/modules/pdf/reader/table-extractor.js +365 -0
- package/dist/browser/modules/pdf/render/layout-engine.d.ts +21 -1
- package/dist/browser/modules/pdf/render/layout-engine.js +112 -5
- package/dist/browser/modules/pdf/render/page-renderer.d.ts +2 -9
- package/dist/browser/modules/pdf/render/page-renderer.js +62 -103
- package/dist/browser/modules/pdf/render/pdf-exporter.js +2 -61
- package/dist/browser/modules/pdf/render/style-converter.d.ts +4 -0
- package/dist/browser/modules/pdf/render/style-converter.js +1 -1
- package/dist/browser/modules/pdf/types.d.ts +14 -1
- package/dist/browser/modules/stream/browser/readable.js +8 -2
- package/dist/browser/utils/crypto.browser.d.ts +64 -0
- package/dist/browser/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +91 -101
- package/dist/browser/utils/crypto.d.ts +97 -0
- package/dist/browser/utils/crypto.js +209 -0
- package/dist/cjs/modules/archive/compression/crc32.js +1 -1
- package/dist/cjs/modules/archive/crypto/aes.js +2 -23
- package/dist/cjs/modules/archive/crypto/index.js +3 -1
- package/dist/cjs/modules/csv/worker/worker-script.generated.js +1 -1
- package/dist/cjs/modules/excel/utils/cell-matrix.js +1 -0
- package/dist/cjs/modules/excel/utils/encryptor.browser.js +7 -12
- package/dist/cjs/modules/excel/utils/encryptor.js +4 -10
- package/dist/cjs/modules/pdf/builder/document-builder.js +1532 -0
- package/dist/cjs/modules/pdf/builder/form-appearance.js +145 -0
- package/dist/cjs/modules/pdf/builder/image-utils.js +135 -0
- package/dist/cjs/modules/pdf/builder/pdf-editor.js +1612 -0
- package/dist/cjs/modules/pdf/builder/resource-merger.js +263 -0
- package/dist/cjs/modules/pdf/core/digital-signature.js +667 -0
- package/dist/cjs/modules/pdf/core/encryption.js +8 -7
- package/dist/cjs/modules/pdf/core/pdf-object.js +38 -0
- package/dist/cjs/modules/pdf/core/pdf-stream.js +66 -0
- package/dist/cjs/modules/pdf/core/pdf-writer.js +272 -6
- package/dist/cjs/modules/pdf/core/pdfa.js +266 -0
- package/dist/cjs/modules/pdf/index.js +19 -1
- package/dist/cjs/modules/pdf/reader/bookmark-extractor.js +327 -0
- package/dist/cjs/modules/pdf/reader/pdf-decrypt.js +6 -5
- package/dist/cjs/modules/pdf/reader/pdf-reader.js +26 -2
- package/dist/cjs/modules/pdf/reader/table-extractor.js +368 -0
- package/dist/cjs/modules/pdf/render/layout-engine.js +113 -4
- package/dist/cjs/modules/pdf/render/page-renderer.js +63 -105
- package/dist/cjs/modules/pdf/render/pdf-exporter.js +3 -62
- package/dist/cjs/modules/pdf/render/style-converter.js +1 -0
- package/dist/cjs/modules/stream/browser/readable.js +8 -2
- package/dist/cjs/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +95 -102
- package/dist/cjs/utils/crypto.js +228 -0
- package/dist/esm/modules/archive/compression/crc32.js +1 -1
- package/dist/esm/modules/archive/crypto/aes.js +1 -20
- package/dist/esm/modules/archive/crypto/index.js +3 -1
- package/dist/esm/modules/csv/worker/worker-script.generated.js +1 -1
- package/dist/esm/modules/excel/utils/cell-matrix.js +1 -0
- package/dist/esm/modules/excel/utils/encryptor.browser.js +7 -12
- package/dist/esm/modules/excel/utils/encryptor.js +4 -7
- package/dist/esm/modules/pdf/builder/document-builder.js +1493 -0
- package/dist/esm/modules/pdf/builder/form-appearance.js +140 -0
- package/dist/esm/modules/pdf/builder/image-utils.js +129 -0
- package/dist/esm/modules/pdf/builder/pdf-editor.js +1574 -0
- package/dist/esm/modules/pdf/builder/resource-merger.js +258 -0
- package/dist/esm/modules/pdf/core/digital-signature.js +659 -0
- package/dist/esm/modules/pdf/core/encryption.js +8 -7
- package/dist/esm/modules/pdf/core/pdf-object.js +38 -0
- package/dist/esm/modules/pdf/core/pdf-stream.js +66 -0
- package/dist/esm/modules/pdf/core/pdf-writer.js +271 -6
- package/dist/esm/modules/pdf/core/pdfa.js +261 -0
- package/dist/esm/modules/pdf/index.js +9 -0
- package/dist/esm/modules/pdf/reader/bookmark-extractor.js +324 -0
- package/dist/esm/modules/pdf/reader/pdf-decrypt.js +6 -5
- package/dist/esm/modules/pdf/reader/pdf-reader.js +26 -2
- package/dist/esm/modules/pdf/reader/table-extractor.js +365 -0
- package/dist/esm/modules/pdf/render/layout-engine.js +112 -5
- package/dist/esm/modules/pdf/render/page-renderer.js +62 -103
- package/dist/esm/modules/pdf/render/pdf-exporter.js +2 -61
- package/dist/esm/modules/pdf/render/style-converter.js +1 -1
- package/dist/esm/modules/stream/browser/readable.js +8 -2
- package/dist/esm/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +91 -101
- package/dist/esm/utils/crypto.js +209 -0
- package/dist/iife/excelts.iife.js +1248 -1074
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +53 -54
- package/dist/types/modules/archive/crypto/aes.d.ts +0 -8
- package/dist/types/modules/archive/crypto/index.d.ts +2 -1
- package/dist/types/modules/csv/parse/row-processor.d.ts +1 -1
- package/dist/types/modules/excel/utils/encryptor.browser.d.ts +4 -5
- package/dist/types/modules/excel/utils/encryptor.d.ts +1 -1
- package/dist/types/modules/pdf/builder/document-builder.d.ts +517 -0
- package/dist/types/modules/pdf/builder/form-appearance.d.ts +56 -0
- package/dist/types/modules/pdf/builder/image-utils.d.ts +39 -0
- package/dist/types/modules/pdf/builder/pdf-editor.d.ts +230 -0
- package/dist/types/modules/pdf/builder/resource-merger.d.ts +41 -0
- package/dist/types/modules/pdf/core/digital-signature.d.ts +109 -0
- package/dist/types/modules/pdf/core/pdf-object.d.ts +11 -0
- package/dist/types/modules/pdf/core/pdf-stream.d.ts +32 -0
- package/dist/types/modules/pdf/core/pdf-writer.d.ts +55 -1
- package/dist/types/modules/pdf/core/pdfa.d.ts +62 -0
- package/dist/types/modules/pdf/index.d.ts +11 -0
- package/dist/types/modules/pdf/reader/bookmark-extractor.d.ts +35 -0
- package/dist/types/modules/pdf/reader/pdf-reader.d.ts +17 -0
- package/dist/types/modules/pdf/reader/table-extractor.d.ts +69 -0
- package/dist/types/modules/pdf/render/layout-engine.d.ts +21 -1
- package/dist/types/modules/pdf/render/page-renderer.d.ts +2 -9
- package/dist/types/modules/pdf/render/style-converter.d.ts +4 -0
- package/dist/types/modules/pdf/types.d.ts +14 -1
- package/dist/types/utils/crypto.browser.d.ts +64 -0
- package/dist/types/utils/crypto.d.ts +97 -0
- package/package.json +110 -111
- package/dist/browser/modules/pdf/core/crypto.d.ts +0 -65
- package/dist/types/modules/pdf/core/crypto.d.ts +0 -65
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Cryptographic primitives — Browser version.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* Uses Web Crypto API for:
|
|
8
|
+
* - `randomBytes` (crypto.getRandomValues — truly 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
|
|
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
|
|
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 (
|
|
509
|
+
// RC4 (legacy)
|
|
582
510
|
// =============================================================================
|
|
583
511
|
/**
|
|
584
512
|
* RC4 stream cipher.
|
|
585
|
-
* @deprecated Only used for reading legacy encrypted PDFs.
|
|
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
|
|
537
|
+
// Random bytes
|
|
610
538
|
// =============================================================================
|
|
611
539
|
/**
|
|
612
|
-
* Generate
|
|
613
|
-
* Uses
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
593
|
+
export function hash(algorithm, data) {
|
|
594
|
+
const algo = algorithm.toLowerCase().replace(/-/g, "");
|
|
595
|
+
if (algo === "sha256") {
|
|
596
|
+
return sha256(data);
|
|
629
597
|
}
|
|
630
|
-
|
|
631
|
-
|
|
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
|
-
|
|
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>;
|