react-native-quick-crypto 1.0.1 → 1.0.2

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.
@@ -17,7 +17,7 @@ import { rsa_generateKeyPair } from './rsa';
17
17
  import { getRandomValues } from './random';
18
18
  import { createHmac } from './hmac';
19
19
  import { createSign, createVerify } from './keys/signVerify';
20
- import { ed_generateKeyPairWebCrypto, Ed } from './ed';
20
+ import { ed_generateKeyPairWebCrypto, x_generateKeyPairWebCrypto, xDeriveBits, Ed } from './ed';
21
21
  import { mldsa_generateKeyPairWebCrypto } from './mldsa';
22
22
  // import { pbkdf2DeriveBits } from './pbkdf2';
23
23
  // import { aesCipher, aesGenerateKey, aesImportKey, getAlgorithmName } from './aes';
@@ -267,6 +267,120 @@ async function aesGcmCipher(mode, key, data, algorithm) {
267
267
  return result.buffer;
268
268
  }
269
269
  }
270
+ async function aesKwCipher(mode, key, data) {
271
+ const isWrap = mode === CipherOrWrapMode.kWebCryptoCipherEncrypt;
272
+
273
+ // AES-KW requires input to be a multiple of 8 bytes (64 bits)
274
+ if (data.byteLength % 8 !== 0) {
275
+ throw lazyDOMException(`AES-KW input length must be a multiple of 8 bytes, got ${data.byteLength}`, 'OperationError');
276
+ }
277
+
278
+ // AES-KW requires at least 16 bytes of input (128 bits)
279
+ if (isWrap && data.byteLength < 16) {
280
+ throw lazyDOMException(`AES-KW input must be at least 16 bytes, got ${data.byteLength}`, 'OperationError');
281
+ }
282
+
283
+ // Get cipher type based on key length
284
+ const keyLength = key.algorithm.length;
285
+ // Use aes*-wrap for both operations (matching Node.js)
286
+ const cipherType = `aes${keyLength}-wrap`;
287
+
288
+ // Export key material
289
+ const exportedKey = key.keyObject.export();
290
+ const cipherKey = bufferLikeToArrayBuffer(exportedKey);
291
+
292
+ // AES-KW uses a default IV as specified in RFC 3394
293
+ const defaultWrapIV = new Uint8Array([0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6]);
294
+ const factory = NitroModules.createHybridObject('CipherFactory');
295
+ const cipher = factory.createCipher({
296
+ isCipher: isWrap,
297
+ cipherType,
298
+ cipherKey,
299
+ iv: defaultWrapIV.buffer // RFC 3394 default IV for AES-KW
300
+ });
301
+
302
+ // Process data
303
+ const updated = cipher.update(data);
304
+ const final = cipher.final();
305
+
306
+ // Concatenate results
307
+ const result = new Uint8Array(updated.byteLength + final.byteLength);
308
+ result.set(new Uint8Array(updated), 0);
309
+ result.set(new Uint8Array(final), updated.byteLength);
310
+ return result.buffer;
311
+ }
312
+ async function chaCha20Poly1305Cipher(mode, key, data, algorithm) {
313
+ const {
314
+ iv,
315
+ additionalData,
316
+ tagLength = 128
317
+ } = algorithm;
318
+
319
+ // Validate IV (must be 12 bytes for ChaCha20-Poly1305)
320
+ const ivBuffer = bufferLikeToArrayBuffer(iv);
321
+ if (!ivBuffer || ivBuffer.byteLength !== 12) {
322
+ throw lazyDOMException('ChaCha20-Poly1305 IV must be exactly 12 bytes', 'OperationError');
323
+ }
324
+
325
+ // Validate tag length (only 128-bit supported)
326
+ if (tagLength !== 128) {
327
+ throw lazyDOMException('ChaCha20-Poly1305 only supports 128-bit auth tags', 'NotSupportedError');
328
+ }
329
+ const tagByteLength = 16; // 128 bits = 16 bytes
330
+
331
+ // Create cipher using existing ChaCha20-Poly1305 implementation
332
+ const factory = NitroModules.createHybridObject('CipherFactory');
333
+ const cipher = factory.createCipher({
334
+ isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
335
+ cipherType: 'chacha20-poly1305',
336
+ cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
337
+ iv: ivBuffer,
338
+ authTagLen: tagByteLength
339
+ });
340
+ let processData;
341
+ let authTag;
342
+ if (mode === CipherOrWrapMode.kWebCryptoCipherDecrypt) {
343
+ // For decryption, extract auth tag from end of data
344
+ const dataView = new Uint8Array(data);
345
+ if (dataView.byteLength < tagByteLength) {
346
+ throw lazyDOMException('The provided data is too small.', 'OperationError');
347
+ }
348
+
349
+ // Split data and tag
350
+ const ciphertextLength = dataView.byteLength - tagByteLength;
351
+ processData = dataView.slice(0, ciphertextLength).buffer;
352
+ authTag = dataView.slice(ciphertextLength).buffer;
353
+
354
+ // Set auth tag for verification
355
+ cipher.setAuthTag(authTag);
356
+ } else {
357
+ processData = data;
358
+ }
359
+
360
+ // Set additional authenticated data if provided
361
+ if (additionalData) {
362
+ cipher.setAAD(bufferLikeToArrayBuffer(additionalData));
363
+ }
364
+
365
+ // Process data
366
+ const updated = cipher.update(processData);
367
+ const final = cipher.final();
368
+ if (mode === CipherOrWrapMode.kWebCryptoCipherEncrypt) {
369
+ // For encryption, append auth tag to result
370
+ const tag = cipher.getAuthTag();
371
+ const result = new Uint8Array(updated.byteLength + final.byteLength + tag.byteLength);
372
+ result.set(new Uint8Array(updated), 0);
373
+ result.set(new Uint8Array(final), updated.byteLength);
374
+ result.set(new Uint8Array(tag), updated.byteLength + final.byteLength);
375
+ return result.buffer;
376
+ } else {
377
+ // For decryption, just concatenate plaintext
378
+ const result = new Uint8Array(updated.byteLength + final.byteLength);
379
+ result.set(new Uint8Array(updated), 0);
380
+ result.set(new Uint8Array(final), updated.byteLength);
381
+ return result.buffer;
382
+ }
383
+ }
270
384
  async function aesGenerateKey(algorithm, extractable, keyUsages) {
271
385
  const {
272
386
  length
@@ -554,7 +668,9 @@ function edImportKey(format, data, algorithm, extractable, keyUsages) {
554
668
  } = algorithm;
555
669
 
556
670
  // Validate usages
557
- if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
671
+ const isX = name === 'X25519' || name === 'X448';
672
+ const allowedUsages = isX ? ['deriveKey', 'deriveBits'] : ['sign', 'verify'];
673
+ if (hasAnyNotIn(keyUsages, allowedUsages)) {
558
674
  throw lazyDOMException(`Unsupported key usage for ${name} key`, 'SyntaxError');
559
675
  }
560
676
  let keyObject;
@@ -627,8 +743,12 @@ const exportKeySpki = async key => {
627
743
  case 'Ed25519':
628
744
  // Fall through
629
745
  case 'Ed448':
746
+ // Fall through
747
+ case 'X25519':
748
+ // Fall through
749
+ case 'X448':
630
750
  if (key.type === 'public') {
631
- // Export Ed key in SPKI DER format
751
+ // Export Ed/X key in SPKI DER format
632
752
  return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI));
633
753
  }
634
754
  break;
@@ -666,8 +786,12 @@ const exportKeyPkcs8 = async key => {
666
786
  case 'Ed25519':
667
787
  // Fall through
668
788
  case 'Ed448':
789
+ // Fall through
790
+ case 'X25519':
791
+ // Fall through
792
+ case 'X448':
669
793
  if (key.type === 'private') {
670
- // Export Ed key in PKCS8 DER format
794
+ // Export Ed/X key in PKCS8 DER format
671
795
  return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8));
672
796
  }
