@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,16 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Cryptographic primitives — Browser version.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
8
|
+
* Uses Web Crypto API for:
|
|
9
|
+
* - `randomBytes` (crypto.getRandomValues — truly 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.
|
|
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
|
|
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
|
|
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 (
|
|
524
|
+
// RC4 (legacy)
|
|
594
525
|
// =============================================================================
|
|
595
526
|
/**
|
|
596
527
|
* RC4 stream cipher.
|
|
597
|
-
* @deprecated Only used for reading legacy encrypted PDFs.
|
|
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
|
|
552
|
+
// Random bytes
|
|
622
553
|
// =============================================================================
|
|
623
554
|
/**
|
|
624
|
-
* Generate
|
|
625
|
-
* Uses
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
608
|
+
function hash(algorithm, data) {
|
|
609
|
+
const algo = algorithm.toLowerCase().replace(/-/g, "");
|
|
610
|
+
if (algo === "sha256") {
|
|
611
|
+
return sha256(data);
|
|
641
612
|
}
|
|
642
|
-
|
|
643
|
-
|
|
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
|
-
|
|
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
|
+
}
|