react-native-quick-crypto 1.1.3 → 1.1.4
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/QuickCrypto.podspec +2 -2
- package/android/build.gradle +2 -2
- package/lib/commonjs/index.js +4 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/subtle.js +692 -12
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/commonjs/utils/types.js.map +1 -1
- package/lib/module/index.js +4 -4
- package/lib/module/index.js.map +1 -1
- package/lib/module/subtle.js +693 -13
- package/lib/module/subtle.js.map +1 -1
- package/lib/module/utils/types.js.map +1 -1
- package/lib/typescript/index.d.ts +6 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/subtle.d.ts.map +1 -1
- package/lib/typescript/utils/types.d.ts +3 -1
- package/lib/typescript/utils/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +16 -3
- package/src/subtle.ts +736 -26
- package/src/utils/types.ts +5 -0
package/lib/module/subtle.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
4
3
|
import { Buffer as SBuffer } from 'safe-buffer';
|
|
5
4
|
import { KFormatType, KeyEncoding, KeyType, kNamedCurveAliases } from './utils';
|
|
6
5
|
import { Buffer } from '@craftzdog/react-native-buffer';
|
|
7
6
|
import { CryptoKey, KeyObject, PublicKeyObject, PrivateKeyObject, SecretKeyObject } from './keys';
|
|
8
|
-
import { bufferLikeToArrayBuffer } from './utils/conversion';
|
|
7
|
+
import { binaryLikeToArrayBuffer, bufferLikeToArrayBuffer } from './utils/conversion';
|
|
9
8
|
import { argon2Sync } from './argon2';
|
|
10
9
|
import { lazyDOMException } from './utils/errors';
|
|
11
10
|
import { normalizeHashName, HashContext } from './utils/hashnames';
|
|
@@ -76,21 +75,682 @@ function getCanonicalAlgorithmNames() {
|
|
|
76
75
|
}
|
|
77
76
|
return _canonicalAlgorithmNames;
|
|
78
77
|
}
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
|
|
79
|
+
// Per-algorithm WebIDL converter table. Mirrors Node's kAlgorithmDefinitions
|
|
80
|
+
// (lib/internal/crypto/util.js): each (algorithm, operation) pair maps to a
|
|
81
|
+
// dictionary converter name, or null when only the `name` member is required.
|
|
82
|
+
// Operation keys are missing when an algorithm cannot perform that operation,
|
|
83
|
+
// causing `normalizeAlgorithm` to reject the call.
|
|
84
|
+
const kAlgorithmDefinitions = {
|
|
85
|
+
'AES-CBC': {
|
|
86
|
+
generateKey: 'AesKeyGenParams',
|
|
87
|
+
exportKey: null,
|
|
88
|
+
importKey: null,
|
|
89
|
+
encrypt: 'AesCbcParams',
|
|
90
|
+
decrypt: 'AesCbcParams',
|
|
91
|
+
'get key length': 'AesDerivedKeyParams'
|
|
92
|
+
},
|
|
93
|
+
'AES-CTR': {
|
|
94
|
+
generateKey: 'AesKeyGenParams',
|
|
95
|
+
exportKey: null,
|
|
96
|
+
importKey: null,
|
|
97
|
+
encrypt: 'AesCtrParams',
|
|
98
|
+
decrypt: 'AesCtrParams',
|
|
99
|
+
'get key length': 'AesDerivedKeyParams'
|
|
100
|
+
},
|
|
101
|
+
'AES-GCM': {
|
|
102
|
+
generateKey: 'AesKeyGenParams',
|
|
103
|
+
exportKey: null,
|
|
104
|
+
importKey: null,
|
|
105
|
+
encrypt: 'AeadParams',
|
|
106
|
+
decrypt: 'AeadParams',
|
|
107
|
+
'get key length': 'AesDerivedKeyParams'
|
|
108
|
+
},
|
|
109
|
+
'AES-KW': {
|
|
110
|
+
generateKey: 'AesKeyGenParams',
|
|
111
|
+
exportKey: null,
|
|
112
|
+
importKey: null,
|
|
113
|
+
'get key length': 'AesDerivedKeyParams',
|
|
114
|
+
wrapKey: null,
|
|
115
|
+
unwrapKey: null
|
|
116
|
+
},
|
|
117
|
+
'AES-OCB': {
|
|
118
|
+
generateKey: 'AesKeyGenParams',
|
|
119
|
+
exportKey: null,
|
|
120
|
+
importKey: null,
|
|
121
|
+
encrypt: 'AeadParams',
|
|
122
|
+
decrypt: 'AeadParams',
|
|
123
|
+
'get key length': 'AesDerivedKeyParams'
|
|
124
|
+
},
|
|
125
|
+
Argon2d: {
|
|
126
|
+
deriveBits: 'Argon2Params',
|
|
127
|
+
'get key length': null,
|
|
128
|
+
importKey: null
|
|
129
|
+
},
|
|
130
|
+
Argon2i: {
|
|
131
|
+
deriveBits: 'Argon2Params',
|
|
132
|
+
'get key length': null,
|
|
133
|
+
importKey: null
|
|
134
|
+
},
|
|
135
|
+
Argon2id: {
|
|
136
|
+
deriveBits: 'Argon2Params',
|
|
137
|
+
'get key length': null,
|
|
138
|
+
importKey: null
|
|
139
|
+
},
|
|
140
|
+
'ChaCha20-Poly1305': {
|
|
141
|
+
generateKey: null,
|
|
142
|
+
exportKey: null,
|
|
143
|
+
importKey: null,
|
|
144
|
+
encrypt: 'AeadParams',
|
|
145
|
+
decrypt: 'AeadParams',
|
|
146
|
+
'get key length': null
|
|
147
|
+
},
|
|
148
|
+
ECDH: {
|
|
149
|
+
generateKey: 'EcKeyGenParams',
|
|
150
|
+
exportKey: null,
|
|
151
|
+
importKey: 'EcKeyImportParams',
|
|
152
|
+
deriveBits: 'EcdhKeyDeriveParams'
|
|
153
|
+
},
|
|
154
|
+
ECDSA: {
|
|
155
|
+
generateKey: 'EcKeyGenParams',
|
|
156
|
+
exportKey: null,
|
|
157
|
+
importKey: 'EcKeyImportParams',
|
|
158
|
+
sign: 'EcdsaParams',
|
|
159
|
+
verify: 'EcdsaParams'
|
|
160
|
+
},
|
|
161
|
+
Ed25519: {
|
|
162
|
+
generateKey: null,
|
|
163
|
+
exportKey: null,
|
|
164
|
+
importKey: null,
|
|
165
|
+
sign: null,
|
|
166
|
+
verify: null
|
|
167
|
+
},
|
|
168
|
+
Ed448: {
|
|
169
|
+
generateKey: null,
|
|
170
|
+
exportKey: null,
|
|
171
|
+
importKey: null,
|
|
172
|
+
sign: 'ContextParams',
|
|
173
|
+
verify: 'ContextParams'
|
|
174
|
+
},
|
|
175
|
+
HKDF: {
|
|
176
|
+
importKey: null,
|
|
177
|
+
deriveBits: 'HkdfParams',
|
|
178
|
+
'get key length': null
|
|
179
|
+
},
|
|
180
|
+
HMAC: {
|
|
181
|
+
generateKey: 'HmacKeyGenParams',
|
|
182
|
+
exportKey: null,
|
|
183
|
+
importKey: 'HmacImportParams',
|
|
184
|
+
sign: null,
|
|
185
|
+
verify: null,
|
|
186
|
+
'get key length': 'HmacImportParams'
|
|
187
|
+
},
|
|
188
|
+
KMAC128: {
|
|
189
|
+
generateKey: 'KmacKeyGenParams',
|
|
190
|
+
exportKey: null,
|
|
191
|
+
importKey: 'KmacImportParams',
|
|
192
|
+
sign: 'KmacParams',
|
|
193
|
+
verify: 'KmacParams',
|
|
194
|
+
'get key length': 'KmacImportParams'
|
|
195
|
+
},
|
|
196
|
+
KMAC256: {
|
|
197
|
+
generateKey: 'KmacKeyGenParams',
|
|
198
|
+
exportKey: null,
|
|
199
|
+
importKey: 'KmacImportParams',
|
|
200
|
+
sign: 'KmacParams',
|
|
201
|
+
verify: 'KmacParams',
|
|
202
|
+
'get key length': 'KmacImportParams'
|
|
203
|
+
},
|
|
204
|
+
'ML-DSA-44': {
|
|
205
|
+
generateKey: null,
|
|
206
|
+
exportKey: null,
|
|
207
|
+
importKey: null,
|
|
208
|
+
sign: 'ContextParams',
|
|
209
|
+
verify: 'ContextParams'
|
|
210
|
+
},
|
|
211
|
+
'ML-DSA-65': {
|
|
212
|
+
generateKey: null,
|
|
213
|
+
exportKey: null,
|
|
214
|
+
importKey: null,
|
|
215
|
+
sign: 'ContextParams',
|
|
216
|
+
verify: 'ContextParams'
|
|
217
|
+
},
|
|
218
|
+
'ML-DSA-87': {
|
|
219
|
+
generateKey: null,
|
|
220
|
+
exportKey: null,
|
|
221
|
+
importKey: null,
|
|
222
|
+
sign: 'ContextParams',
|
|
223
|
+
verify: 'ContextParams'
|
|
224
|
+
},
|
|
225
|
+
'ML-KEM-512': {
|
|
226
|
+
generateKey: null,
|
|
227
|
+
exportKey: null,
|
|
228
|
+
importKey: null,
|
|
229
|
+
encapsulateBits: null,
|
|
230
|
+
decapsulateBits: null,
|
|
231
|
+
encapsulateKey: null,
|
|
232
|
+
decapsulateKey: null
|
|
233
|
+
},
|
|
234
|
+
'ML-KEM-768': {
|
|
235
|
+
generateKey: null,
|
|
236
|
+
exportKey: null,
|
|
237
|
+
importKey: null,
|
|
238
|
+
encapsulateBits: null,
|
|
239
|
+
decapsulateBits: null,
|
|
240
|
+
encapsulateKey: null,
|
|
241
|
+
decapsulateKey: null
|
|
242
|
+
},
|
|
243
|
+
'ML-KEM-1024': {
|
|
244
|
+
generateKey: null,
|
|
245
|
+
exportKey: null,
|
|
246
|
+
importKey: null,
|
|
247
|
+
encapsulateBits: null,
|
|
248
|
+
decapsulateBits: null,
|
|
249
|
+
encapsulateKey: null,
|
|
250
|
+
decapsulateKey: null
|
|
251
|
+
},
|
|
252
|
+
PBKDF2: {
|
|
253
|
+
importKey: null,
|
|
254
|
+
deriveBits: 'Pbkdf2Params',
|
|
255
|
+
'get key length': null
|
|
256
|
+
},
|
|
257
|
+
'RSA-OAEP': {
|
|
258
|
+
generateKey: 'RsaHashedKeyGenParams',
|
|
259
|
+
exportKey: null,
|
|
260
|
+
importKey: 'RsaHashedImportParams',
|
|
261
|
+
encrypt: 'RsaOaepParams',
|
|
262
|
+
decrypt: 'RsaOaepParams'
|
|
263
|
+
},
|
|
264
|
+
'RSA-PSS': {
|
|
265
|
+
generateKey: 'RsaHashedKeyGenParams',
|
|
266
|
+
exportKey: null,
|
|
267
|
+
importKey: 'RsaHashedImportParams',
|
|
268
|
+
sign: 'RsaPssParams',
|
|
269
|
+
verify: 'RsaPssParams'
|
|
270
|
+
},
|
|
271
|
+
'RSASSA-PKCS1-v1_5': {
|
|
272
|
+
generateKey: 'RsaHashedKeyGenParams',
|
|
273
|
+
exportKey: null,
|
|
274
|
+
importKey: 'RsaHashedImportParams',
|
|
275
|
+
sign: null,
|
|
276
|
+
verify: null
|
|
277
|
+
},
|
|
278
|
+
'SHA-1': {
|
|
279
|
+
digest: null
|
|
280
|
+
},
|
|
281
|
+
'SHA-256': {
|
|
282
|
+
digest: null
|
|
283
|
+
},
|
|
284
|
+
'SHA-384': {
|
|
285
|
+
digest: null
|
|
286
|
+
},
|
|
287
|
+
'SHA-512': {
|
|
288
|
+
digest: null
|
|
289
|
+
},
|
|
290
|
+
'SHA3-256': {
|
|
291
|
+
digest: null
|
|
292
|
+
},
|
|
293
|
+
'SHA3-384': {
|
|
294
|
+
digest: null
|
|
295
|
+
},
|
|
296
|
+
'SHA3-512': {
|
|
297
|
+
digest: null
|
|
298
|
+
},
|
|
299
|
+
cSHAKE128: {
|
|
300
|
+
digest: 'CShakeParams'
|
|
301
|
+
},
|
|
302
|
+
cSHAKE256: {
|
|
303
|
+
digest: 'CShakeParams'
|
|
304
|
+
},
|
|
305
|
+
KT128: {
|
|
306
|
+
digest: 'KangarooTwelveParams'
|
|
307
|
+
},
|
|
308
|
+
KT256: {
|
|
309
|
+
digest: 'KangarooTwelveParams'
|
|
310
|
+
},
|
|
311
|
+
TurboSHAKE128: {
|
|
312
|
+
digest: 'TurboShakeParams'
|
|
313
|
+
},
|
|
314
|
+
TurboSHAKE256: {
|
|
315
|
+
digest: 'TurboShakeParams'
|
|
316
|
+
},
|
|
317
|
+
X25519: {
|
|
318
|
+
generateKey: null,
|
|
319
|
+
exportKey: null,
|
|
320
|
+
importKey: null,
|
|
321
|
+
deriveBits: 'EcdhKeyDeriveParams'
|
|
322
|
+
},
|
|
323
|
+
X448: {
|
|
324
|
+
generateKey: null,
|
|
325
|
+
exportKey: null,
|
|
326
|
+
importKey: null,
|
|
327
|
+
deriveBits: 'EcdhKeyDeriveParams'
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
for (const v of SLH_DSA_VARIANTS) {
|
|
331
|
+
kAlgorithmDefinitions[v] = {
|
|
332
|
+
generateKey: null,
|
|
333
|
+
exportKey: null,
|
|
334
|
+
importKey: null,
|
|
335
|
+
sign: null,
|
|
336
|
+
verify: null
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// WebIDL dictionary member specs. Mirrors Node's per-converter
|
|
341
|
+
// `createDictionaryConverter` definitions in lib/internal/crypto/webidl.js.
|
|
342
|
+
// `required: true` causes `normalizeAlgorithm` to throw a TypeError when the
|
|
343
|
+
// member is missing — matching the spec'd WebCrypto behavior that
|
|
344
|
+
// `SubtleCrypto.supports` relies on via try/catch.
|
|
345
|
+
|
|
346
|
+
const kRequiredFields = {
|
|
347
|
+
AesKeyGenParams: [{
|
|
348
|
+
key: 'length',
|
|
349
|
+
required: true
|
|
350
|
+
}],
|
|
351
|
+
AesDerivedKeyParams: [{
|
|
352
|
+
key: 'length',
|
|
353
|
+
required: true
|
|
354
|
+
}],
|
|
355
|
+
AesCbcParams: [{
|
|
356
|
+
key: 'iv',
|
|
357
|
+
required: true
|
|
358
|
+
}],
|
|
359
|
+
AesCtrParams: [{
|
|
360
|
+
key: 'counter',
|
|
361
|
+
required: true
|
|
362
|
+
}, {
|
|
363
|
+
key: 'length',
|
|
364
|
+
required: true
|
|
365
|
+
}],
|
|
366
|
+
AeadParams: [{
|
|
367
|
+
key: 'iv',
|
|
368
|
+
required: true
|
|
369
|
+
}, {
|
|
370
|
+
key: 'tagLength'
|
|
371
|
+
}, {
|
|
372
|
+
key: 'additionalData'
|
|
373
|
+
}],
|
|
374
|
+
EcKeyGenParams: [{
|
|
375
|
+
key: 'namedCurve',
|
|
376
|
+
required: true
|
|
377
|
+
}],
|
|
378
|
+
EcKeyImportParams: [{
|
|
379
|
+
key: 'namedCurve',
|
|
380
|
+
required: true
|
|
381
|
+
}],
|
|
382
|
+
EcdsaParams: [{
|
|
383
|
+
key: 'hash',
|
|
384
|
+
required: true
|
|
385
|
+
}],
|
|
386
|
+
EcdhKeyDeriveParams: [{
|
|
387
|
+
key: 'public',
|
|
388
|
+
required: true
|
|
389
|
+
}],
|
|
390
|
+
HmacKeyGenParams: [{
|
|
391
|
+
key: 'hash',
|
|
392
|
+
required: true
|
|
393
|
+
}, {
|
|
394
|
+
key: 'length'
|
|
395
|
+
}],
|
|
396
|
+
HmacImportParams: [{
|
|
397
|
+
key: 'hash',
|
|
398
|
+
required: true
|
|
399
|
+
}, {
|
|
400
|
+
key: 'length'
|
|
401
|
+
}],
|
|
402
|
+
HkdfParams: [{
|
|
403
|
+
key: 'hash',
|
|
404
|
+
required: true
|
|
405
|
+
}, {
|
|
406
|
+
key: 'salt',
|
|
407
|
+
required: true
|
|
408
|
+
}, {
|
|
409
|
+
key: 'info',
|
|
410
|
+
required: true
|
|
411
|
+
}],
|
|
412
|
+
Pbkdf2Params: [{
|
|
413
|
+
key: 'hash',
|
|
414
|
+
required: true
|
|
415
|
+
}, {
|
|
416
|
+
key: 'iterations',
|
|
417
|
+
required: true
|
|
418
|
+
}, {
|
|
419
|
+
key: 'salt',
|
|
420
|
+
required: true
|
|
421
|
+
}],
|
|
422
|
+
RsaHashedKeyGenParams: [{
|
|
423
|
+
key: 'modulusLength',
|
|
424
|
+
required: true
|
|
425
|
+
}, {
|
|
426
|
+
key: 'publicExponent',
|
|
427
|
+
required: true
|
|
428
|
+
}, {
|
|
429
|
+
key: 'hash',
|
|
430
|
+
required: true
|
|
431
|
+
}],
|
|
432
|
+
RsaHashedImportParams: [{
|
|
433
|
+
key: 'hash',
|
|
434
|
+
required: true
|
|
435
|
+
}],
|
|
436
|
+
RsaOaepParams: [{
|
|
437
|
+
key: 'label'
|
|
438
|
+
}],
|
|
439
|
+
RsaPssParams: [{
|
|
440
|
+
key: 'saltLength',
|
|
441
|
+
required: true
|
|
442
|
+
}],
|
|
443
|
+
ContextParams: [{
|
|
444
|
+
key: 'context'
|
|
445
|
+
}],
|
|
446
|
+
Argon2Params: [{
|
|
447
|
+
key: 'nonce',
|
|
448
|
+
required: true
|
|
449
|
+
}, {
|
|
450
|
+
key: 'parallelism',
|
|
451
|
+
required: true
|
|
452
|
+
}, {
|
|
453
|
+
key: 'memory',
|
|
454
|
+
required: true
|
|
455
|
+
}, {
|
|
456
|
+
key: 'passes',
|
|
457
|
+
required: true
|
|
458
|
+
}, {
|
|
459
|
+
key: 'version'
|
|
460
|
+
}, {
|
|
461
|
+
key: 'secretValue'
|
|
462
|
+
}, {
|
|
463
|
+
key: 'associatedData'
|
|
464
|
+
}],
|
|
465
|
+
KmacKeyGenParams: [{
|
|
466
|
+
key: 'length'
|
|
467
|
+
}],
|
|
468
|
+
KmacImportParams: [{
|
|
469
|
+
key: 'length'
|
|
470
|
+
}],
|
|
471
|
+
KmacParams: [{
|
|
472
|
+
key: 'outputLength',
|
|
473
|
+
required: true
|
|
474
|
+
}, {
|
|
475
|
+
key: 'customization'
|
|
476
|
+
}],
|
|
477
|
+
CShakeParams: [{
|
|
478
|
+
key: 'outputLength',
|
|
479
|
+
required: true
|
|
480
|
+
}, {
|
|
481
|
+
key: 'functionName'
|
|
482
|
+
}, {
|
|
483
|
+
key: 'customization'
|
|
484
|
+
}],
|
|
485
|
+
KangarooTwelveParams: [{
|
|
486
|
+
key: 'outputLength',
|
|
487
|
+
required: true
|
|
488
|
+
}, {
|
|
489
|
+
key: 'customization'
|
|
490
|
+
}],
|
|
491
|
+
TurboShakeParams: [{
|
|
492
|
+
key: 'outputLength',
|
|
493
|
+
required: true
|
|
494
|
+
}, {
|
|
495
|
+
key: 'domainSeparation'
|
|
496
|
+
}]
|
|
497
|
+
};
|
|
498
|
+
function isBufferSource(value) {
|
|
499
|
+
return value instanceof ArrayBuffer || ArrayBuffer.isView(value);
|
|
500
|
+
}
|
|
501
|
+
function validateBufferSource(algorithm, key) {
|
|
502
|
+
const value = algorithm[key];
|
|
503
|
+
if (value === undefined) return undefined;
|
|
504
|
+
if (!isBufferSource(value)) {
|
|
505
|
+
throw new TypeError(`Failed to normalize algorithm: '${key}' must be a BufferSource`);
|
|
506
|
+
}
|
|
507
|
+
return bufferLikeToArrayBuffer(value);
|
|
508
|
+
}
|
|
509
|
+
function validateBinaryLike(algorithm, key) {
|
|
510
|
+
const value = algorithm[key];
|
|
511
|
+
if (value === undefined) return undefined;
|
|
512
|
+
try {
|
|
513
|
+
return binaryLikeToArrayBuffer(value);
|
|
514
|
+
} catch {
|
|
515
|
+
throw new TypeError(`Failed to normalize algorithm: '${key}' must be a BufferSource`);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
function validateByteLength(buffer, key, length, message) {
|
|
519
|
+
if (buffer !== undefined && buffer.byteLength !== length) {
|
|
520
|
+
throw lazyDOMException(message ?? `${key} must be ${length} bytes`, 'OperationError');
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
function validateUnsignedInteger(algorithm, key) {
|
|
524
|
+
const value = algorithm[key];
|
|
525
|
+
if (value === undefined) return undefined;
|
|
526
|
+
const numberValue = Number(value);
|
|
527
|
+
if (!Number.isFinite(numberValue) || !Number.isInteger(numberValue) || numberValue < 0) {
|
|
528
|
+
throw new TypeError(`Failed to normalize algorithm: '${key}' must be an unsigned integer`);
|
|
529
|
+
}
|
|
530
|
+
algorithm[key] = numberValue;
|
|
531
|
+
return numberValue;
|
|
532
|
+
}
|
|
533
|
+
function validateHashAlgorithm(algorithm, converterName) {
|
|
534
|
+
const hash = algorithm.hash;
|
|
535
|
+
if (hash === undefined) return;
|
|
536
|
+
const normalizedHash = normalizeHashName(hash, HashContext.WebCrypto);
|
|
537
|
+
if (!['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512', 'SHA3-256', 'SHA3-384', 'SHA3-512'].includes(normalizedHash)) {
|
|
538
|
+
throw lazyDOMException(`Unsupported ${converterName}.hash`, 'NotSupportedError');
|
|
539
|
+
}
|
|
540
|
+
algorithm.hash = {
|
|
541
|
+
name: normalizedHash
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
function validateAesLength(length) {
|
|
545
|
+
if (length !== undefined && length !== 128 && length !== 192 && length !== 256) {
|
|
546
|
+
throw lazyDOMException('Invalid key length', 'OperationError');
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
function validateMacLength(algorithm, key, zeroError) {
|
|
550
|
+
const length = validateUnsignedInteger(algorithm, key);
|
|
551
|
+
if (length === undefined) return;
|
|
552
|
+
if (length === 0) {
|
|
553
|
+
throw lazyDOMException(`${key} cannot be 0`, zeroError);
|
|
554
|
+
}
|
|
555
|
+
if (length % 8) {
|
|
556
|
+
throw lazyDOMException(`Unsupported ${key}`, 'NotSupportedError');
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
function validateAeadParams(algorithm) {
|
|
560
|
+
const iv = validateBufferSource(algorithm, 'iv');
|
|
561
|
+
const tagLength = validateUnsignedInteger(algorithm, 'tagLength');
|
|
562
|
+
validateBufferSource(algorithm, 'additionalData');
|
|
563
|
+
switch (algorithm.name) {
|
|
564
|
+
case 'AES-GCM':
|
|
565
|
+
if (tagLength !== undefined && ![32, 64, 96, 104, 112, 120, 128].includes(tagLength)) {
|
|
566
|
+
throw lazyDOMException(`${tagLength} is not a valid AES-GCM tag length`, 'OperationError');
|
|
567
|
+
}
|
|
568
|
+
break;
|
|
569
|
+
case 'AES-OCB':
|
|
570
|
+
if (iv !== undefined && (iv.byteLength < 1 || iv.byteLength > 15)) {
|
|
571
|
+
throw lazyDOMException('AES-OCB algorithm.iv must be between 1 and 15 bytes', 'OperationError');
|
|
572
|
+
}
|
|
573
|
+
if (tagLength !== undefined && ![64, 96, 128].includes(tagLength)) {
|
|
574
|
+
throw lazyDOMException(`${tagLength} is not a valid AES-OCB tag length`, 'OperationError');
|
|
575
|
+
}
|
|
576
|
+
break;
|
|
577
|
+
case 'ChaCha20-Poly1305':
|
|
578
|
+
validateByteLength(iv, 'algorithm.iv', 12, 'ChaCha20-Poly1305 IV must be exactly 12 bytes');
|
|
579
|
+
if (tagLength !== undefined && tagLength !== 128) {
|
|
580
|
+
throw lazyDOMException(`${tagLength} is not a valid ChaCha20-Poly1305 tag length`, 'OperationError');
|
|
581
|
+
}
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
function validateNormalizedAlgorithm(converterName, algorithm) {
|
|
586
|
+
switch (converterName) {
|
|
587
|
+
case 'AesKeyGenParams':
|
|
588
|
+
case 'AesDerivedKeyParams':
|
|
589
|
+
validateAesLength(validateUnsignedInteger(algorithm, 'length'));
|
|
590
|
+
break;
|
|
591
|
+
case 'AesCbcParams':
|
|
592
|
+
validateByteLength(validateBufferSource(algorithm, 'iv'), 'algorithm.iv', 16, 'algorithm.iv must contain exactly 16 bytes');
|
|
593
|
+
break;
|
|
594
|
+
case 'AesCtrParams':
|
|
595
|
+
{
|
|
596
|
+
validateByteLength(validateBufferSource(algorithm, 'counter'), 'algorithm.counter', 16);
|
|
597
|
+
const length = validateUnsignedInteger(algorithm, 'length');
|
|
598
|
+
if (length !== undefined && (length === 0 || length > 128)) {
|
|
599
|
+
throw lazyDOMException('AES-CTR algorithm.length must be between 1 and 128', 'OperationError');
|
|
600
|
+
}
|
|
601
|
+
break;
|
|
602
|
+
}
|
|
603
|
+
case 'AeadParams':
|
|
604
|
+
validateAeadParams(algorithm);
|
|
605
|
+
break;
|
|
606
|
+
case 'EcdsaParams':
|
|
607
|
+
case 'HmacKeyGenParams':
|
|
608
|
+
case 'HmacImportParams':
|
|
609
|
+
case 'HkdfParams':
|
|
610
|
+
case 'Pbkdf2Params':
|
|
611
|
+
case 'RsaHashedKeyGenParams':
|
|
612
|
+
case 'RsaHashedImportParams':
|
|
613
|
+
validateHashAlgorithm(algorithm, converterName);
|
|
614
|
+
if (converterName === 'HmacKeyGenParams') {
|
|
615
|
+
validateMacLength(algorithm, 'length', 'OperationError');
|
|
616
|
+
}
|
|
617
|
+
if (converterName === 'HkdfParams') {
|
|
618
|
+
validateBinaryLike(algorithm, 'salt');
|
|
619
|
+
validateBinaryLike(algorithm, 'info');
|
|
620
|
+
} else if (converterName === 'Pbkdf2Params') {
|
|
621
|
+
const iterations = validateUnsignedInteger(algorithm, 'iterations');
|
|
622
|
+
if (iterations === 0) {
|
|
623
|
+
throw lazyDOMException('iterations cannot be zero', 'OperationError');
|
|
624
|
+
}
|
|
625
|
+
validateBinaryLike(algorithm, 'salt');
|
|
626
|
+
} else if (converterName === 'RsaHashedKeyGenParams') {
|
|
627
|
+
validateUnsignedInteger(algorithm, 'modulusLength');
|
|
628
|
+
validateBufferSource(algorithm, 'publicExponent');
|
|
629
|
+
}
|
|
630
|
+
break;
|
|
631
|
+
case 'RsaPssParams':
|
|
632
|
+
validateUnsignedInteger(algorithm, 'saltLength');
|
|
633
|
+
break;
|
|
634
|
+
case 'RsaOaepParams':
|
|
635
|
+
validateBufferSource(algorithm, 'label');
|
|
636
|
+
break;
|
|
637
|
+
case 'ContextParams':
|
|
638
|
+
validateBufferSource(algorithm, 'context');
|
|
639
|
+
break;
|
|
640
|
+
case 'EcdhKeyDeriveParams':
|
|
641
|
+
if (!(algorithm.public instanceof CryptoKey)) {
|
|
642
|
+
throw lazyDOMException('algorithm.public must be a public key', 'InvalidAccessError');
|
|
643
|
+
}
|
|
644
|
+
break;
|
|
645
|
+
case 'Argon2Params':
|
|
646
|
+
{
|
|
647
|
+
validateBufferSource(algorithm, 'nonce');
|
|
648
|
+
const parallelism = validateUnsignedInteger(algorithm, 'parallelism');
|
|
649
|
+
const memory = validateUnsignedInteger(algorithm, 'memory');
|
|
650
|
+
validateUnsignedInteger(algorithm, 'passes');
|
|
651
|
+
const version = validateUnsignedInteger(algorithm, 'version');
|
|
652
|
+
validateBufferSource(algorithm, 'secretValue');
|
|
653
|
+
validateBufferSource(algorithm, 'associatedData');
|
|
654
|
+
if (parallelism !== undefined && (parallelism === 0 || parallelism > 2 ** 24 - 1)) {
|
|
655
|
+
throw lazyDOMException('parallelism must be > 0 and < 16777215', 'OperationError');
|
|
656
|
+
}
|
|
657
|
+
if (memory !== undefined && parallelism !== undefined && memory < 8 * parallelism) {
|
|
658
|
+
throw lazyDOMException('memory must be at least 8 times the degree of parallelism', 'OperationError');
|
|
659
|
+
}
|
|
660
|
+
if (version !== undefined && version !== 0x13) {
|
|
661
|
+
throw lazyDOMException(`${version} is not a valid Argon2 version`, 'OperationError');
|
|
662
|
+
}
|
|
663
|
+
break;
|
|
664
|
+
}
|
|
665
|
+
case 'KmacKeyGenParams':
|
|
666
|
+
validateMacLength(algorithm, 'length', 'OperationError');
|
|
667
|
+
break;
|
|
668
|
+
case 'KmacImportParams':
|
|
669
|
+
validateMacLength(algorithm, 'length', 'DataError');
|
|
670
|
+
break;
|
|
671
|
+
case 'KmacParams':
|
|
672
|
+
validateMacLength(algorithm, 'outputLength', 'OperationError');
|
|
673
|
+
validateBufferSource(algorithm, 'customization');
|
|
674
|
+
break;
|
|
675
|
+
case 'CShakeParams':
|
|
676
|
+
case 'KangarooTwelveParams':
|
|
677
|
+
{
|
|
678
|
+
const outputLength = validateUnsignedInteger(algorithm, 'outputLength');
|
|
679
|
+
if (outputLength !== undefined && (outputLength === 0 || outputLength % 8)) {
|
|
680
|
+
throw lazyDOMException(`Invalid ${converterName} outputLength`, 'OperationError');
|
|
681
|
+
}
|
|
682
|
+
validateBufferSource(algorithm, 'functionName');
|
|
683
|
+
validateBufferSource(algorithm, 'customization');
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
case 'TurboShakeParams':
|
|
687
|
+
{
|
|
688
|
+
const outputLength = validateUnsignedInteger(algorithm, 'outputLength');
|
|
689
|
+
const domainSeparation = validateUnsignedInteger(algorithm, 'domainSeparation');
|
|
690
|
+
if (outputLength !== undefined && (outputLength === 0 || outputLength % 8)) {
|
|
691
|
+
throw lazyDOMException('Invalid TurboShakeParams outputLength', 'OperationError');
|
|
692
|
+
}
|
|
693
|
+
if (domainSeparation !== undefined && (domainSeparation < 0x01 || domainSeparation > 0x7f)) {
|
|
694
|
+
throw lazyDOMException('TurboShakeParams.domainSeparation must be in range 0x01-0x7f', 'OperationError');
|
|
695
|
+
}
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// WebCrypto §18.4.4 algorithm normalization. Mirrors Node's normalizeAlgorithm
|
|
702
|
+
// in lib/internal/crypto/util.js: canonicalizes `name`, looks up the
|
|
703
|
+
// (name, op) → converter mapping, and rejects inputs that omit required
|
|
704
|
+
// dictionary members. Callers in Subtle.supports rely on this throwing for
|
|
705
|
+
// invalid params — without it, supports() over-reports capability (#1025).
|
|
706
|
+
function normalizeAlgorithm(algorithm, operation) {
|
|
81
707
|
if (typeof algorithm === 'string') {
|
|
708
|
+
return normalizeAlgorithm({
|
|
709
|
+
name: algorithm
|
|
710
|
+
}, operation);
|
|
711
|
+
}
|
|
712
|
+
const name = algorithm.name;
|
|
713
|
+
if (typeof name !== 'string') {
|
|
714
|
+
throw new TypeError("Algorithm: 'name' is required");
|
|
715
|
+
}
|
|
716
|
+
const map = getCanonicalAlgorithmNames();
|
|
717
|
+
const canonical = map.get(name.toLowerCase());
|
|
718
|
+
if (canonical === undefined) {
|
|
719
|
+
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
|
|
720
|
+
}
|
|
721
|
+
const opMap = kAlgorithmDefinitions[canonical];
|
|
722
|
+
if (!opMap || !(operation in opMap)) {
|
|
723
|
+
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
|
|
724
|
+
}
|
|
725
|
+
const converterName = opMap[operation];
|
|
726
|
+
if (converterName == null) {
|
|
82
727
|
return {
|
|
83
|
-
name:
|
|
728
|
+
name: canonical
|
|
84
729
|
};
|
|
85
730
|
}
|
|
86
|
-
|
|
87
|
-
|
|
731
|
+
const fields = kRequiredFields[converterName];
|
|
732
|
+
if (!fields) {
|
|
88
733
|
return {
|
|
89
734
|
...algorithm,
|
|
90
735
|
name: canonical
|
|
91
736
|
};
|
|
92
737
|
}
|
|
93
|
-
|
|
738
|
+
const out = {
|
|
739
|
+
name: canonical
|
|
740
|
+
};
|
|
741
|
+
const src = algorithm;
|
|
742
|
+
for (const field of fields) {
|
|
743
|
+
const value = src[field.key];
|
|
744
|
+
if (value === undefined) {
|
|
745
|
+
if (field.required) {
|
|
746
|
+
throw new TypeError(`Failed to normalize algorithm: '${field.key}' is required in '${converterName}'`);
|
|
747
|
+
}
|
|
748
|
+
continue;
|
|
749
|
+
}
|
|
750
|
+
out[field.key] = value;
|
|
751
|
+
}
|
|
752
|
+
validateNormalizedAlgorithm(converterName, out);
|
|
753
|
+
return out;
|
|
94
754
|
}
|
|
95
755
|
function getAlgorithmName(name, length) {
|
|
96
756
|
switch (name) {
|
|
@@ -1967,7 +2627,6 @@ export class Subtle {
|
|
|
1967
2627
|
}
|
|
1968
2628
|
async deriveBits(algorithm, baseKey, length = null) {
|
|
1969
2629
|
requireArgs(arguments.length, 2, 'deriveBits');
|
|
1970
|
-
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'deriveBits');
|
|
1971
2630
|
// WebCrypto §SubtleCrypto.deriveBits step 11: throw InvalidAccessError
|
|
1972
2631
|
// unless `baseKey.[[usages]]` contains "deriveBits" specifically. The
|
|
1973
2632
|
// previous `deriveBits || deriveKey` accept-either branch silently
|
|
@@ -1976,6 +2635,7 @@ export class Subtle {
|
|
|
1976
2635
|
if (!baseKey.usages.includes('deriveBits')) {
|
|
1977
2636
|
throw lazyDOMException('baseKey does not have deriveBits usage', 'InvalidAccessError');
|
|
1978
2637
|
}
|
|
2638
|
+
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'deriveBits');
|
|
1979
2639
|
if (baseKey.algorithm.name !== normalizedAlgorithm.name) {
|
|
1980
2640
|
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
|
1981
2641
|
}
|
|
@@ -2009,7 +2669,9 @@ export class Subtle {
|
|
|
2009
2669
|
async deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages) {
|
|
2010
2670
|
requireArgs(arguments.length, 5, 'deriveKey');
|
|
2011
2671
|
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'deriveBits');
|
|
2012
|
-
|
|
2672
|
+
// Validate the derived-key algorithm up front (mirrors Node webcrypto.js:341).
|
|
2673
|
+
// The normalized form is unused — `this.importKey` re-normalizes below.
|
|
2674
|
+
normalizeAlgorithm(derivedKeyAlgorithm, 'importKey');
|
|
2013
2675
|
|
|
2014
2676
|
// Validate baseKey usage
|
|
2015
2677
|
if (!baseKey.usages.includes('deriveKey')) {
|
|
@@ -2020,7 +2682,10 @@ export class Subtle {
|
|
|
2020
2682
|
}
|
|
2021
2683
|
|
|
2022
2684
|
// Calculate required key length (may be null for KDF-derived material).
|
|
2023
|
-
|
|
2685
|
+
// Mirrors Node webcrypto.js:350 — uses the raw derivedKeyAlgorithm with
|
|
2686
|
+
// op='get key length' so AES `length` survives normalization (the
|
|
2687
|
+
// 'importKey' converter for AES is null and strips dictionary members).
|
|
2688
|
+
const length = getKeyLength(normalizeAlgorithm(derivedKeyAlgorithm, 'get key length'));
|
|
2024
2689
|
|
|
2025
2690
|
// Step 1: Derive bits
|
|
2026
2691
|
let derivedBits;
|
|
@@ -2100,7 +2765,15 @@ export class Subtle {
|
|
|
2100
2765
|
}
|
|
2101
2766
|
async wrapKey(format, key, wrappingKey, wrapAlgorithm) {
|
|
2102
2767
|
requireArgs(arguments.length, 4, 'wrapKey');
|
|
2103
|
-
|
|
2768
|
+
// Mirrors Node webcrypto.js:923-927: prefer the 'wrapKey' op (only
|
|
2769
|
+
// AES-KW defines it) and fall back to 'encrypt' for cipher-based wrap
|
|
2770
|
+
// algorithms like AES-GCM and RSA-OAEP.
|
|
2771
|
+
let normalizedWrapAlgorithm;
|
|
2772
|
+
try {
|
|
2773
|
+
normalizedWrapAlgorithm = normalizeAlgorithm(wrapAlgorithm, 'wrapKey');
|
|
2774
|
+
} catch {
|
|
2775
|
+
normalizedWrapAlgorithm = normalizeAlgorithm(wrapAlgorithm, 'encrypt');
|
|
2776
|
+
}
|
|
2104
2777
|
if (normalizedWrapAlgorithm.name !== wrappingKey.algorithm.name) {
|
|
2105
2778
|
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
|
2106
2779
|
}
|
|
@@ -2139,7 +2812,14 @@ export class Subtle {
|
|
|
2139
2812
|
}
|
|
2140
2813
|
async unwrapKey(format, wrappedKey, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages) {
|
|
2141
2814
|
requireArgs(arguments.length, 7, 'unwrapKey');
|
|
2142
|
-
|
|
2815
|
+
// Mirrors Node webcrypto.js:1006-1010: prefer 'unwrapKey', fall back to
|
|
2816
|
+
// 'decrypt' for cipher-based unwrap algorithms.
|
|
2817
|
+
let normalizedUnwrapAlgorithm;
|
|
2818
|
+
try {
|
|
2819
|
+
normalizedUnwrapAlgorithm = normalizeAlgorithm(unwrapAlgorithm, 'unwrapKey');
|
|
2820
|
+
} catch {
|
|
2821
|
+
normalizedUnwrapAlgorithm = normalizeAlgorithm(unwrapAlgorithm, 'decrypt');
|
|
2822
|
+
}
|
|
2143
2823
|
if (normalizedUnwrapAlgorithm.name !== unwrappingKey.algorithm.name) {
|
|
2144
2824
|
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
|
|
2145
2825
|
}
|