@gjsify/crypto 0.3.12 → 0.3.14
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/lib/esm/asn1.js +576 -450
- package/lib/esm/bigint-math.js +37 -28
- package/lib/esm/cipher.js +1252 -1229
- package/lib/esm/constants.js +12 -13
- package/lib/esm/crypto-utils.js +54 -36
- package/lib/esm/dh.js +408 -368
- package/lib/esm/ecdh.js +403 -321
- package/lib/esm/ecdsa.js +138 -111
- package/lib/esm/hash.js +100 -89
- package/lib/esm/hkdf.js +65 -47
- package/lib/esm/hmac.js +95 -90
- package/lib/esm/index.js +75 -148
- package/lib/esm/key-object.js +348 -307
- package/lib/esm/mgf1.js +30 -24
- package/lib/esm/pbkdf2.js +66 -59
- package/lib/esm/public-encrypt.js +203 -156
- package/lib/esm/random.js +137 -124
- package/lib/esm/rsa-oaep.js +94 -87
- package/lib/esm/rsa-pss.js +95 -88
- package/lib/esm/scrypt.js +116 -115
- package/lib/esm/sign.js +267 -237
- package/lib/esm/timing-safe-equal.js +16 -11
- package/lib/esm/x509.js +215 -206
- package/package.json +7 -7
package/lib/esm/cipher.js
CHANGED
|
@@ -1,1272 +1,1295 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
|
+
|
|
3
|
+
//#region src/cipher.ts
|
|
2
4
|
const SBOX = new Uint8Array([
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
5
|
+
99,
|
|
6
|
+
124,
|
|
7
|
+
119,
|
|
8
|
+
123,
|
|
9
|
+
242,
|
|
10
|
+
107,
|
|
11
|
+
111,
|
|
12
|
+
197,
|
|
13
|
+
48,
|
|
14
|
+
1,
|
|
15
|
+
103,
|
|
16
|
+
43,
|
|
17
|
+
254,
|
|
18
|
+
215,
|
|
19
|
+
171,
|
|
20
|
+
118,
|
|
21
|
+
202,
|
|
22
|
+
130,
|
|
23
|
+
201,
|
|
24
|
+
125,
|
|
25
|
+
250,
|
|
26
|
+
89,
|
|
27
|
+
71,
|
|
28
|
+
240,
|
|
29
|
+
173,
|
|
30
|
+
212,
|
|
31
|
+
162,
|
|
32
|
+
175,
|
|
33
|
+
156,
|
|
34
|
+
164,
|
|
35
|
+
114,
|
|
36
|
+
192,
|
|
37
|
+
183,
|
|
38
|
+
253,
|
|
39
|
+
147,
|
|
40
|
+
38,
|
|
41
|
+
54,
|
|
42
|
+
63,
|
|
43
|
+
247,
|
|
44
|
+
204,
|
|
45
|
+
52,
|
|
46
|
+
165,
|
|
47
|
+
229,
|
|
48
|
+
241,
|
|
49
|
+
113,
|
|
50
|
+
216,
|
|
51
|
+
49,
|
|
52
|
+
21,
|
|
53
|
+
4,
|
|
54
|
+
199,
|
|
55
|
+
35,
|
|
56
|
+
195,
|
|
57
|
+
24,
|
|
58
|
+
150,
|
|
59
|
+
5,
|
|
60
|
+
154,
|
|
61
|
+
7,
|
|
62
|
+
18,
|
|
63
|
+
128,
|
|
64
|
+
226,
|
|
65
|
+
235,
|
|
66
|
+
39,
|
|
67
|
+
178,
|
|
68
|
+
117,
|
|
69
|
+
9,
|
|
70
|
+
131,
|
|
71
|
+
44,
|
|
72
|
+
26,
|
|
73
|
+
27,
|
|
74
|
+
110,
|
|
75
|
+
90,
|
|
76
|
+
160,
|
|
77
|
+
82,
|
|
78
|
+
59,
|
|
79
|
+
214,
|
|
80
|
+
179,
|
|
81
|
+
41,
|
|
82
|
+
227,
|
|
83
|
+
47,
|
|
84
|
+
132,
|
|
85
|
+
83,
|
|
86
|
+
209,
|
|
87
|
+
0,
|
|
88
|
+
237,
|
|
89
|
+
32,
|
|
90
|
+
252,
|
|
91
|
+
177,
|
|
92
|
+
91,
|
|
93
|
+
106,
|
|
94
|
+
203,
|
|
95
|
+
190,
|
|
96
|
+
57,
|
|
97
|
+
74,
|
|
98
|
+
76,
|
|
99
|
+
88,
|
|
100
|
+
207,
|
|
101
|
+
208,
|
|
102
|
+
239,
|
|
103
|
+
170,
|
|
104
|
+
251,
|
|
105
|
+
67,
|
|
106
|
+
77,
|
|
107
|
+
51,
|
|
108
|
+
133,
|
|
109
|
+
69,
|
|
110
|
+
249,
|
|
111
|
+
2,
|
|
112
|
+
127,
|
|
113
|
+
80,
|
|
114
|
+
60,
|
|
115
|
+
159,
|
|
116
|
+
168,
|
|
117
|
+
81,
|
|
118
|
+
163,
|
|
119
|
+
64,
|
|
120
|
+
143,
|
|
121
|
+
146,
|
|
122
|
+
157,
|
|
123
|
+
56,
|
|
124
|
+
245,
|
|
125
|
+
188,
|
|
126
|
+
182,
|
|
127
|
+
218,
|
|
128
|
+
33,
|
|
129
|
+
16,
|
|
130
|
+
255,
|
|
131
|
+
243,
|
|
132
|
+
210,
|
|
133
|
+
205,
|
|
134
|
+
12,
|
|
135
|
+
19,
|
|
136
|
+
236,
|
|
137
|
+
95,
|
|
138
|
+
151,
|
|
139
|
+
68,
|
|
140
|
+
23,
|
|
141
|
+
196,
|
|
142
|
+
167,
|
|
143
|
+
126,
|
|
144
|
+
61,
|
|
145
|
+
100,
|
|
146
|
+
93,
|
|
147
|
+
25,
|
|
148
|
+
115,
|
|
149
|
+
96,
|
|
150
|
+
129,
|
|
151
|
+
79,
|
|
152
|
+
220,
|
|
153
|
+
34,
|
|
154
|
+
42,
|
|
155
|
+
144,
|
|
156
|
+
136,
|
|
157
|
+
70,
|
|
158
|
+
238,
|
|
159
|
+
184,
|
|
160
|
+
20,
|
|
161
|
+
222,
|
|
162
|
+
94,
|
|
163
|
+
11,
|
|
164
|
+
219,
|
|
165
|
+
224,
|
|
166
|
+
50,
|
|
167
|
+
58,
|
|
168
|
+
10,
|
|
169
|
+
73,
|
|
170
|
+
6,
|
|
171
|
+
36,
|
|
172
|
+
92,
|
|
173
|
+
194,
|
|
174
|
+
211,
|
|
175
|
+
172,
|
|
176
|
+
98,
|
|
177
|
+
145,
|
|
178
|
+
149,
|
|
179
|
+
228,
|
|
180
|
+
121,
|
|
181
|
+
231,
|
|
182
|
+
200,
|
|
183
|
+
55,
|
|
184
|
+
109,
|
|
185
|
+
141,
|
|
186
|
+
213,
|
|
187
|
+
78,
|
|
188
|
+
169,
|
|
189
|
+
108,
|
|
190
|
+
86,
|
|
191
|
+
244,
|
|
192
|
+
234,
|
|
193
|
+
101,
|
|
194
|
+
122,
|
|
195
|
+
174,
|
|
196
|
+
8,
|
|
197
|
+
186,
|
|
198
|
+
120,
|
|
199
|
+
37,
|
|
200
|
+
46,
|
|
201
|
+
28,
|
|
202
|
+
166,
|
|
203
|
+
180,
|
|
204
|
+
198,
|
|
205
|
+
232,
|
|
206
|
+
221,
|
|
207
|
+
116,
|
|
208
|
+
31,
|
|
209
|
+
75,
|
|
210
|
+
189,
|
|
211
|
+
139,
|
|
212
|
+
138,
|
|
213
|
+
112,
|
|
214
|
+
62,
|
|
215
|
+
181,
|
|
216
|
+
102,
|
|
217
|
+
72,
|
|
218
|
+
3,
|
|
219
|
+
246,
|
|
220
|
+
14,
|
|
221
|
+
97,
|
|
222
|
+
53,
|
|
223
|
+
87,
|
|
224
|
+
185,
|
|
225
|
+
134,
|
|
226
|
+
193,
|
|
227
|
+
29,
|
|
228
|
+
158,
|
|
229
|
+
225,
|
|
230
|
+
248,
|
|
231
|
+
152,
|
|
232
|
+
17,
|
|
233
|
+
105,
|
|
234
|
+
217,
|
|
235
|
+
142,
|
|
236
|
+
148,
|
|
237
|
+
155,
|
|
238
|
+
30,
|
|
239
|
+
135,
|
|
240
|
+
233,
|
|
241
|
+
206,
|
|
242
|
+
85,
|
|
243
|
+
40,
|
|
244
|
+
223,
|
|
245
|
+
140,
|
|
246
|
+
161,
|
|
247
|
+
137,
|
|
248
|
+
13,
|
|
249
|
+
191,
|
|
250
|
+
230,
|
|
251
|
+
66,
|
|
252
|
+
104,
|
|
253
|
+
65,
|
|
254
|
+
153,
|
|
255
|
+
45,
|
|
256
|
+
15,
|
|
257
|
+
176,
|
|
258
|
+
84,
|
|
259
|
+
187,
|
|
260
|
+
22
|
|
259
261
|
]);
|
|
260
262
|
const INV_SBOX = new Uint8Array([
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
263
|
+
82,
|
|
264
|
+
9,
|
|
265
|
+
106,
|
|
266
|
+
213,
|
|
267
|
+
48,
|
|
268
|
+
54,
|
|
269
|
+
165,
|
|
270
|
+
56,
|
|
271
|
+
191,
|
|
272
|
+
64,
|
|
273
|
+
163,
|
|
274
|
+
158,
|
|
275
|
+
129,
|
|
276
|
+
243,
|
|
277
|
+
215,
|
|
278
|
+
251,
|
|
279
|
+
124,
|
|
280
|
+
227,
|
|
281
|
+
57,
|
|
282
|
+
130,
|
|
283
|
+
155,
|
|
284
|
+
47,
|
|
285
|
+
255,
|
|
286
|
+
135,
|
|
287
|
+
52,
|
|
288
|
+
142,
|
|
289
|
+
67,
|
|
290
|
+
68,
|
|
291
|
+
196,
|
|
292
|
+
222,
|
|
293
|
+
233,
|
|
294
|
+
203,
|
|
295
|
+
84,
|
|
296
|
+
123,
|
|
297
|
+
148,
|
|
298
|
+
50,
|
|
299
|
+
166,
|
|
300
|
+
194,
|
|
301
|
+
35,
|
|
302
|
+
61,
|
|
303
|
+
238,
|
|
304
|
+
76,
|
|
305
|
+
149,
|
|
306
|
+
11,
|
|
307
|
+
66,
|
|
308
|
+
250,
|
|
309
|
+
195,
|
|
310
|
+
78,
|
|
311
|
+
8,
|
|
312
|
+
46,
|
|
313
|
+
161,
|
|
314
|
+
102,
|
|
315
|
+
40,
|
|
316
|
+
217,
|
|
317
|
+
36,
|
|
318
|
+
178,
|
|
319
|
+
118,
|
|
320
|
+
91,
|
|
321
|
+
162,
|
|
322
|
+
73,
|
|
323
|
+
109,
|
|
324
|
+
139,
|
|
325
|
+
209,
|
|
326
|
+
37,
|
|
327
|
+
114,
|
|
328
|
+
248,
|
|
329
|
+
246,
|
|
330
|
+
100,
|
|
331
|
+
134,
|
|
332
|
+
104,
|
|
333
|
+
152,
|
|
334
|
+
22,
|
|
335
|
+
212,
|
|
336
|
+
164,
|
|
337
|
+
92,
|
|
338
|
+
204,
|
|
339
|
+
93,
|
|
340
|
+
101,
|
|
341
|
+
182,
|
|
342
|
+
146,
|
|
343
|
+
108,
|
|
344
|
+
112,
|
|
345
|
+
72,
|
|
346
|
+
80,
|
|
347
|
+
253,
|
|
348
|
+
237,
|
|
349
|
+
185,
|
|
350
|
+
218,
|
|
351
|
+
94,
|
|
352
|
+
21,
|
|
353
|
+
70,
|
|
354
|
+
87,
|
|
355
|
+
167,
|
|
356
|
+
141,
|
|
357
|
+
157,
|
|
358
|
+
132,
|
|
359
|
+
144,
|
|
360
|
+
216,
|
|
361
|
+
171,
|
|
362
|
+
0,
|
|
363
|
+
140,
|
|
364
|
+
188,
|
|
365
|
+
211,
|
|
366
|
+
10,
|
|
367
|
+
247,
|
|
368
|
+
228,
|
|
369
|
+
88,
|
|
370
|
+
5,
|
|
371
|
+
184,
|
|
372
|
+
179,
|
|
373
|
+
69,
|
|
374
|
+
6,
|
|
375
|
+
208,
|
|
376
|
+
44,
|
|
377
|
+
30,
|
|
378
|
+
143,
|
|
379
|
+
202,
|
|
380
|
+
63,
|
|
381
|
+
15,
|
|
382
|
+
2,
|
|
383
|
+
193,
|
|
384
|
+
175,
|
|
385
|
+
189,
|
|
386
|
+
3,
|
|
387
|
+
1,
|
|
388
|
+
19,
|
|
389
|
+
138,
|
|
390
|
+
107,
|
|
391
|
+
58,
|
|
392
|
+
145,
|
|
393
|
+
17,
|
|
394
|
+
65,
|
|
395
|
+
79,
|
|
396
|
+
103,
|
|
397
|
+
220,
|
|
398
|
+
234,
|
|
399
|
+
151,
|
|
400
|
+
242,
|
|
401
|
+
207,
|
|
402
|
+
206,
|
|
403
|
+
240,
|
|
404
|
+
180,
|
|
405
|
+
230,
|
|
406
|
+
115,
|
|
407
|
+
150,
|
|
408
|
+
172,
|
|
409
|
+
116,
|
|
410
|
+
34,
|
|
411
|
+
231,
|
|
412
|
+
173,
|
|
413
|
+
53,
|
|
414
|
+
133,
|
|
415
|
+
226,
|
|
416
|
+
249,
|
|
417
|
+
55,
|
|
418
|
+
232,
|
|
419
|
+
28,
|
|
420
|
+
117,
|
|
421
|
+
223,
|
|
422
|
+
110,
|
|
423
|
+
71,
|
|
424
|
+
241,
|
|
425
|
+
26,
|
|
426
|
+
113,
|
|
427
|
+
29,
|
|
428
|
+
41,
|
|
429
|
+
197,
|
|
430
|
+
137,
|
|
431
|
+
111,
|
|
432
|
+
183,
|
|
433
|
+
98,
|
|
434
|
+
14,
|
|
435
|
+
170,
|
|
436
|
+
24,
|
|
437
|
+
190,
|
|
438
|
+
27,
|
|
439
|
+
252,
|
|
440
|
+
86,
|
|
441
|
+
62,
|
|
442
|
+
75,
|
|
443
|
+
198,
|
|
444
|
+
210,
|
|
445
|
+
121,
|
|
446
|
+
32,
|
|
447
|
+
154,
|
|
448
|
+
219,
|
|
449
|
+
192,
|
|
450
|
+
254,
|
|
451
|
+
120,
|
|
452
|
+
205,
|
|
453
|
+
90,
|
|
454
|
+
244,
|
|
455
|
+
31,
|
|
456
|
+
221,
|
|
457
|
+
168,
|
|
458
|
+
51,
|
|
459
|
+
136,
|
|
460
|
+
7,
|
|
461
|
+
199,
|
|
462
|
+
49,
|
|
463
|
+
177,
|
|
464
|
+
18,
|
|
465
|
+
16,
|
|
466
|
+
89,
|
|
467
|
+
39,
|
|
468
|
+
128,
|
|
469
|
+
236,
|
|
470
|
+
95,
|
|
471
|
+
96,
|
|
472
|
+
81,
|
|
473
|
+
127,
|
|
474
|
+
169,
|
|
475
|
+
25,
|
|
476
|
+
181,
|
|
477
|
+
74,
|
|
478
|
+
13,
|
|
479
|
+
45,
|
|
480
|
+
229,
|
|
481
|
+
122,
|
|
482
|
+
159,
|
|
483
|
+
147,
|
|
484
|
+
201,
|
|
485
|
+
156,
|
|
486
|
+
239,
|
|
487
|
+
160,
|
|
488
|
+
224,
|
|
489
|
+
59,
|
|
490
|
+
77,
|
|
491
|
+
174,
|
|
492
|
+
42,
|
|
493
|
+
245,
|
|
494
|
+
176,
|
|
495
|
+
200,
|
|
496
|
+
235,
|
|
497
|
+
187,
|
|
498
|
+
60,
|
|
499
|
+
131,
|
|
500
|
+
83,
|
|
501
|
+
153,
|
|
502
|
+
97,
|
|
503
|
+
23,
|
|
504
|
+
43,
|
|
505
|
+
4,
|
|
506
|
+
126,
|
|
507
|
+
186,
|
|
508
|
+
119,
|
|
509
|
+
214,
|
|
510
|
+
38,
|
|
511
|
+
225,
|
|
512
|
+
105,
|
|
513
|
+
20,
|
|
514
|
+
99,
|
|
515
|
+
85,
|
|
516
|
+
33,
|
|
517
|
+
12,
|
|
518
|
+
125
|
|
517
519
|
]);
|
|
518
|
-
const RCON = [
|
|
520
|
+
const RCON = [
|
|
521
|
+
1,
|
|
522
|
+
2,
|
|
523
|
+
4,
|
|
524
|
+
8,
|
|
525
|
+
16,
|
|
526
|
+
32,
|
|
527
|
+
64,
|
|
528
|
+
128,
|
|
529
|
+
27,
|
|
530
|
+
54
|
|
531
|
+
];
|
|
519
532
|
function gmul(a, b) {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
533
|
+
let p = 0;
|
|
534
|
+
for (let i = 0; i < 8; i++) {
|
|
535
|
+
if (b & 1) p ^= a;
|
|
536
|
+
const hi = a & 128;
|
|
537
|
+
a = a << 1 & 255;
|
|
538
|
+
if (hi) a ^= 27;
|
|
539
|
+
b >>= 1;
|
|
540
|
+
}
|
|
541
|
+
return p;
|
|
529
542
|
}
|
|
530
543
|
function keyExpansion(key) {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
544
|
+
const nk = key.length / 4;
|
|
545
|
+
const nr = nk + 6;
|
|
546
|
+
const nw = 4 * (nr + 1);
|
|
547
|
+
const w = new Array(nw);
|
|
548
|
+
for (let i = 0; i < nk; i++) {
|
|
549
|
+
w[i] = new Uint8Array([
|
|
550
|
+
key[4 * i],
|
|
551
|
+
key[4 * i + 1],
|
|
552
|
+
key[4 * i + 2],
|
|
553
|
+
key[4 * i + 3]
|
|
554
|
+
]);
|
|
555
|
+
}
|
|
556
|
+
for (let i = nk; i < nw; i++) {
|
|
557
|
+
let temp = new Uint8Array(w[i - 1]);
|
|
558
|
+
if (i % nk === 0) {
|
|
559
|
+
temp = new Uint8Array([
|
|
560
|
+
SBOX[temp[1]] ^ RCON[i / nk - 1],
|
|
561
|
+
SBOX[temp[2]],
|
|
562
|
+
SBOX[temp[3]],
|
|
563
|
+
SBOX[temp[0]]
|
|
564
|
+
]);
|
|
565
|
+
} else if (nk > 6 && i % nk === 4) {
|
|
566
|
+
temp = new Uint8Array([
|
|
567
|
+
SBOX[temp[0]],
|
|
568
|
+
SBOX[temp[1]],
|
|
569
|
+
SBOX[temp[2]],
|
|
570
|
+
SBOX[temp[3]]
|
|
571
|
+
]);
|
|
572
|
+
}
|
|
573
|
+
w[i] = new Uint8Array(4);
|
|
574
|
+
for (let j = 0; j < 4; j++) w[i][j] = w[i - nk][j] ^ temp[j];
|
|
575
|
+
}
|
|
576
|
+
const roundKeys = [];
|
|
577
|
+
for (let r = 0; r <= nr; r++) {
|
|
578
|
+
const rk = new Uint8Array(16);
|
|
579
|
+
for (let c = 0; c < 4; c++) {
|
|
580
|
+
rk[4 * c] = w[4 * r + c][0];
|
|
581
|
+
rk[4 * c + 1] = w[4 * r + c][1];
|
|
582
|
+
rk[4 * c + 2] = w[4 * r + c][2];
|
|
583
|
+
rk[4 * c + 3] = w[4 * r + c][3];
|
|
584
|
+
}
|
|
585
|
+
roundKeys.push(rk);
|
|
586
|
+
}
|
|
587
|
+
return roundKeys;
|
|
565
588
|
}
|
|
566
589
|
function aesEncryptBlock(block, roundKeys) {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
590
|
+
const state = new Uint8Array(block);
|
|
591
|
+
const nr = roundKeys.length - 1;
|
|
592
|
+
for (let i = 0; i < 16; i++) state[i] ^= roundKeys[0][i];
|
|
593
|
+
for (let round = 1; round < nr; round++) {
|
|
594
|
+
for (let i = 0; i < 16; i++) state[i] = SBOX[state[i]];
|
|
595
|
+
const t1 = state[1];
|
|
596
|
+
state[1] = state[5];
|
|
597
|
+
state[5] = state[9];
|
|
598
|
+
state[9] = state[13];
|
|
599
|
+
state[13] = t1;
|
|
600
|
+
const t2a = state[2];
|
|
601
|
+
const t2b = state[6];
|
|
602
|
+
state[2] = state[10];
|
|
603
|
+
state[6] = state[14];
|
|
604
|
+
state[10] = t2a;
|
|
605
|
+
state[14] = t2b;
|
|
606
|
+
const t3 = state[15];
|
|
607
|
+
state[15] = state[11];
|
|
608
|
+
state[11] = state[7];
|
|
609
|
+
state[7] = state[3];
|
|
610
|
+
state[3] = t3;
|
|
611
|
+
for (let c = 0; c < 4; c++) {
|
|
612
|
+
const i = c * 4;
|
|
613
|
+
const a0 = state[i], a1 = state[i + 1], a2 = state[i + 2], a3 = state[i + 3];
|
|
614
|
+
state[i] = gmul(2, a0) ^ gmul(3, a1) ^ a2 ^ a3;
|
|
615
|
+
state[i + 1] = a0 ^ gmul(2, a1) ^ gmul(3, a2) ^ a3;
|
|
616
|
+
state[i + 2] = a0 ^ a1 ^ gmul(2, a2) ^ gmul(3, a3);
|
|
617
|
+
state[i + 3] = gmul(3, a0) ^ a1 ^ a2 ^ gmul(2, a3);
|
|
618
|
+
}
|
|
619
|
+
for (let i = 0; i < 16; i++) state[i] ^= roundKeys[round][i];
|
|
620
|
+
}
|
|
621
|
+
for (let i = 0; i < 16; i++) state[i] = SBOX[state[i]];
|
|
622
|
+
const t1f = state[1];
|
|
623
|
+
state[1] = state[5];
|
|
624
|
+
state[5] = state[9];
|
|
625
|
+
state[9] = state[13];
|
|
626
|
+
state[13] = t1f;
|
|
627
|
+
const t2af = state[2];
|
|
628
|
+
const t2bf = state[6];
|
|
629
|
+
state[2] = state[10];
|
|
630
|
+
state[6] = state[14];
|
|
631
|
+
state[10] = t2af;
|
|
632
|
+
state[14] = t2bf;
|
|
633
|
+
const t3f = state[15];
|
|
634
|
+
state[15] = state[11];
|
|
635
|
+
state[11] = state[7];
|
|
636
|
+
state[7] = state[3];
|
|
637
|
+
state[3] = t3f;
|
|
638
|
+
for (let i = 0; i < 16; i++) state[i] ^= roundKeys[nr][i];
|
|
639
|
+
return state;
|
|
617
640
|
}
|
|
618
641
|
function aesDecryptBlock(block, roundKeys) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
642
|
+
const state = new Uint8Array(block);
|
|
643
|
+
const nr = roundKeys.length - 1;
|
|
644
|
+
for (let i = 0; i < 16; i++) state[i] ^= roundKeys[nr][i];
|
|
645
|
+
for (let round = nr - 1; round > 0; round--) {
|
|
646
|
+
const t1 = state[13];
|
|
647
|
+
state[13] = state[9];
|
|
648
|
+
state[9] = state[5];
|
|
649
|
+
state[5] = state[1];
|
|
650
|
+
state[1] = t1;
|
|
651
|
+
const t2a = state[10];
|
|
652
|
+
const t2b = state[14];
|
|
653
|
+
state[10] = state[2];
|
|
654
|
+
state[14] = state[6];
|
|
655
|
+
state[2] = t2a;
|
|
656
|
+
state[6] = t2b;
|
|
657
|
+
const t3 = state[3];
|
|
658
|
+
state[3] = state[7];
|
|
659
|
+
state[7] = state[11];
|
|
660
|
+
state[11] = state[15];
|
|
661
|
+
state[15] = t3;
|
|
662
|
+
for (let i = 0; i < 16; i++) state[i] = INV_SBOX[state[i]];
|
|
663
|
+
for (let i = 0; i < 16; i++) state[i] ^= roundKeys[round][i];
|
|
664
|
+
for (let c = 0; c < 4; c++) {
|
|
665
|
+
const i = c * 4;
|
|
666
|
+
const a0 = state[i], a1 = state[i + 1], a2 = state[i + 2], a3 = state[i + 3];
|
|
667
|
+
state[i] = gmul(14, a0) ^ gmul(11, a1) ^ gmul(13, a2) ^ gmul(9, a3);
|
|
668
|
+
state[i + 1] = gmul(9, a0) ^ gmul(14, a1) ^ gmul(11, a2) ^ gmul(13, a3);
|
|
669
|
+
state[i + 2] = gmul(13, a0) ^ gmul(9, a1) ^ gmul(14, a2) ^ gmul(11, a3);
|
|
670
|
+
state[i + 3] = gmul(11, a0) ^ gmul(13, a1) ^ gmul(9, a2) ^ gmul(14, a3);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
const t1f = state[13];
|
|
674
|
+
state[13] = state[9];
|
|
675
|
+
state[9] = state[5];
|
|
676
|
+
state[5] = state[1];
|
|
677
|
+
state[1] = t1f;
|
|
678
|
+
const t2af = state[10];
|
|
679
|
+
const t2bf = state[14];
|
|
680
|
+
state[10] = state[2];
|
|
681
|
+
state[14] = state[6];
|
|
682
|
+
state[2] = t2af;
|
|
683
|
+
state[6] = t2bf;
|
|
684
|
+
const t3f = state[3];
|
|
685
|
+
state[3] = state[7];
|
|
686
|
+
state[7] = state[11];
|
|
687
|
+
state[11] = state[15];
|
|
688
|
+
state[15] = t3f;
|
|
689
|
+
for (let i = 0; i < 16; i++) state[i] = INV_SBOX[state[i]];
|
|
690
|
+
for (let i = 0; i < 16; i++) state[i] ^= roundKeys[0][i];
|
|
691
|
+
return state;
|
|
669
692
|
}
|
|
670
693
|
function incrementCounter(counter) {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
694
|
+
for (let i = 15; i >= 0; i--) {
|
|
695
|
+
if (++counter[i] !== 0) break;
|
|
696
|
+
}
|
|
674
697
|
}
|
|
675
698
|
function gcmIncrementCounter(counter) {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
699
|
+
for (let i = 15; i >= 12; i--) {
|
|
700
|
+
if (++counter[i] !== 0) break;
|
|
701
|
+
}
|
|
679
702
|
}
|
|
703
|
+
/**
|
|
704
|
+
* Multiply two 128-bit values in GF(2^128) using the irreducible polynomial
|
|
705
|
+
* x^128 + x^7 + x^2 + x + 1 (represented as R = 0xe1 << 120).
|
|
706
|
+
*
|
|
707
|
+
* X and Y are 16-byte Uint8Arrays (big-endian bit ordering).
|
|
708
|
+
* Returns a new 16-byte Uint8Array.
|
|
709
|
+
*/
|
|
680
710
|
function gfMul(X, Y) {
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
711
|
+
const Z = new Uint8Array(16);
|
|
712
|
+
const V = new Uint8Array(X);
|
|
713
|
+
for (let i = 0; i < 128; i++) {
|
|
714
|
+
if (Y[i >>> 3] & 1 << 7 - (i & 7)) {
|
|
715
|
+
for (let j = 0; j < 16; j++) Z[j] ^= V[j];
|
|
716
|
+
}
|
|
717
|
+
const lsb = V[15] & 1;
|
|
718
|
+
for (let j = 15; j > 0; j--) {
|
|
719
|
+
V[j] = V[j] >>> 1 | (V[j - 1] & 1) << 7;
|
|
720
|
+
}
|
|
721
|
+
V[0] = V[0] >>> 1;
|
|
722
|
+
if (lsb) {
|
|
723
|
+
V[0] ^= 225;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
return Z;
|
|
697
727
|
}
|
|
728
|
+
/**
|
|
729
|
+
* GHASH function per NIST SP 800-38D.
|
|
730
|
+
*
|
|
731
|
+
* H: the hash subkey (AES_K(0^128)), 16 bytes
|
|
732
|
+
* aad: additional authenticated data (arbitrary length)
|
|
733
|
+
* ciphertext: ciphertext (arbitrary length)
|
|
734
|
+
*
|
|
735
|
+
* Returns a 16-byte authentication hash.
|
|
736
|
+
*/
|
|
698
737
|
function ghash(H, aad, ciphertext) {
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
738
|
+
const X = new Uint8Array(16);
|
|
739
|
+
const aadBlocks = Math.ceil(aad.length / 16) || 0;
|
|
740
|
+
for (let i = 0; i < aadBlocks; i++) {
|
|
741
|
+
const start = i * 16;
|
|
742
|
+
const end = Math.min(start + 16, aad.length);
|
|
743
|
+
for (let j = 0; j < 16; j++) {
|
|
744
|
+
const idx = start + j;
|
|
745
|
+
if (idx < end) {
|
|
746
|
+
X[j] ^= aad[idx];
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
const product = gfMul(X, H);
|
|
750
|
+
X.set(product);
|
|
751
|
+
}
|
|
752
|
+
const ctBlocks = Math.ceil(ciphertext.length / 16) || 0;
|
|
753
|
+
for (let i = 0; i < ctBlocks; i++) {
|
|
754
|
+
const start = i * 16;
|
|
755
|
+
const end = Math.min(start + 16, ciphertext.length);
|
|
756
|
+
for (let j = 0; j < 16; j++) {
|
|
757
|
+
const idx = start + j;
|
|
758
|
+
if (idx < end) {
|
|
759
|
+
X[j] ^= ciphertext[idx];
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
const product = gfMul(X, H);
|
|
763
|
+
X.set(product);
|
|
764
|
+
}
|
|
765
|
+
const lenBlock = new Uint8Array(16);
|
|
766
|
+
const aadBits = aad.length * 8;
|
|
767
|
+
const ctBits = ciphertext.length * 8;
|
|
768
|
+
const aadHi = Math.floor(aadBits / 4294967296);
|
|
769
|
+
const aadLo = aadBits >>> 0;
|
|
770
|
+
lenBlock[0] = aadHi >>> 24 & 255;
|
|
771
|
+
lenBlock[1] = aadHi >>> 16 & 255;
|
|
772
|
+
lenBlock[2] = aadHi >>> 8 & 255;
|
|
773
|
+
lenBlock[3] = aadHi & 255;
|
|
774
|
+
lenBlock[4] = aadLo >>> 24 & 255;
|
|
775
|
+
lenBlock[5] = aadLo >>> 16 & 255;
|
|
776
|
+
lenBlock[6] = aadLo >>> 8 & 255;
|
|
777
|
+
lenBlock[7] = aadLo & 255;
|
|
778
|
+
const ctHi = Math.floor(ctBits / 4294967296);
|
|
779
|
+
const ctLo = ctBits >>> 0;
|
|
780
|
+
lenBlock[8] = ctHi >>> 24 & 255;
|
|
781
|
+
lenBlock[9] = ctHi >>> 16 & 255;
|
|
782
|
+
lenBlock[10] = ctHi >>> 8 & 255;
|
|
783
|
+
lenBlock[11] = ctHi & 255;
|
|
784
|
+
lenBlock[12] = ctLo >>> 24 & 255;
|
|
785
|
+
lenBlock[13] = ctLo >>> 16 & 255;
|
|
786
|
+
lenBlock[14] = ctLo >>> 8 & 255;
|
|
787
|
+
lenBlock[15] = ctLo & 255;
|
|
788
|
+
for (let j = 0; j < 16; j++) X[j] ^= lenBlock[j];
|
|
789
|
+
const product = gfMul(X, H);
|
|
790
|
+
X.set(product);
|
|
791
|
+
return X;
|
|
753
792
|
}
|
|
754
793
|
function parseAlgorithm(algorithm) {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
794
|
+
const lower = algorithm.toLowerCase();
|
|
795
|
+
const match = lower.match(/^aes-(128|192|256)-(cbc|ctr|ecb|cfb|ofb|gcm)$/);
|
|
796
|
+
if (!match) {
|
|
797
|
+
throw new Error(`Unsupported cipher algorithm: ${algorithm}`);
|
|
798
|
+
}
|
|
799
|
+
const keyBits = parseInt(match[1]);
|
|
800
|
+
const mode = match[2];
|
|
801
|
+
return {
|
|
802
|
+
keySize: keyBits / 8,
|
|
803
|
+
ivSize: mode === "ecb" ? 0 : mode === "gcm" ? 12 : 16,
|
|
804
|
+
mode
|
|
805
|
+
};
|
|
767
806
|
}
|
|
768
807
|
function toBuffer(data, encoding) {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
808
|
+
if (typeof data === "string") {
|
|
809
|
+
return Buffer.from(data, encoding || "utf8");
|
|
810
|
+
}
|
|
811
|
+
return Buffer.from(data);
|
|
773
812
|
}
|
|
774
813
|
function encodeOutput(data, encoding) {
|
|
775
|
-
|
|
776
|
-
|
|
814
|
+
if (!encoding) return Buffer.from(data);
|
|
815
|
+
return Buffer.from(data).toString(encoding);
|
|
777
816
|
}
|
|
817
|
+
/**
|
|
818
|
+
* Count how many trailing bytes at the end of a Uint8Array form an incomplete
|
|
819
|
+
* UTF-8 multibyte sequence. Returns 0 if the last character is complete.
|
|
820
|
+
*/
|
|
778
821
|
function incompleteUtf8Tail(buf) {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
822
|
+
if (buf.length === 0) return 0;
|
|
823
|
+
const end = buf.length;
|
|
824
|
+
for (let back = 1; back <= Math.min(4, end); back++) {
|
|
825
|
+
const b = buf[end - back];
|
|
826
|
+
if ((b & 128) === 0) {
|
|
827
|
+
return 0;
|
|
828
|
+
}
|
|
829
|
+
if ((b & 192) === 128) {
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
let expected;
|
|
833
|
+
if ((b & 224) === 192) expected = 2;
|
|
834
|
+
else if ((b & 240) === 224) expected = 3;
|
|
835
|
+
else if ((b & 248) === 240) expected = 4;
|
|
836
|
+
else return 0;
|
|
837
|
+
return back < expected ? back : 0;
|
|
838
|
+
}
|
|
839
|
+
return 0;
|
|
797
840
|
}
|
|
798
841
|
function pkcs7Pad(data) {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
842
|
+
const padLen = 16 - data.length % 16;
|
|
843
|
+
const padded = new Uint8Array(data.length + padLen);
|
|
844
|
+
padded.set(data);
|
|
845
|
+
for (let i = data.length; i < padded.length; i++) padded[i] = padLen;
|
|
846
|
+
return padded;
|
|
804
847
|
}
|
|
805
848
|
function pkcs7Unpad(data) {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
}
|
|
818
|
-
class CipherBase {
|
|
819
|
-
_roundKeys;
|
|
820
|
-
_iv;
|
|
821
|
-
_mode;
|
|
822
|
-
_buffer = new Uint8Array(0);
|
|
823
|
-
_autoPadding = true;
|
|
824
|
-
_finalized = false;
|
|
825
|
-
constructor(algorithm, key, iv) {
|
|
826
|
-
const info = parseAlgorithm(algorithm);
|
|
827
|
-
if (key.length !== info.keySize) {
|
|
828
|
-
throw new Error(`Invalid key length ${key.length}, expected ${info.keySize} for ${algorithm}`);
|
|
829
|
-
}
|
|
830
|
-
if (info.ivSize > 0 && (!iv || iv.length !== info.ivSize)) {
|
|
831
|
-
throw new Error(`Invalid IV length ${iv?.length ?? 0}, expected ${info.ivSize} for ${algorithm}`);
|
|
832
|
-
}
|
|
833
|
-
this._roundKeys = keyExpansion(key);
|
|
834
|
-
this._iv = iv ? new Uint8Array(iv) : new Uint8Array(16);
|
|
835
|
-
this._mode = info.mode;
|
|
836
|
-
}
|
|
837
|
-
setAutoPadding(autoPadding) {
|
|
838
|
-
this._autoPadding = autoPadding;
|
|
839
|
-
return this;
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
class Cipher extends CipherBase {
|
|
843
|
-
_prevBlock;
|
|
844
|
-
_counter;
|
|
845
|
-
// GCM state
|
|
846
|
-
_gcmH = null;
|
|
847
|
-
// Hash subkey H = AES_K(0^128)
|
|
848
|
-
_gcmJ0 = null;
|
|
849
|
-
// Initial counter J0
|
|
850
|
-
_gcmAAD = new Uint8Array(0);
|
|
851
|
-
// Additional authenticated data
|
|
852
|
-
_gcmCiphertext = [];
|
|
853
|
-
// Accumulated ciphertext for GHASH
|
|
854
|
-
_gcmCiphertextLen = 0;
|
|
855
|
-
// Total ciphertext length
|
|
856
|
-
_gcmAuthTag = null;
|
|
857
|
-
// Computed authentication tag
|
|
858
|
-
_gcmAADSet = false;
|
|
859
|
-
// Whether setAAD was called
|
|
860
|
-
constructor(algorithm, key, iv) {
|
|
861
|
-
super(algorithm, key, iv);
|
|
862
|
-
this._prevBlock = new Uint8Array(this._iv);
|
|
863
|
-
if (this._mode === "gcm") {
|
|
864
|
-
this._gcmH = aesEncryptBlock(new Uint8Array(16), this._roundKeys);
|
|
865
|
-
this._gcmJ0 = new Uint8Array(16);
|
|
866
|
-
this._gcmJ0.set(this._iv.subarray(0, 12));
|
|
867
|
-
this._gcmJ0[15] = 1;
|
|
868
|
-
this._counter = new Uint8Array(this._gcmJ0);
|
|
869
|
-
gcmIncrementCounter(this._counter);
|
|
870
|
-
} else {
|
|
871
|
-
this._counter = new Uint8Array(this._iv);
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
/**
|
|
875
|
-
* Set Additional Authenticated Data for GCM mode.
|
|
876
|
-
* Must be called before any update() calls.
|
|
877
|
-
*/
|
|
878
|
-
setAAD(data) {
|
|
879
|
-
if (this._mode !== "gcm") {
|
|
880
|
-
throw new Error("setAAD is only supported in GCM mode");
|
|
881
|
-
}
|
|
882
|
-
if (this._gcmCiphertextLen > 0) {
|
|
883
|
-
throw new Error("setAAD must be called before update()");
|
|
884
|
-
}
|
|
885
|
-
this._gcmAAD = new Uint8Array(data);
|
|
886
|
-
this._gcmAADSet = true;
|
|
887
|
-
return this;
|
|
888
|
-
}
|
|
889
|
-
/**
|
|
890
|
-
* Get the authentication tag after final() has been called.
|
|
891
|
-
* Only valid for GCM mode.
|
|
892
|
-
*/
|
|
893
|
-
getAuthTag() {
|
|
894
|
-
if (this._mode !== "gcm") {
|
|
895
|
-
throw new Error("getAuthTag is only supported in GCM mode");
|
|
896
|
-
}
|
|
897
|
-
if (!this._gcmAuthTag) {
|
|
898
|
-
throw new Error("getAuthTag must be called after final()");
|
|
899
|
-
}
|
|
900
|
-
return Buffer.from(this._gcmAuthTag);
|
|
901
|
-
}
|
|
902
|
-
update(data, inputEncoding, outputEncoding) {
|
|
903
|
-
const input = toBuffer(data, inputEncoding);
|
|
904
|
-
const combined = new Uint8Array(this._buffer.length + input.length);
|
|
905
|
-
combined.set(this._buffer);
|
|
906
|
-
combined.set(input, this._buffer.length);
|
|
907
|
-
if (this._mode === "gcm") {
|
|
908
|
-
const output2 = this._processGcmEncrypt(combined);
|
|
909
|
-
this._buffer = new Uint8Array(0);
|
|
910
|
-
return encodeOutput(output2, outputEncoding);
|
|
911
|
-
}
|
|
912
|
-
if (this._mode === "ctr" || this._mode === "cfb" || this._mode === "ofb") {
|
|
913
|
-
const output2 = this._processStream(combined);
|
|
914
|
-
this._buffer = new Uint8Array(0);
|
|
915
|
-
return encodeOutput(output2, outputEncoding);
|
|
916
|
-
}
|
|
917
|
-
const fullBlocks = Math.floor(combined.length / 16);
|
|
918
|
-
const processLen = fullBlocks * 16;
|
|
919
|
-
const output = [];
|
|
920
|
-
for (let i = 0; i < processLen; i += 16) {
|
|
921
|
-
const block = combined.slice(i, i + 16);
|
|
922
|
-
output.push(this._encryptBlock(block));
|
|
923
|
-
}
|
|
924
|
-
this._buffer = combined.slice(processLen);
|
|
925
|
-
const result = new Uint8Array(output.length * 16);
|
|
926
|
-
for (let i = 0; i < output.length; i++) result.set(output[i], i * 16);
|
|
927
|
-
return encodeOutput(result, outputEncoding);
|
|
928
|
-
}
|
|
929
|
-
final(outputEncoding) {
|
|
930
|
-
if (this._finalized) throw new Error("Cipher already finalized");
|
|
931
|
-
this._finalized = true;
|
|
932
|
-
if (this._mode === "gcm") {
|
|
933
|
-
let finalOutput = new Uint8Array(0);
|
|
934
|
-
if (this._buffer.length > 0) {
|
|
935
|
-
finalOutput = this._processGcmEncrypt(this._buffer);
|
|
936
|
-
this._buffer = new Uint8Array(0);
|
|
937
|
-
}
|
|
938
|
-
const allCiphertext = new Uint8Array(this._gcmCiphertextLen);
|
|
939
|
-
let offset = 0;
|
|
940
|
-
for (const chunk of this._gcmCiphertext) {
|
|
941
|
-
allCiphertext.set(chunk, offset);
|
|
942
|
-
offset += chunk.length;
|
|
943
|
-
}
|
|
944
|
-
const ghashResult = ghash(this._gcmH, this._gcmAAD, allCiphertext);
|
|
945
|
-
const encJ0 = aesEncryptBlock(this._gcmJ0, this._roundKeys);
|
|
946
|
-
const tag = new Uint8Array(16);
|
|
947
|
-
for (let i = 0; i < 16; i++) tag[i] = ghashResult[i] ^ encJ0[i];
|
|
948
|
-
this._gcmAuthTag = Buffer.from(tag);
|
|
949
|
-
return encodeOutput(finalOutput, outputEncoding);
|
|
950
|
-
}
|
|
951
|
-
if (this._mode === "ctr" || this._mode === "cfb" || this._mode === "ofb") {
|
|
952
|
-
if (this._buffer.length > 0) {
|
|
953
|
-
const output2 = this._processStream(this._buffer);
|
|
954
|
-
this._buffer = new Uint8Array(0);
|
|
955
|
-
return encodeOutput(output2, outputEncoding);
|
|
956
|
-
}
|
|
957
|
-
return encodeOutput(new Uint8Array(0), outputEncoding);
|
|
958
|
-
}
|
|
959
|
-
let data = this._buffer;
|
|
960
|
-
if (this._autoPadding) {
|
|
961
|
-
data = pkcs7Pad(data);
|
|
962
|
-
} else if (data.length % 16 !== 0) {
|
|
963
|
-
throw new Error("data not multiple of block size");
|
|
964
|
-
}
|
|
965
|
-
const output = [];
|
|
966
|
-
for (let i = 0; i < data.length; i += 16) {
|
|
967
|
-
output.push(this._encryptBlock(data.slice(i, i + 16)));
|
|
968
|
-
}
|
|
969
|
-
this._buffer = new Uint8Array(0);
|
|
970
|
-
if (output.length === 0) return encodeOutput(new Uint8Array(0), outputEncoding);
|
|
971
|
-
const result = new Uint8Array(output.length * 16);
|
|
972
|
-
for (let i = 0; i < output.length; i++) result.set(output[i], i * 16);
|
|
973
|
-
return encodeOutput(result, outputEncoding);
|
|
974
|
-
}
|
|
975
|
-
_encryptBlock(block) {
|
|
976
|
-
if (this._mode === "cbc") {
|
|
977
|
-
const xored = new Uint8Array(16);
|
|
978
|
-
for (let i = 0; i < 16; i++) xored[i] = block[i] ^ this._prevBlock[i];
|
|
979
|
-
const encrypted = aesEncryptBlock(xored, this._roundKeys);
|
|
980
|
-
this._prevBlock = encrypted;
|
|
981
|
-
return encrypted;
|
|
982
|
-
} else if (this._mode === "ecb") {
|
|
983
|
-
return aesEncryptBlock(block, this._roundKeys);
|
|
984
|
-
}
|
|
985
|
-
throw new Error(`Block encryption not supported for mode: ${this._mode}`);
|
|
986
|
-
}
|
|
987
|
-
_processStream(data) {
|
|
988
|
-
const output = new Uint8Array(data.length);
|
|
989
|
-
for (let i = 0; i < data.length; i += 16) {
|
|
990
|
-
const keystream = aesEncryptBlock(this._counter, this._roundKeys);
|
|
991
|
-
const remaining = Math.min(16, data.length - i);
|
|
992
|
-
for (let j = 0; j < remaining; j++) {
|
|
993
|
-
output[i + j] = data[i + j] ^ keystream[j];
|
|
994
|
-
}
|
|
995
|
-
incrementCounter(this._counter);
|
|
996
|
-
}
|
|
997
|
-
return output;
|
|
998
|
-
}
|
|
999
|
-
/**
|
|
1000
|
-
* GCM encryption: CTR mode encryption, also accumulates ciphertext for GHASH.
|
|
1001
|
-
*/
|
|
1002
|
-
_processGcmEncrypt(data) {
|
|
1003
|
-
const output = new Uint8Array(data.length);
|
|
1004
|
-
for (let i = 0; i < data.length; i += 16) {
|
|
1005
|
-
const keystream = aesEncryptBlock(this._counter, this._roundKeys);
|
|
1006
|
-
const remaining = Math.min(16, data.length - i);
|
|
1007
|
-
for (let j = 0; j < remaining; j++) {
|
|
1008
|
-
output[i + j] = data[i + j] ^ keystream[j];
|
|
1009
|
-
}
|
|
1010
|
-
gcmIncrementCounter(this._counter);
|
|
1011
|
-
}
|
|
1012
|
-
this._gcmCiphertext.push(new Uint8Array(output));
|
|
1013
|
-
this._gcmCiphertextLen += output.length;
|
|
1014
|
-
return output;
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
class Decipher extends CipherBase {
|
|
1018
|
-
_prevBlock;
|
|
1019
|
-
_counter;
|
|
1020
|
-
_pendingUtf8 = new Uint8Array(0);
|
|
1021
|
-
// GCM state
|
|
1022
|
-
_gcmH = null;
|
|
1023
|
-
// Hash subkey H = AES_K(0^128)
|
|
1024
|
-
_gcmJ0 = null;
|
|
1025
|
-
// Initial counter J0
|
|
1026
|
-
_gcmAAD = new Uint8Array(0);
|
|
1027
|
-
// Additional authenticated data
|
|
1028
|
-
_gcmCiphertext = [];
|
|
1029
|
-
// Accumulated ciphertext for GHASH
|
|
1030
|
-
_gcmCiphertextLen = 0;
|
|
1031
|
-
// Total ciphertext length
|
|
1032
|
-
_gcmExpectedTag = null;
|
|
1033
|
-
// Expected authentication tag
|
|
1034
|
-
_gcmAADSet = false;
|
|
1035
|
-
// Whether setAAD was called
|
|
1036
|
-
constructor(algorithm, key, iv) {
|
|
1037
|
-
super(algorithm, key, iv);
|
|
1038
|
-
this._prevBlock = new Uint8Array(this._iv);
|
|
1039
|
-
if (this._mode === "gcm") {
|
|
1040
|
-
this._gcmH = aesEncryptBlock(new Uint8Array(16), this._roundKeys);
|
|
1041
|
-
this._gcmJ0 = new Uint8Array(16);
|
|
1042
|
-
this._gcmJ0.set(this._iv.subarray(0, 12));
|
|
1043
|
-
this._gcmJ0[15] = 1;
|
|
1044
|
-
this._counter = new Uint8Array(this._gcmJ0);
|
|
1045
|
-
gcmIncrementCounter(this._counter);
|
|
1046
|
-
} else {
|
|
1047
|
-
this._counter = new Uint8Array(this._iv);
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
/**
|
|
1051
|
-
* Set Additional Authenticated Data for GCM mode.
|
|
1052
|
-
* Must be called before any update() calls.
|
|
1053
|
-
*/
|
|
1054
|
-
setAAD(data) {
|
|
1055
|
-
if (this._mode !== "gcm") {
|
|
1056
|
-
throw new Error("setAAD is only supported in GCM mode");
|
|
1057
|
-
}
|
|
1058
|
-
if (this._gcmCiphertextLen > 0) {
|
|
1059
|
-
throw new Error("setAAD must be called before update()");
|
|
1060
|
-
}
|
|
1061
|
-
this._gcmAAD = new Uint8Array(data);
|
|
1062
|
-
this._gcmAADSet = true;
|
|
1063
|
-
return this;
|
|
1064
|
-
}
|
|
1065
|
-
/**
|
|
1066
|
-
* Set the expected authentication tag for GCM decryption.
|
|
1067
|
-
* Must be called before final().
|
|
1068
|
-
*/
|
|
1069
|
-
setAuthTag(tag) {
|
|
1070
|
-
if (this._mode !== "gcm") {
|
|
1071
|
-
throw new Error("setAuthTag is only supported in GCM mode");
|
|
1072
|
-
}
|
|
1073
|
-
this._gcmExpectedTag = Buffer.from(tag);
|
|
1074
|
-
return this;
|
|
1075
|
-
}
|
|
1076
|
-
_encodeWithUtf8Handling(bytes, encoding, isFinal) {
|
|
1077
|
-
if (!encoding || encoding !== "utf8" && encoding !== "utf-8") {
|
|
1078
|
-
return encodeOutput(bytes, encoding);
|
|
1079
|
-
}
|
|
1080
|
-
let data;
|
|
1081
|
-
if (this._pendingUtf8.length > 0) {
|
|
1082
|
-
data = new Uint8Array(this._pendingUtf8.length + bytes.length);
|
|
1083
|
-
data.set(this._pendingUtf8);
|
|
1084
|
-
data.set(bytes, this._pendingUtf8.length);
|
|
1085
|
-
this._pendingUtf8 = new Uint8Array(0);
|
|
1086
|
-
} else {
|
|
1087
|
-
data = bytes;
|
|
1088
|
-
}
|
|
1089
|
-
if (!isFinal) {
|
|
1090
|
-
const tail = incompleteUtf8Tail(data);
|
|
1091
|
-
if (tail > 0) {
|
|
1092
|
-
this._pendingUtf8 = new Uint8Array(data.slice(data.length - tail));
|
|
1093
|
-
data = new Uint8Array(data.slice(0, data.length - tail));
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
return Buffer.from(data).toString("utf8");
|
|
1097
|
-
}
|
|
1098
|
-
update(data, inputEncoding, outputEncoding) {
|
|
1099
|
-
const input = toBuffer(data, inputEncoding);
|
|
1100
|
-
const combined = new Uint8Array(this._buffer.length + input.length);
|
|
1101
|
-
combined.set(this._buffer);
|
|
1102
|
-
combined.set(input, this._buffer.length);
|
|
1103
|
-
if (this._mode === "gcm") {
|
|
1104
|
-
this._gcmCiphertext.push(new Uint8Array(combined));
|
|
1105
|
-
this._gcmCiphertextLen += combined.length;
|
|
1106
|
-
const output2 = this._processGcmDecrypt(combined);
|
|
1107
|
-
this._buffer = new Uint8Array(0);
|
|
1108
|
-
return this._encodeWithUtf8Handling(output2, outputEncoding, false);
|
|
1109
|
-
}
|
|
1110
|
-
if (this._mode === "ctr" || this._mode === "cfb" || this._mode === "ofb") {
|
|
1111
|
-
const output2 = this._processStream(combined);
|
|
1112
|
-
this._buffer = new Uint8Array(0);
|
|
1113
|
-
return this._encodeWithUtf8Handling(output2, outputEncoding, false);
|
|
1114
|
-
}
|
|
1115
|
-
const fullBlocks = Math.floor(combined.length / 16);
|
|
1116
|
-
if (fullBlocks === 0) {
|
|
1117
|
-
this._buffer = combined;
|
|
1118
|
-
return this._encodeWithUtf8Handling(new Uint8Array(0), outputEncoding, false);
|
|
1119
|
-
}
|
|
1120
|
-
const processBlocks = this._autoPadding ? fullBlocks - 1 : fullBlocks;
|
|
1121
|
-
const processLen = processBlocks * 16;
|
|
1122
|
-
const output = [];
|
|
1123
|
-
for (let i = 0; i < processLen; i += 16) {
|
|
1124
|
-
const block = combined.slice(i, i + 16);
|
|
1125
|
-
output.push(this._decryptBlock(block));
|
|
1126
|
-
}
|
|
1127
|
-
this._buffer = combined.slice(processLen);
|
|
1128
|
-
const result = new Uint8Array(output.length * 16);
|
|
1129
|
-
for (let i = 0; i < output.length; i++) result.set(output[i], i * 16);
|
|
1130
|
-
return this._encodeWithUtf8Handling(result, outputEncoding, false);
|
|
1131
|
-
}
|
|
1132
|
-
final(outputEncoding) {
|
|
1133
|
-
if (this._finalized) throw new Error("Decipher already finalized");
|
|
1134
|
-
this._finalized = true;
|
|
1135
|
-
if (this._mode === "gcm") {
|
|
1136
|
-
let finalOutput = new Uint8Array(0);
|
|
1137
|
-
if (this._buffer.length > 0) {
|
|
1138
|
-
this._gcmCiphertext.push(new Uint8Array(this._buffer));
|
|
1139
|
-
this._gcmCiphertextLen += this._buffer.length;
|
|
1140
|
-
finalOutput = this._processGcmDecrypt(this._buffer);
|
|
1141
|
-
this._buffer = new Uint8Array(0);
|
|
1142
|
-
}
|
|
1143
|
-
if (!this._gcmExpectedTag) {
|
|
1144
|
-
throw new Error("Unsupported state or unable to authenticate data");
|
|
1145
|
-
}
|
|
1146
|
-
const allCiphertext = new Uint8Array(this._gcmCiphertextLen);
|
|
1147
|
-
let offset = 0;
|
|
1148
|
-
for (const chunk of this._gcmCiphertext) {
|
|
1149
|
-
allCiphertext.set(chunk, offset);
|
|
1150
|
-
offset += chunk.length;
|
|
1151
|
-
}
|
|
1152
|
-
const ghashResult = ghash(this._gcmH, this._gcmAAD, allCiphertext);
|
|
1153
|
-
const encJ0 = aesEncryptBlock(this._gcmJ0, this._roundKeys);
|
|
1154
|
-
const computedTag = new Uint8Array(16);
|
|
1155
|
-
for (let i = 0; i < 16; i++) computedTag[i] = ghashResult[i] ^ encJ0[i];
|
|
1156
|
-
const expectedTag = this._gcmExpectedTag;
|
|
1157
|
-
const tagLen = Math.min(expectedTag.length, 16);
|
|
1158
|
-
let diff = 0;
|
|
1159
|
-
for (let i = 0; i < tagLen; i++) {
|
|
1160
|
-
diff |= computedTag[i] ^ expectedTag[i];
|
|
1161
|
-
}
|
|
1162
|
-
if (diff !== 0) {
|
|
1163
|
-
throw new Error("Unsupported state or unable to authenticate data");
|
|
1164
|
-
}
|
|
1165
|
-
return this._encodeWithUtf8Handling(finalOutput, outputEncoding, true);
|
|
1166
|
-
}
|
|
1167
|
-
if (this._mode === "ctr" || this._mode === "cfb" || this._mode === "ofb") {
|
|
1168
|
-
if (this._buffer.length > 0) {
|
|
1169
|
-
const output2 = this._processStream(this._buffer);
|
|
1170
|
-
this._buffer = new Uint8Array(0);
|
|
1171
|
-
return this._encodeWithUtf8Handling(output2, outputEncoding, true);
|
|
1172
|
-
}
|
|
1173
|
-
return this._encodeWithUtf8Handling(new Uint8Array(0), outputEncoding, true);
|
|
1174
|
-
}
|
|
1175
|
-
if (this._buffer.length === 0) {
|
|
1176
|
-
return this._encodeWithUtf8Handling(new Uint8Array(0), outputEncoding, true);
|
|
1177
|
-
}
|
|
1178
|
-
if (this._buffer.length % 16 !== 0) {
|
|
1179
|
-
throw new Error("bad decrypt");
|
|
1180
|
-
}
|
|
1181
|
-
const output = [];
|
|
1182
|
-
for (let i = 0; i < this._buffer.length; i += 16) {
|
|
1183
|
-
output.push(this._decryptBlock(this._buffer.slice(i, i + 16)));
|
|
1184
|
-
}
|
|
1185
|
-
const combined = new Uint8Array(output.length * 16);
|
|
1186
|
-
for (let i = 0; i < output.length; i++) combined.set(output[i], i * 16);
|
|
1187
|
-
const result = this._autoPadding ? pkcs7Unpad(combined) : combined;
|
|
1188
|
-
this._buffer = new Uint8Array(0);
|
|
1189
|
-
return this._encodeWithUtf8Handling(result, outputEncoding, true);
|
|
1190
|
-
}
|
|
1191
|
-
_decryptBlock(block) {
|
|
1192
|
-
if (this._mode === "cbc") {
|
|
1193
|
-
const decrypted = aesDecryptBlock(block, this._roundKeys);
|
|
1194
|
-
const output = new Uint8Array(16);
|
|
1195
|
-
for (let i = 0; i < 16; i++) output[i] = decrypted[i] ^ this._prevBlock[i];
|
|
1196
|
-
this._prevBlock = new Uint8Array(block);
|
|
1197
|
-
return output;
|
|
1198
|
-
} else if (this._mode === "ecb") {
|
|
1199
|
-
return aesDecryptBlock(block, this._roundKeys);
|
|
1200
|
-
}
|
|
1201
|
-
throw new Error(`Block decryption not supported for mode: ${this._mode}`);
|
|
1202
|
-
}
|
|
1203
|
-
_processStream(data) {
|
|
1204
|
-
const output = new Uint8Array(data.length);
|
|
1205
|
-
for (let i = 0; i < data.length; i += 16) {
|
|
1206
|
-
const keystream = aesEncryptBlock(this._counter, this._roundKeys);
|
|
1207
|
-
const remaining = Math.min(16, data.length - i);
|
|
1208
|
-
for (let j = 0; j < remaining; j++) {
|
|
1209
|
-
output[i + j] = data[i + j] ^ keystream[j];
|
|
1210
|
-
}
|
|
1211
|
-
incrementCounter(this._counter);
|
|
1212
|
-
}
|
|
1213
|
-
return output;
|
|
1214
|
-
}
|
|
1215
|
-
/**
|
|
1216
|
-
* GCM decryption: CTR mode decryption (same as encryption, since CTR is symmetric).
|
|
1217
|
-
*/
|
|
1218
|
-
_processGcmDecrypt(data) {
|
|
1219
|
-
const output = new Uint8Array(data.length);
|
|
1220
|
-
for (let i = 0; i < data.length; i += 16) {
|
|
1221
|
-
const keystream = aesEncryptBlock(this._counter, this._roundKeys);
|
|
1222
|
-
const remaining = Math.min(16, data.length - i);
|
|
1223
|
-
for (let j = 0; j < remaining; j++) {
|
|
1224
|
-
output[i + j] = data[i + j] ^ keystream[j];
|
|
1225
|
-
}
|
|
1226
|
-
gcmIncrementCounter(this._counter);
|
|
1227
|
-
}
|
|
1228
|
-
return output;
|
|
1229
|
-
}
|
|
849
|
+
if (data.length === 0 || data.length % 16 !== 0) {
|
|
850
|
+
throw new Error("bad decrypt");
|
|
851
|
+
}
|
|
852
|
+
const padLen = data[data.length - 1];
|
|
853
|
+
if (padLen === 0 || padLen > 16) {
|
|
854
|
+
throw new Error("bad decrypt");
|
|
855
|
+
}
|
|
856
|
+
for (let i = data.length - padLen; i < data.length; i++) {
|
|
857
|
+
if (data[i] !== padLen) throw new Error("bad decrypt");
|
|
858
|
+
}
|
|
859
|
+
return new Uint8Array(data.slice(0, data.length - padLen));
|
|
1230
860
|
}
|
|
861
|
+
var CipherBase = class {
|
|
862
|
+
_roundKeys;
|
|
863
|
+
_iv;
|
|
864
|
+
_mode;
|
|
865
|
+
_buffer = new Uint8Array(0);
|
|
866
|
+
_autoPadding = true;
|
|
867
|
+
_finalized = false;
|
|
868
|
+
constructor(algorithm, key, iv) {
|
|
869
|
+
const info = parseAlgorithm(algorithm);
|
|
870
|
+
if (key.length !== info.keySize) {
|
|
871
|
+
throw new Error(`Invalid key length ${key.length}, expected ${info.keySize} for ${algorithm}`);
|
|
872
|
+
}
|
|
873
|
+
if (info.ivSize > 0 && (!iv || iv.length !== info.ivSize)) {
|
|
874
|
+
throw new Error(`Invalid IV length ${iv?.length ?? 0}, expected ${info.ivSize} for ${algorithm}`);
|
|
875
|
+
}
|
|
876
|
+
this._roundKeys = keyExpansion(key);
|
|
877
|
+
this._iv = iv ? new Uint8Array(iv) : new Uint8Array(16);
|
|
878
|
+
this._mode = info.mode;
|
|
879
|
+
}
|
|
880
|
+
setAutoPadding(autoPadding) {
|
|
881
|
+
this._autoPadding = autoPadding;
|
|
882
|
+
return this;
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
var Cipher = class extends CipherBase {
|
|
886
|
+
_prevBlock;
|
|
887
|
+
_counter;
|
|
888
|
+
_gcmH = null;
|
|
889
|
+
_gcmJ0 = null;
|
|
890
|
+
_gcmAAD = new Uint8Array(0);
|
|
891
|
+
_gcmCiphertext = [];
|
|
892
|
+
_gcmCiphertextLen = 0;
|
|
893
|
+
_gcmAuthTag = null;
|
|
894
|
+
_gcmAADSet = false;
|
|
895
|
+
constructor(algorithm, key, iv) {
|
|
896
|
+
super(algorithm, key, iv);
|
|
897
|
+
this._prevBlock = new Uint8Array(this._iv);
|
|
898
|
+
if (this._mode === "gcm") {
|
|
899
|
+
this._gcmH = aesEncryptBlock(new Uint8Array(16), this._roundKeys);
|
|
900
|
+
this._gcmJ0 = new Uint8Array(16);
|
|
901
|
+
this._gcmJ0.set(this._iv.subarray(0, 12));
|
|
902
|
+
this._gcmJ0[15] = 1;
|
|
903
|
+
this._counter = new Uint8Array(this._gcmJ0);
|
|
904
|
+
gcmIncrementCounter(this._counter);
|
|
905
|
+
} else {
|
|
906
|
+
this._counter = new Uint8Array(this._iv);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Set Additional Authenticated Data for GCM mode.
|
|
911
|
+
* Must be called before any update() calls.
|
|
912
|
+
*/
|
|
913
|
+
setAAD(data) {
|
|
914
|
+
if (this._mode !== "gcm") {
|
|
915
|
+
throw new Error("setAAD is only supported in GCM mode");
|
|
916
|
+
}
|
|
917
|
+
if (this._gcmCiphertextLen > 0) {
|
|
918
|
+
throw new Error("setAAD must be called before update()");
|
|
919
|
+
}
|
|
920
|
+
this._gcmAAD = new Uint8Array(data);
|
|
921
|
+
this._gcmAADSet = true;
|
|
922
|
+
return this;
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Get the authentication tag after final() has been called.
|
|
926
|
+
* Only valid for GCM mode.
|
|
927
|
+
*/
|
|
928
|
+
getAuthTag() {
|
|
929
|
+
if (this._mode !== "gcm") {
|
|
930
|
+
throw new Error("getAuthTag is only supported in GCM mode");
|
|
931
|
+
}
|
|
932
|
+
if (!this._gcmAuthTag) {
|
|
933
|
+
throw new Error("getAuthTag must be called after final()");
|
|
934
|
+
}
|
|
935
|
+
return Buffer.from(this._gcmAuthTag);
|
|
936
|
+
}
|
|
937
|
+
update(data, inputEncoding, outputEncoding) {
|
|
938
|
+
const input = toBuffer(data, inputEncoding);
|
|
939
|
+
const combined = new Uint8Array(this._buffer.length + input.length);
|
|
940
|
+
combined.set(this._buffer);
|
|
941
|
+
combined.set(input, this._buffer.length);
|
|
942
|
+
if (this._mode === "gcm") {
|
|
943
|
+
const output = this._processGcmEncrypt(combined);
|
|
944
|
+
this._buffer = new Uint8Array(0);
|
|
945
|
+
return encodeOutput(output, outputEncoding);
|
|
946
|
+
}
|
|
947
|
+
if (this._mode === "ctr" || this._mode === "cfb" || this._mode === "ofb") {
|
|
948
|
+
const output = this._processStream(combined);
|
|
949
|
+
this._buffer = new Uint8Array(0);
|
|
950
|
+
return encodeOutput(output, outputEncoding);
|
|
951
|
+
}
|
|
952
|
+
const fullBlocks = Math.floor(combined.length / 16);
|
|
953
|
+
const processLen = fullBlocks * 16;
|
|
954
|
+
const output = [];
|
|
955
|
+
for (let i = 0; i < processLen; i += 16) {
|
|
956
|
+
const block = combined.slice(i, i + 16);
|
|
957
|
+
output.push(this._encryptBlock(block));
|
|
958
|
+
}
|
|
959
|
+
this._buffer = combined.slice(processLen);
|
|
960
|
+
const result = new Uint8Array(output.length * 16);
|
|
961
|
+
for (let i = 0; i < output.length; i++) result.set(output[i], i * 16);
|
|
962
|
+
return encodeOutput(result, outputEncoding);
|
|
963
|
+
}
|
|
964
|
+
final(outputEncoding) {
|
|
965
|
+
if (this._finalized) throw new Error("Cipher already finalized");
|
|
966
|
+
this._finalized = true;
|
|
967
|
+
if (this._mode === "gcm") {
|
|
968
|
+
let finalOutput = new Uint8Array(0);
|
|
969
|
+
if (this._buffer.length > 0) {
|
|
970
|
+
finalOutput = this._processGcmEncrypt(this._buffer);
|
|
971
|
+
this._buffer = new Uint8Array(0);
|
|
972
|
+
}
|
|
973
|
+
const allCiphertext = new Uint8Array(this._gcmCiphertextLen);
|
|
974
|
+
let offset = 0;
|
|
975
|
+
for (const chunk of this._gcmCiphertext) {
|
|
976
|
+
allCiphertext.set(chunk, offset);
|
|
977
|
+
offset += chunk.length;
|
|
978
|
+
}
|
|
979
|
+
const ghashResult = ghash(this._gcmH, this._gcmAAD, allCiphertext);
|
|
980
|
+
const encJ0 = aesEncryptBlock(this._gcmJ0, this._roundKeys);
|
|
981
|
+
const tag = new Uint8Array(16);
|
|
982
|
+
for (let i = 0; i < 16; i++) tag[i] = ghashResult[i] ^ encJ0[i];
|
|
983
|
+
this._gcmAuthTag = Buffer.from(tag);
|
|
984
|
+
return encodeOutput(finalOutput, outputEncoding);
|
|
985
|
+
}
|
|
986
|
+
if (this._mode === "ctr" || this._mode === "cfb" || this._mode === "ofb") {
|
|
987
|
+
if (this._buffer.length > 0) {
|
|
988
|
+
const output = this._processStream(this._buffer);
|
|
989
|
+
this._buffer = new Uint8Array(0);
|
|
990
|
+
return encodeOutput(output, outputEncoding);
|
|
991
|
+
}
|
|
992
|
+
return encodeOutput(new Uint8Array(0), outputEncoding);
|
|
993
|
+
}
|
|
994
|
+
let data = this._buffer;
|
|
995
|
+
if (this._autoPadding) {
|
|
996
|
+
data = pkcs7Pad(data);
|
|
997
|
+
} else if (data.length % 16 !== 0) {
|
|
998
|
+
throw new Error("data not multiple of block size");
|
|
999
|
+
}
|
|
1000
|
+
const output = [];
|
|
1001
|
+
for (let i = 0; i < data.length; i += 16) {
|
|
1002
|
+
output.push(this._encryptBlock(data.slice(i, i + 16)));
|
|
1003
|
+
}
|
|
1004
|
+
this._buffer = new Uint8Array(0);
|
|
1005
|
+
if (output.length === 0) return encodeOutput(new Uint8Array(0), outputEncoding);
|
|
1006
|
+
const result = new Uint8Array(output.length * 16);
|
|
1007
|
+
for (let i = 0; i < output.length; i++) result.set(output[i], i * 16);
|
|
1008
|
+
return encodeOutput(result, outputEncoding);
|
|
1009
|
+
}
|
|
1010
|
+
_encryptBlock(block) {
|
|
1011
|
+
if (this._mode === "cbc") {
|
|
1012
|
+
const xored = new Uint8Array(16);
|
|
1013
|
+
for (let i = 0; i < 16; i++) xored[i] = block[i] ^ this._prevBlock[i];
|
|
1014
|
+
const encrypted = aesEncryptBlock(xored, this._roundKeys);
|
|
1015
|
+
this._prevBlock = encrypted;
|
|
1016
|
+
return encrypted;
|
|
1017
|
+
} else if (this._mode === "ecb") {
|
|
1018
|
+
return aesEncryptBlock(block, this._roundKeys);
|
|
1019
|
+
}
|
|
1020
|
+
throw new Error(`Block encryption not supported for mode: ${this._mode}`);
|
|
1021
|
+
}
|
|
1022
|
+
_processStream(data) {
|
|
1023
|
+
const output = new Uint8Array(data.length);
|
|
1024
|
+
for (let i = 0; i < data.length; i += 16) {
|
|
1025
|
+
const keystream = aesEncryptBlock(this._counter, this._roundKeys);
|
|
1026
|
+
const remaining = Math.min(16, data.length - i);
|
|
1027
|
+
for (let j = 0; j < remaining; j++) {
|
|
1028
|
+
output[i + j] = data[i + j] ^ keystream[j];
|
|
1029
|
+
}
|
|
1030
|
+
incrementCounter(this._counter);
|
|
1031
|
+
}
|
|
1032
|
+
return output;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* GCM encryption: CTR mode encryption, also accumulates ciphertext for GHASH.
|
|
1036
|
+
*/
|
|
1037
|
+
_processGcmEncrypt(data) {
|
|
1038
|
+
const output = new Uint8Array(data.length);
|
|
1039
|
+
for (let i = 0; i < data.length; i += 16) {
|
|
1040
|
+
const keystream = aesEncryptBlock(this._counter, this._roundKeys);
|
|
1041
|
+
const remaining = Math.min(16, data.length - i);
|
|
1042
|
+
for (let j = 0; j < remaining; j++) {
|
|
1043
|
+
output[i + j] = data[i + j] ^ keystream[j];
|
|
1044
|
+
}
|
|
1045
|
+
gcmIncrementCounter(this._counter);
|
|
1046
|
+
}
|
|
1047
|
+
this._gcmCiphertext.push(new Uint8Array(output));
|
|
1048
|
+
this._gcmCiphertextLen += output.length;
|
|
1049
|
+
return output;
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
var Decipher = class extends CipherBase {
|
|
1053
|
+
_prevBlock;
|
|
1054
|
+
_counter;
|
|
1055
|
+
_pendingUtf8 = new Uint8Array(0);
|
|
1056
|
+
_gcmH = null;
|
|
1057
|
+
_gcmJ0 = null;
|
|
1058
|
+
_gcmAAD = new Uint8Array(0);
|
|
1059
|
+
_gcmCiphertext = [];
|
|
1060
|
+
_gcmCiphertextLen = 0;
|
|
1061
|
+
_gcmExpectedTag = null;
|
|
1062
|
+
_gcmAADSet = false;
|
|
1063
|
+
constructor(algorithm, key, iv) {
|
|
1064
|
+
super(algorithm, key, iv);
|
|
1065
|
+
this._prevBlock = new Uint8Array(this._iv);
|
|
1066
|
+
if (this._mode === "gcm") {
|
|
1067
|
+
this._gcmH = aesEncryptBlock(new Uint8Array(16), this._roundKeys);
|
|
1068
|
+
this._gcmJ0 = new Uint8Array(16);
|
|
1069
|
+
this._gcmJ0.set(this._iv.subarray(0, 12));
|
|
1070
|
+
this._gcmJ0[15] = 1;
|
|
1071
|
+
this._counter = new Uint8Array(this._gcmJ0);
|
|
1072
|
+
gcmIncrementCounter(this._counter);
|
|
1073
|
+
} else {
|
|
1074
|
+
this._counter = new Uint8Array(this._iv);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Set Additional Authenticated Data for GCM mode.
|
|
1079
|
+
* Must be called before any update() calls.
|
|
1080
|
+
*/
|
|
1081
|
+
setAAD(data) {
|
|
1082
|
+
if (this._mode !== "gcm") {
|
|
1083
|
+
throw new Error("setAAD is only supported in GCM mode");
|
|
1084
|
+
}
|
|
1085
|
+
if (this._gcmCiphertextLen > 0) {
|
|
1086
|
+
throw new Error("setAAD must be called before update()");
|
|
1087
|
+
}
|
|
1088
|
+
this._gcmAAD = new Uint8Array(data);
|
|
1089
|
+
this._gcmAADSet = true;
|
|
1090
|
+
return this;
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Set the expected authentication tag for GCM decryption.
|
|
1094
|
+
* Must be called before final().
|
|
1095
|
+
*/
|
|
1096
|
+
setAuthTag(tag) {
|
|
1097
|
+
if (this._mode !== "gcm") {
|
|
1098
|
+
throw new Error("setAuthTag is only supported in GCM mode");
|
|
1099
|
+
}
|
|
1100
|
+
this._gcmExpectedTag = Buffer.from(tag);
|
|
1101
|
+
return this;
|
|
1102
|
+
}
|
|
1103
|
+
_encodeWithUtf8Handling(bytes, encoding, isFinal) {
|
|
1104
|
+
if (!encoding || encoding !== "utf8" && encoding !== "utf-8") {
|
|
1105
|
+
return encodeOutput(bytes, encoding);
|
|
1106
|
+
}
|
|
1107
|
+
let data;
|
|
1108
|
+
if (this._pendingUtf8.length > 0) {
|
|
1109
|
+
data = new Uint8Array(this._pendingUtf8.length + bytes.length);
|
|
1110
|
+
data.set(this._pendingUtf8);
|
|
1111
|
+
data.set(bytes, this._pendingUtf8.length);
|
|
1112
|
+
this._pendingUtf8 = new Uint8Array(0);
|
|
1113
|
+
} else {
|
|
1114
|
+
data = bytes;
|
|
1115
|
+
}
|
|
1116
|
+
if (!isFinal) {
|
|
1117
|
+
const tail = incompleteUtf8Tail(data);
|
|
1118
|
+
if (tail > 0) {
|
|
1119
|
+
this._pendingUtf8 = new Uint8Array(data.slice(data.length - tail));
|
|
1120
|
+
data = new Uint8Array(data.slice(0, data.length - tail));
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
return Buffer.from(data).toString("utf8");
|
|
1124
|
+
}
|
|
1125
|
+
update(data, inputEncoding, outputEncoding) {
|
|
1126
|
+
const input = toBuffer(data, inputEncoding);
|
|
1127
|
+
const combined = new Uint8Array(this._buffer.length + input.length);
|
|
1128
|
+
combined.set(this._buffer);
|
|
1129
|
+
combined.set(input, this._buffer.length);
|
|
1130
|
+
if (this._mode === "gcm") {
|
|
1131
|
+
this._gcmCiphertext.push(new Uint8Array(combined));
|
|
1132
|
+
this._gcmCiphertextLen += combined.length;
|
|
1133
|
+
const output = this._processGcmDecrypt(combined);
|
|
1134
|
+
this._buffer = new Uint8Array(0);
|
|
1135
|
+
return this._encodeWithUtf8Handling(output, outputEncoding, false);
|
|
1136
|
+
}
|
|
1137
|
+
if (this._mode === "ctr" || this._mode === "cfb" || this._mode === "ofb") {
|
|
1138
|
+
const output = this._processStream(combined);
|
|
1139
|
+
this._buffer = new Uint8Array(0);
|
|
1140
|
+
return this._encodeWithUtf8Handling(output, outputEncoding, false);
|
|
1141
|
+
}
|
|
1142
|
+
const fullBlocks = Math.floor(combined.length / 16);
|
|
1143
|
+
if (fullBlocks === 0) {
|
|
1144
|
+
this._buffer = combined;
|
|
1145
|
+
return this._encodeWithUtf8Handling(new Uint8Array(0), outputEncoding, false);
|
|
1146
|
+
}
|
|
1147
|
+
const processBlocks = this._autoPadding ? fullBlocks - 1 : fullBlocks;
|
|
1148
|
+
const processLen = processBlocks * 16;
|
|
1149
|
+
const output = [];
|
|
1150
|
+
for (let i = 0; i < processLen; i += 16) {
|
|
1151
|
+
const block = combined.slice(i, i + 16);
|
|
1152
|
+
output.push(this._decryptBlock(block));
|
|
1153
|
+
}
|
|
1154
|
+
this._buffer = combined.slice(processLen);
|
|
1155
|
+
const result = new Uint8Array(output.length * 16);
|
|
1156
|
+
for (let i = 0; i < output.length; i++) result.set(output[i], i * 16);
|
|
1157
|
+
return this._encodeWithUtf8Handling(result, outputEncoding, false);
|
|
1158
|
+
}
|
|
1159
|
+
final(outputEncoding) {
|
|
1160
|
+
if (this._finalized) throw new Error("Decipher already finalized");
|
|
1161
|
+
this._finalized = true;
|
|
1162
|
+
if (this._mode === "gcm") {
|
|
1163
|
+
let finalOutput = new Uint8Array(0);
|
|
1164
|
+
if (this._buffer.length > 0) {
|
|
1165
|
+
this._gcmCiphertext.push(new Uint8Array(this._buffer));
|
|
1166
|
+
this._gcmCiphertextLen += this._buffer.length;
|
|
1167
|
+
finalOutput = this._processGcmDecrypt(this._buffer);
|
|
1168
|
+
this._buffer = new Uint8Array(0);
|
|
1169
|
+
}
|
|
1170
|
+
if (!this._gcmExpectedTag) {
|
|
1171
|
+
throw new Error("Unsupported state or unable to authenticate data");
|
|
1172
|
+
}
|
|
1173
|
+
const allCiphertext = new Uint8Array(this._gcmCiphertextLen);
|
|
1174
|
+
let offset = 0;
|
|
1175
|
+
for (const chunk of this._gcmCiphertext) {
|
|
1176
|
+
allCiphertext.set(chunk, offset);
|
|
1177
|
+
offset += chunk.length;
|
|
1178
|
+
}
|
|
1179
|
+
const ghashResult = ghash(this._gcmH, this._gcmAAD, allCiphertext);
|
|
1180
|
+
const encJ0 = aesEncryptBlock(this._gcmJ0, this._roundKeys);
|
|
1181
|
+
const computedTag = new Uint8Array(16);
|
|
1182
|
+
for (let i = 0; i < 16; i++) computedTag[i] = ghashResult[i] ^ encJ0[i];
|
|
1183
|
+
const expectedTag = this._gcmExpectedTag;
|
|
1184
|
+
const tagLen = Math.min(expectedTag.length, 16);
|
|
1185
|
+
let diff = 0;
|
|
1186
|
+
for (let i = 0; i < tagLen; i++) {
|
|
1187
|
+
diff |= computedTag[i] ^ expectedTag[i];
|
|
1188
|
+
}
|
|
1189
|
+
if (diff !== 0) {
|
|
1190
|
+
throw new Error("Unsupported state or unable to authenticate data");
|
|
1191
|
+
}
|
|
1192
|
+
return this._encodeWithUtf8Handling(finalOutput, outputEncoding, true);
|
|
1193
|
+
}
|
|
1194
|
+
if (this._mode === "ctr" || this._mode === "cfb" || this._mode === "ofb") {
|
|
1195
|
+
if (this._buffer.length > 0) {
|
|
1196
|
+
const output = this._processStream(this._buffer);
|
|
1197
|
+
this._buffer = new Uint8Array(0);
|
|
1198
|
+
return this._encodeWithUtf8Handling(output, outputEncoding, true);
|
|
1199
|
+
}
|
|
1200
|
+
return this._encodeWithUtf8Handling(new Uint8Array(0), outputEncoding, true);
|
|
1201
|
+
}
|
|
1202
|
+
if (this._buffer.length === 0) {
|
|
1203
|
+
return this._encodeWithUtf8Handling(new Uint8Array(0), outputEncoding, true);
|
|
1204
|
+
}
|
|
1205
|
+
if (this._buffer.length % 16 !== 0) {
|
|
1206
|
+
throw new Error("bad decrypt");
|
|
1207
|
+
}
|
|
1208
|
+
const output = [];
|
|
1209
|
+
for (let i = 0; i < this._buffer.length; i += 16) {
|
|
1210
|
+
output.push(this._decryptBlock(this._buffer.slice(i, i + 16)));
|
|
1211
|
+
}
|
|
1212
|
+
const combined = new Uint8Array(output.length * 16);
|
|
1213
|
+
for (let i = 0; i < output.length; i++) combined.set(output[i], i * 16);
|
|
1214
|
+
const result = this._autoPadding ? pkcs7Unpad(combined) : combined;
|
|
1215
|
+
this._buffer = new Uint8Array(0);
|
|
1216
|
+
return this._encodeWithUtf8Handling(result, outputEncoding, true);
|
|
1217
|
+
}
|
|
1218
|
+
_decryptBlock(block) {
|
|
1219
|
+
if (this._mode === "cbc") {
|
|
1220
|
+
const decrypted = aesDecryptBlock(block, this._roundKeys);
|
|
1221
|
+
const output = new Uint8Array(16);
|
|
1222
|
+
for (let i = 0; i < 16; i++) output[i] = decrypted[i] ^ this._prevBlock[i];
|
|
1223
|
+
this._prevBlock = new Uint8Array(block);
|
|
1224
|
+
return output;
|
|
1225
|
+
} else if (this._mode === "ecb") {
|
|
1226
|
+
return aesDecryptBlock(block, this._roundKeys);
|
|
1227
|
+
}
|
|
1228
|
+
throw new Error(`Block decryption not supported for mode: ${this._mode}`);
|
|
1229
|
+
}
|
|
1230
|
+
_processStream(data) {
|
|
1231
|
+
const output = new Uint8Array(data.length);
|
|
1232
|
+
for (let i = 0; i < data.length; i += 16) {
|
|
1233
|
+
const keystream = aesEncryptBlock(this._counter, this._roundKeys);
|
|
1234
|
+
const remaining = Math.min(16, data.length - i);
|
|
1235
|
+
for (let j = 0; j < remaining; j++) {
|
|
1236
|
+
output[i + j] = data[i + j] ^ keystream[j];
|
|
1237
|
+
}
|
|
1238
|
+
incrementCounter(this._counter);
|
|
1239
|
+
}
|
|
1240
|
+
return output;
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* GCM decryption: CTR mode decryption (same as encryption, since CTR is symmetric).
|
|
1244
|
+
*/
|
|
1245
|
+
_processGcmDecrypt(data) {
|
|
1246
|
+
const output = new Uint8Array(data.length);
|
|
1247
|
+
for (let i = 0; i < data.length; i += 16) {
|
|
1248
|
+
const keystream = aesEncryptBlock(this._counter, this._roundKeys);
|
|
1249
|
+
const remaining = Math.min(16, data.length - i);
|
|
1250
|
+
for (let j = 0; j < remaining; j++) {
|
|
1251
|
+
output[i + j] = data[i + j] ^ keystream[j];
|
|
1252
|
+
}
|
|
1253
|
+
gcmIncrementCounter(this._counter);
|
|
1254
|
+
}
|
|
1255
|
+
return output;
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1231
1258
|
function createCipher(_algorithm, _password) {
|
|
1232
|
-
|
|
1259
|
+
throw new Error("crypto.createCipher() is deprecated. Use createCipheriv() instead.");
|
|
1233
1260
|
}
|
|
1234
1261
|
function createCipheriv(algorithm, key, iv) {
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1262
|
+
const keyBuf = typeof key === "string" ? Buffer.from(key) : new Uint8Array(key);
|
|
1263
|
+
const ivBuf = iv == null ? null : typeof iv === "string" ? Buffer.from(iv) : new Uint8Array(iv);
|
|
1264
|
+
return new Cipher(algorithm, keyBuf, ivBuf);
|
|
1238
1265
|
}
|
|
1239
1266
|
function createDecipher(_algorithm, _password) {
|
|
1240
|
-
|
|
1267
|
+
throw new Error("crypto.createDecipher() is deprecated. Use createDecipheriv() instead.");
|
|
1241
1268
|
}
|
|
1242
1269
|
function createDecipheriv(algorithm, key, iv) {
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1270
|
+
const keyBuf = typeof key === "string" ? Buffer.from(key) : new Uint8Array(key);
|
|
1271
|
+
const ivBuf = iv == null ? null : typeof iv === "string" ? Buffer.from(iv) : new Uint8Array(iv);
|
|
1272
|
+
return new Decipher(algorithm, keyBuf, ivBuf);
|
|
1246
1273
|
}
|
|
1247
1274
|
function getCiphers() {
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1275
|
+
return [
|
|
1276
|
+
"aes-128-cbc",
|
|
1277
|
+
"aes-128-ecb",
|
|
1278
|
+
"aes-192-cbc",
|
|
1279
|
+
"aes-192-ecb",
|
|
1280
|
+
"aes-256-cbc",
|
|
1281
|
+
"aes-256-ecb",
|
|
1282
|
+
"aes-128-ctr",
|
|
1283
|
+
"aes-192-ctr",
|
|
1284
|
+
"aes-256-ctr",
|
|
1285
|
+
"aes-128-cfb",
|
|
1286
|
+
"aes-192-cfb",
|
|
1287
|
+
"aes-256-cfb",
|
|
1288
|
+
"aes-128-gcm",
|
|
1289
|
+
"aes-192-gcm",
|
|
1290
|
+
"aes-256-gcm"
|
|
1291
|
+
];
|
|
1265
1292
|
}
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
createDecipher,
|
|
1270
|
-
createDecipheriv,
|
|
1271
|
-
getCiphers
|
|
1272
|
-
};
|
|
1293
|
+
|
|
1294
|
+
//#endregion
|
|
1295
|
+
export { createCipher, createCipheriv, createDecipher, createDecipheriv, getCiphers };
|