673
797
  break;
@@ -693,6 +817,19 @@ const exportKeyRaw = key => {
693
817
  return ecExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatRaw);
694
818
  }
695
819
  break;
820
+ case 'Ed25519':
821
+ // Fall through
822
+ case 'Ed448':
823
+ // Fall through
824
+ case 'X25519':
825
+ // Fall through
826
+ case 'X448':
827
+ if (key.type === 'public') {
828
+ // Export raw public key
829
+ const exported = key.keyObject.handle.exportKey();
830
+ return bufferLikeToArrayBuffer(exported);
831
+ }
832
+ break;
696
833
  case 'AES-CTR':
697
834
  // Fall through
698
835
  case 'AES-CBC':
@@ -701,6 +838,8 @@ const exportKeyRaw = key => {
701
838
  // Fall through
702
839
  case 'AES-KW':
703
840
  // Fall through
841
+ case 'ChaCha20-Poly1305':
842
+ // Fall through
704
843
  case 'HMAC':
705
844
  {
706
845
  const exported = key.keyObject.export();
@@ -740,6 +879,8 @@ const exportKeyJWK = key => {
740
879
  case 'AES-GCM':
741
880
  // Fall through
742
881
  case 'AES-KW':
882
+ // Fall through
883
+ case 'ChaCha20-Poly1305':
743
884
  if (key.algorithm.length === undefined) {
744
885
  throw lazyDOMException(`Algorithm ${key.algorithm.name} missing required length property`, 'InvalidAccessError');
745
886
  }
@@ -937,6 +1078,10 @@ const cipherOrWrap = async (mode, algorithm, key, data, op) => {
937
1078
  // Fall through
938
1079
  case 'AES-GCM':
939
1080
  return aesCipher(mode, key, data, algorithm);
1081
+ case 'AES-KW':
1082
+ return aesKwCipher(mode, key, data);
1083
+ case 'ChaCha20-Poly1305':
1084
+ return chaCha20Poly1305Cipher(mode, key, data, algorithm);
940
1085
  }
941
1086
  };
942
1087
  export class Subtle {
@@ -949,16 +1094,49 @@ export class Subtle {
949
1094
  return asyncDigest(normalizedAlgorithm, data);
950
1095
  }
951
1096
  async deriveBits(algorithm, baseKey, length) {
952
- if (!baseKey.keyUsages.includes('deriveBits')) {
953
- throw new Error('baseKey does not have deriveBits usage');
1097
+ // Allow either deriveBits OR deriveKey usage (WebCrypto spec allows both)
1098
+ if (!baseKey.keyUsages.includes('deriveBits') && !baseKey.keyUsages.includes('deriveKey')) {
1099
+ throw new Error('baseKey does not have deriveBits or deriveKey usage');
954
1100
  }
955
1101
  if (baseKey.algorithm.name !== algorithm.name) throw new Error('Key algorithm mismatch');
956
1102
  switch (algorithm.name) {
957
1103
  case 'PBKDF2':
958
1104
  return pbkdf2DeriveBits(algorithm, baseKey, length);
1105
+ case 'X25519':
1106
+ // Fall through
1107
+ case 'X448':
1108
+ return xDeriveBits(algorithm, baseKey, length);
959
1109
  }
960
1110
  throw new Error(`'subtle.deriveBits()' for ${algorithm.name} is not implemented.`);
961
1111
  }
1112
+ async deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages) {
1113
+ // Validate baseKey usage
1114
+ if (!baseKey.usages.includes('deriveKey') && !baseKey.usages.includes('deriveBits')) {
1115
+ throw lazyDOMException('baseKey does not have deriveKey or deriveBits usage', 'InvalidAccessError');
1116
+ }
1117
+
1118
+ // Calculate required key length
1119
+ const length = getKeyLength(derivedKeyAlgorithm);
1120
+
1121
+ // Step 1: Derive bits
1122
+ let derivedBits;
1123
+ if (baseKey.algorithm.name !== algorithm.name) throw new Error('Key algorithm mismatch');
1124
+ switch (algorithm.name) {
1125
+ case 'PBKDF2':
1126
+ derivedBits = await pbkdf2DeriveBits(algorithm, baseKey, length);
1127
+ break;
1128
+ case 'X25519':
1129
+ // Fall through
1130
+ case 'X448':
1131
+ derivedBits = await xDeriveBits(algorithm, baseKey, length);
1132
+ break;
1133
+ default:
1134
+ throw new Error(`'subtle.deriveKey()' for ${algorithm.name} is not implemented.`);
1135
+ }
1136
+
1137
+ // Step 2: Import as key
1138
+ return this.importKey('raw', derivedBits, derivedKeyAlgorithm, extractable, keyUsages);
1139
+ }
962
1140
  async encrypt(algorithm, key, data) {
963
1141
  const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'encrypt');
964
1142
  return cipherOrWrap(CipherOrWrapMode.kWebCryptoCipherEncrypt, normalizedAlgorithm, key, bufferLikeToArrayBuffer(data), 'encrypt');
@@ -976,6 +1154,76 @@ export class Subtle {
976
1154
  return exportKeyRaw(key);
977
1155
  }
978
1156
  }
1157
+ async wrapKey(format, key, wrappingKey, wrapAlgorithm) {
1158
+ // Validate wrappingKey usage
1159
+ if (!wrappingKey.usages.includes('wrapKey')) {
1160
+ throw lazyDOMException('wrappingKey does not have wrapKey usage', 'InvalidAccessError');
1161
+ }
1162
+
1163
+ // Step 1: Export the key
1164
+ const exported = await this.exportKey(format, key);
1165
+
1166
+ // Step 2: Convert to ArrayBuffer if JWK
1167
+ let keyData;
1168
+ if (format === 'jwk') {
1169
+ const jwkString = JSON.stringify(exported);
1170
+ const buffer = SBuffer.from(jwkString, 'utf8');
1171
+
1172
+ // For AES-KW, pad to multiple of 8 bytes (accounting for null terminator)
1173
+ if (wrapAlgorithm.name === 'AES-KW') {
1174
+ const length = buffer.length;
1175
+ // Add 1 for null terminator, then pad to multiple of 8
1176
+ const paddedLength = Math.ceil((length + 1) / 8) * 8;
1177
+ const paddedBuffer = SBuffer.alloc(paddedLength);
1178
+ buffer.copy(paddedBuffer);
1179
+ // Null terminator for JSON string (remaining bytes are already zeros from alloc)
1180
+ paddedBuffer.writeUInt8(0, length);
1181
+ keyData = bufferLikeToArrayBuffer(paddedBuffer);
1182
+ } else {
1183
+ keyData = bufferLikeToArrayBuffer(buffer);
1184
+ }
1185
+ } else {
1186
+ keyData = exported;
1187
+ }
1188
+
1189
+ // Step 3: Encrypt the exported key
1190
+ return cipherOrWrap(CipherOrWrapMode.kWebCryptoCipherEncrypt, wrapAlgorithm, wrappingKey, keyData, 'wrapKey');
1191
+ }
1192
+ async unwrapKey(format, wrappedKey, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages) {
1193
+ // Validate unwrappingKey usage
1194
+ if (!unwrappingKey.usages.includes('unwrapKey')) {
1195
+ throw lazyDOMException('unwrappingKey does not have unwrapKey usage', 'InvalidAccessError');
1196
+ }
1197
+
1198
+ // Step 1: Decrypt the wrapped key
1199
+ const decrypted = await cipherOrWrap(CipherOrWrapMode.kWebCryptoCipherDecrypt, unwrapAlgorithm, unwrappingKey, bufferLikeToArrayBuffer(wrappedKey), 'unwrapKey');
1200
+
1201
+ // Step 2: Convert to appropriate format
1202
+ let keyData;
1203
+ if (format === 'jwk') {
1204
+ const buffer = SBuffer.from(decrypted);
1205
+ // For AES-KW, the data may be padded - find the null terminator
1206
+ let jwkString;
1207
+ if (unwrapAlgorithm.name === 'AES-KW') {
1208
+ // Find the null terminator (if present) to get the original string
1209
+ const nullIndex = buffer.indexOf(0);
1210
+ if (nullIndex !== -1) {
1211
+ jwkString = buffer.toString('utf8', 0, nullIndex);
1212
+ } else {
1213
+ // No null terminator, try to parse the whole buffer
1214
+ jwkString = buffer.toString('utf8').trim();
1215
+ }
1216
+ } else {
1217
+ jwkString = buffer.toString('utf8');
1218
+ }
1219
+ keyData = JSON.parse(jwkString);
1220
+ } else {
1221
+ keyData = decrypted;
1222
+ }
1223
+
1224
+ // Step 3: Import the key
1225
+ return this.importKey(format, keyData, unwrappedKeyAlgorithm, extractable, keyUsages);
1226
+ }
979
1227
  async generateKey(algorithm, extractable, keyUsages) {
980
1228
  algorithm = normalizeAlgorithm(algorithm, 'generateKey');
981
1229
  let result;
@@ -1002,6 +1250,18 @@ export class Subtle {
1002
1250
  case 'AES-KW':
1003
1251
  result = await aesGenerateKey(algorithm, extractable, keyUsages);
1004
1252
  break;
1253
+ case 'ChaCha20-Poly1305':
1254
+ {
1255
+ const length = algorithm.length ?? 256;
1256
+ if (length !== 256) {
1257
+ throw lazyDOMException('ChaCha20-Poly1305 only supports 256-bit keys', 'NotSupportedError');
1258
+ }
1259
+ result = await aesGenerateKey({
1260
+ name: 'ChaCha20-Poly1305',
1261
+ length: 256
1262
+ }, extractable, keyUsages);
1263
+ break;
1264
+ }
1005
1265
  case 'HMAC':
1006
1266
  result = await hmacGenerateKey(algorithm, extractable, keyUsages);
1007
1267
  break;
@@ -1019,6 +1279,12 @@ export class Subtle {
1019
1279
  result = await mldsa_generateKeyPairWebCrypto(algorithm.name, extractable, keyUsages);
1020
1280
  checkCryptoKeyPairUsages(result);
1021
1281
  break;
1282
+ case 'X25519':
1283
+ // Fall through
1284
+ case 'X448':
1285
+ result = await x_generateKeyPairWebCrypto(algorithm.name.toLowerCase(), extractable, keyUsages);
1286
+ checkCryptoKeyPairUsages(result);
1287
+ break;
1022
1288
  default:
1023
1289
  throw new Error(`'subtle.generateKey()' is not implemented for ${algorithm.name}.
1024
1290
  Unrecognized algorithm name`);
@@ -1051,11 +1317,17 @@ export class Subtle {
1051
1317
  case 'AES-GCM':
1052
1318
  // Fall through
1053
1319
  case 'AES-KW':
1320
+ // Fall through
1321
+ case 'ChaCha20-Poly1305':
1054
1322
  result = await aesImportKey(normalizedAlgorithm, format, data, extractable, keyUsages);
1055
1323
  break;
1056
1324
  case 'PBKDF2':
1057
1325
  result = await importGenericSecretKey(normalizedAlgorithm, format, data, extractable, keyUsages);
1058
1326
  break;
1327
+ case 'X25519':
1328
+ // Fall through
1329
+ case 'X448':
1330
+ // Fall through
1059
1331
  case 'Ed25519':
1060
1332
  // Fall through
1061
1333
  case 'Ed448':
@@ -1077,11 +1349,104 @@ export class Subtle {
1077
1349
  return result;
1078
1350
  }
1079
1351
  async sign(algorithm, key, data) {
1080
- return signVerify(algorithm, key, data);
1352
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'sign');
1353
+ if (normalizedAlgorithm.name === 'HMAC') {
1354
+ // Validate key usage
1355
+ if (!key.usages.includes('sign')) {
1356
+ throw lazyDOMException('Key does not have sign usage', 'InvalidAccessError');
1357
+ }
1358
+
1359
+ // Get hash algorithm from key or algorithm params
1360
+ // Hash can be either a string or an object with name property
1361
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1362
+ const alg = normalizedAlgorithm;
1363
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1364
+ const keyAlg = key.algorithm;
1365
+ let hashAlgorithm = 'SHA-256';
1366
+ if (typeof alg.hash === 'string') {
1367
+ hashAlgorithm = alg.hash;
1368
+ } else if (alg.hash?.name) {
1369
+ hashAlgorithm = alg.hash.name;
1370
+ } else if (typeof keyAlg.hash === 'string') {
1371
+ hashAlgorithm = keyAlg.hash;
1372
+ } else if (keyAlg.hash?.name) {
1373
+ hashAlgorithm = keyAlg.hash.name;
1374
+ }
1375
+
1376
+ // Create HMAC and sign
1377
+ const keyData = key.keyObject.export();
1378
+ const hmac = createHmac(hashAlgorithm, keyData);
1379
+ hmac.update(bufferLikeToArrayBuffer(data));
1380
+ return bufferLikeToArrayBuffer(hmac.digest());
1381
+ }
1382
+ return signVerify(normalizedAlgorithm, key, data);
1081
1383
  }
1082
1384
  async verify(algorithm, key, signature, data) {
1083
- return signVerify(algorithm, key, data, signature);
1385
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'verify');
1386
+ if (normalizedAlgorithm.name === 'HMAC') {
1387
+ // Validate key usage
1388
+ if (!key.usages.includes('verify')) {
1389
+ throw lazyDOMException('Key does not have verify usage', 'InvalidAccessError');
1390
+ }
1391
+
1392
+ // Get hash algorithm
1393
+ // Hash can be either a string or an object with name property
1394
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1395
+ const alg = normalizedAlgorithm;
1396
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1397
+ const keyAlg = key.algorithm;
1398
+ let hashAlgorithm = 'SHA-256';
1399
+ if (typeof alg.hash === 'string') {
1400
+ hashAlgorithm = alg.hash;
1401
+ } else if (alg.hash?.name) {
1402
+ hashAlgorithm = alg.hash.name;
1403
+ } else if (typeof keyAlg.hash === 'string') {
1404
+ hashAlgorithm = keyAlg.hash;
1405
+ } else if (keyAlg.hash?.name) {
1406
+ hashAlgorithm = keyAlg.hash.name;
1407
+ }
1408
+
1409
+ // Create HMAC and compute expected signature
1410
+ const keyData = key.keyObject.export();
1411
+ const hmac = createHmac(hashAlgorithm, keyData);
1412
+ const dataBuffer = bufferLikeToArrayBuffer(data);
1413
+ hmac.update(dataBuffer);
1414
+ const expectedDigest = hmac.digest();
1415
+ const expected = new Uint8Array(bufferLikeToArrayBuffer(expectedDigest));
1416
+
1417
+ // Constant-time comparison
1418
+ const signatureArray = new Uint8Array(bufferLikeToArrayBuffer(signature));
1419
+ if (expected.length !== signatureArray.length) {
1420
+ return false;
1421
+ }
1422
+
1423
+ // Manual constant-time comparison
1424
+ let result = 0;
1425
+ for (let i = 0; i < expected.length; i++) {
1426
+ result |= expected[i] ^ signatureArray[i];
1427
+ }
1428
+ return result === 0;
1429
+ }
1430
+ return signVerify(normalizedAlgorithm, key, data, signature);
1084
1431
  }
1085
1432
  }
1086
1433
  export const subtle = new Subtle();
1434
+ function getKeyLength(algorithm) {
1435
+ const name = algorithm.name;
1436
+ switch (name) {
1437
+ case 'AES-CTR':
1438
+ case 'AES-CBC':
1439
+ case 'AES-GCM':
1440
+ case 'AES-KW':
1441
+ case 'ChaCha20-Poly1305':
1442
+ return algorithm.length || 256;
1443
+ case 'HMAC':
1444
+ {
1445
+ const hmacAlg = algorithm;
1446
+ return hmacAlg.length || 256;
1447
+ }
1448
+ default:
1449
+ throw lazyDOMException(`Cannot determine key length for ${name}`, 'NotSupportedError');
1450
+ }
1451
+ }
1087
1452
  //# sourceMappingURL=subtle.js.map