@blamejs/pki 0.5.17 → 0.5.19

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/webcrypto.js CHANGED
@@ -42,6 +42,52 @@ var guard = require("./guard-all");
42
42
  var constants = require("./constants");
43
43
  var asn1 = require("./asn1-der");
44
44
  var oid = require("./oid");
45
+ // What this engine reads from the runtime while it is deciding something, taken at load. The
46
+ // decisions here are the ones the whole toolkit signs and verifies behind: whether a value IS a
47
+ // CryptoKey, which algorithm a key names, how many octets a modulus has. A caller who receives
48
+ // control afterwards -- through an accessor on a key-like object, or while a verb is suspended on
49
+ // an await -- can replace any of them, and every check around them still runs and still passes.
50
+ // See guard-intrinsic for the whole captured set.
51
+ var intrinsic = require("./guard-intrinsic");
52
+ var _isArray = intrinsic.isArray;
53
+ var _hasOwn = intrinsic.hasOwn;
54
+ var _stringify = intrinsic.stringify;
55
+ var _bufferFrom = intrinsic.bufferFrom;
56
+ var _bufToString = intrinsic.uncurry(Buffer.prototype.toString);
57
+ var _bufferConcat = intrinsic.bufferConcat;
58
+ var _bufferAlloc = intrinsic.bufferAlloc;
59
+ var _isBuffer = intrinsic.isBuffer;
60
+ var _keys = intrinsic.keys;
61
+ var _map = intrinsic.map;
62
+ var _forEach = intrinsic.forEach;
63
+ var _indexOf = intrinsic.indexOf;
64
+ var _isInteger = intrinsic.isInteger;
65
+ var _join = intrinsic.join;
66
+ var _filter = intrinsic.filter;
67
+ var _arraySlice = intrinsic.arraySlice;
68
+ var _defineProperty = intrinsic.defineProperty;
69
+ var _max = intrinsic.max;
70
+ var _parseInt = intrinsic.parseInt;
71
+ var _isFinite = intrinsic.isFinite;
72
+ var _String = intrinsic.String;
73
+ var _Number = intrinsic.Number;
74
+ var _BigInt = intrinsic.BigInt;
75
+ var _Uint8Array = intrinsic.Uint8Array;
76
+ var _assign = intrinsic.assign;
77
+ var _create = intrinsic.create;
78
+ var _isView = intrinsic.isView;
79
+ var _toUpperCase = intrinsic.toUpperCase;
80
+ var _toLowerCase = intrinsic.toLowerCase;
81
+ var _stringIndexOf = intrinsic.stringIndexOf;
82
+ var _subarray = intrinsic.subarray;
83
+ var _arrayBufferSlice = intrinsic.arrayBufferSlice;
84
+ var _numberToString = intrinsic.numberToString;
85
+ var _bigIntToString = intrinsic.bigIntToString;
86
+ var _push = intrinsic.push;
87
+ var _concat = intrinsic.concat;
88
+ // Promise.resolve is a constructor method, so it keeps its receiver: `_resolve(Promise, x)`.
89
+ var _resolve = intrinsic.uncurry(intrinsic.promiseResolve);
90
+ var _types = intrinsic.types;
45
91
 
46
92
  // Single-owner error class -- co-located with its module (framework-error
47
93
  // stays the cross-module home; this is webcrypto-private). withCause: a
@@ -58,7 +104,7 @@ function _toBuf(data, who) {
58
104
  }
59
105
 
60
106
  function _toArrayBuffer(buf) {
61
- return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
107
+ return _arrayBufferSlice(buf.buffer, buf.byteOffset, buf.byteOffset + buf.byteLength);
62
108
  }
63
109
 
64
110
  function _wcErr(code, msg) { return new WebCryptoError(code, msg); }
@@ -68,7 +114,7 @@ function _wcErr(code, msg) { return new WebCryptoError(code, msg); }
68
114
  // bogus 6-byte key). Node's own canonical JWK export (_rawPublic) round-trips
69
115
  // cleanly, so the strictness is benign there and fail-closed on untrusted import.
70
116
  function _b64urlToBuf(s, who) { return guard.encoding.base64url(s, null, _wcErr, "webcrypto/data", who || "base64url value"); }
71
- function _bufToB64url(buf) { return Buffer.from(buf).toString("base64url"); }
117
+ function _bufToB64url(buf) { return _bufToString(_bufferFrom(buf), "base64url"); }
72
118
 
73
119
  function _normalizeAlg(algorithm, who) {
74
120
  var alg = (typeof algorithm === "string") ? { name: algorithm } : algorithm;
@@ -76,8 +122,8 @@ function _normalizeAlg(algorithm, who) {
76
122
  throw new WebCryptoError("webcrypto/syntax", (who || "operation") + ": algorithm must be a string or an object with a name");
77
123
  }
78
124
  var out = {};
79
- for (var k in alg) { if (Object.prototype.hasOwnProperty.call(alg, k)) out[k] = alg[k]; }
80
- out.name = alg.name.toUpperCase();
125
+ for (var k in alg) { if (_hasOwn(alg, k)) out[k] = alg[k]; }
126
+ out.name = _toUpperCase(alg.name);
81
127
  return out;
82
128
  }
83
129
 
@@ -119,8 +165,11 @@ var XOF_NODE = {
119
165
 
120
166
  function _hashNode(h, who) {
121
167
  var name = (typeof h === "string") ? h : (h && h.name);
122
- var node = HASH_NODE[String(name).toUpperCase()];
123
- if (!node) throw new WebCryptoError("webcrypto/not-supported", (who || "operation") + ": unsupported hash " + JSON.stringify(name));
168
+ // The case fold is what picks the registry row, so it runs through the captured method: dispatched
169
+ // live, a replaced `toUpperCase` answering "SHA-1" makes a caller who asked for SHA-256 receive a
170
+ // SHA-1 digest, and nothing between here and the hash says the algorithm changed.
171
+ var node = HASH_NODE[_toUpperCase(_String(name))];
172
+ if (!node) throw new WebCryptoError("webcrypto/not-supported", (who || "operation") + ": unsupported hash " + _stringify(name));
124
173
  return node;
125
174
  }
126
175
 
@@ -138,10 +187,10 @@ var HMAC_BLOCK_BITS = {
138
187
 
139
188
  function _hmacLengthBits(alg, who) {
140
189
  var name = (typeof alg.hash === "string") ? alg.hash : (alg.hash && alg.hash.name);
141
- var blockBits = HMAC_BLOCK_BITS[String(name).toUpperCase()];
142
- if (!blockBits) throw new WebCryptoError("webcrypto/not-supported", who + ": unsupported hash " + JSON.stringify(name));
190
+ var blockBits = HMAC_BLOCK_BITS[_toUpperCase(_String(name))];
191
+ if (!blockBits) throw new WebCryptoError("webcrypto/not-supported", who + ": unsupported hash " + _stringify(name));
143
192
  if (alg.length == null) return blockBits;
144
- if (typeof alg.length !== "number" || !isFinite(alg.length) || alg.length <= 0 || alg.length % 8 !== 0) {
193
+ if (typeof alg.length !== "number" || !_isFinite(alg.length) || alg.length <= 0 || alg.length % 8 !== 0) {
145
194
  throw new WebCryptoError("webcrypto/syntax", who + ": HMAC length must be a positive multiple of 8 bits");
146
195
  }
147
196
  return alg.length;
@@ -161,7 +210,7 @@ var ML_KEM_NODE = { "ML-KEM-512": "ml-kem-512", "ML-KEM-768": "ml-kem-768", "ML-
161
210
  var SLH_DSA_NODE = {};
162
211
  ["sha2-128s", "sha2-128f", "sha2-192s", "sha2-192f", "sha2-256s", "sha2-256f",
163
212
  "shake-128s", "shake-128f", "shake-192s", "shake-192f", "shake-256s", "shake-256f"
164
- ].forEach(function (s) { SLH_DSA_NODE["SLH-DSA-" + s.toUpperCase()] = "slh-dsa-" + s; });
213
+ ].forEach(function (s) { SLH_DSA_NODE["SLH-DSA-" + _toUpperCase(s)] = "slh-dsa-" + s; });
165
214
 
166
215
  // The algorithm names each keyed operation recognizes. Membership is checked
167
216
  // before the algorithm/key name binding so an unrecognized algorithm reports
@@ -169,7 +218,7 @@ var SLH_DSA_NODE = {};
169
218
  // InvalidAccessError, matching the W3C error ordering.
170
219
  var SIGN_VERIFY_NAMES = {};
171
220
  ["RSASSA-PKCS1-V1_5", "RSA-PSS", "ECDSA", "ED25519", "ED448", "HMAC"]
172
- .concat(Object.keys(ML_DSA_NODE), Object.keys(SLH_DSA_NODE))
221
+ .concat(_keys(ML_DSA_NODE), _keys(SLH_DSA_NODE))
173
222
  .forEach(function (n) { SIGN_VERIFY_NAMES[n] = true; });
174
223
  var ENCRYPT_DECRYPT_NAMES = { "RSA-OAEP": true, "AES-GCM": true, "AES-CBC": true, "AES-CTR": true };
175
224
  var DERIVE_NAMES = { "ECDH": true, "X25519": true, "X448": true, "HKDF": true, "PBKDF2": true, "X963KDF": true };
@@ -206,8 +255,16 @@ function CryptoKey(type, extractable, algorithm, usages, handle) {
206
255
  this.type = type;
207
256
  this.extractable = !!extractable;
208
257
  this.algorithm = algorithm;
209
- this.usages = usages ? usages.slice() : [];
210
- Object.defineProperty(this, "_handle", { value: handle, enumerable: false });
258
+ // The copy is what the key will be asked about for the rest of its life, so the method that makes
259
+ // it is the captured one: a replaced `slice` hands back a list the caller still controls. The
260
+ // list-ness is checked rather than left to the copy to discover -- `Array.prototype.slice` on a
261
+ // number yields an empty list, so a non-list would have minted a key permitted for NOTHING
262
+ // instead of naming the bad argument.
263
+ if (usages != null && !_isArray(usages)) {
264
+ throw new WebCryptoError("webcrypto/syntax", "usages must be an array of key-usage strings");
265
+ }
266
+ this.usages = usages ? _arraySlice(usages) : [];
267
+ _defineProperty(this, "_handle", { value: handle, enumerable: false });
211
268
  }
212
269
 
213
270
  // This engine reads key material through its own CryptoKey handle, which a key minted by another
@@ -225,8 +282,11 @@ function _requireOwnKey(key, who) {
225
282
 
226
283
  function _requireUsage(key, usage) {
227
284
  _requireOwnKey(key, usage);
228
- if (key.usages.indexOf(usage) === -1) {
229
- throw new WebCryptoError("webcrypto/invalid-access", "key is not permitted for '" + usage + "' (usages: " + key.usages.join(",") + ")");
285
+ // The membership test IS the permission check, so it runs through the captured method: dispatched
286
+ // live, an `Array.prototype.indexOf` replaced after load reports every usage present and a key
287
+ // minted to verify signs instead, with this refusal never raised.
288
+ if (_indexOf(key.usages, usage) === -1) {
289
+ throw new WebCryptoError("webcrypto/invalid-access", "key is not permitted for '" + usage + "' (usages: " + _join(key.usages, ",") + ")");
230
290
  }
231
291
  }
232
292
 
@@ -239,8 +299,8 @@ function _requireUsage(key, usage) {
239
299
  // be satisfied by a key of algorithm Y (algorithm confusion).
240
300
  function _requireAlgMatch(alg, key, who) {
241
301
  var keyName = key && key.algorithm && key.algorithm.name;
242
- if (String(keyName).toUpperCase() !== alg.name) {
243
- throw new WebCryptoError("webcrypto/invalid-access", who + ": algorithm " + JSON.stringify(alg.name) + " does not match the key's algorithm " + JSON.stringify(keyName));
302
+ if (_toUpperCase(_String(keyName)) !== alg.name) {
303
+ throw new WebCryptoError("webcrypto/invalid-access", who + ": algorithm " + _stringify(alg.name) + " does not match the key's algorithm " + _stringify(keyName));
244
304
  }
245
305
  }
246
306
 
@@ -250,7 +310,7 @@ function SubtleCrypto() {}
250
310
 
251
311
  SubtleCrypto.prototype.digest = async function digest(algorithm, data) {
252
312
  var name = _normalizeAlg(algorithm, "digest").name;
253
- var xof = XOF_NODE[String(name).toUpperCase()];
313
+ var xof = XOF_NODE[_toUpperCase(_String(name))];
254
314
  // An XOF is always constructed with its output length stated. Omitting it
255
315
  // makes node emit a deprecation warning and fall back to a 32-byte squeeze,
256
316
  // which for SHAKE256 would silently produce half the required digest.
@@ -263,6 +323,14 @@ SubtleCrypto.prototype.digest = async function digest(algorithm, data) {
263
323
 
264
324
  SubtleCrypto.prototype.generateKey = async function generateKey(algorithm, extractable, keyUsages) {
265
325
  var alg = _normalizeAlg(algorithm, "generateKey");
326
+ // Before the partition below, not only in the CryptoKey constructor: the asymmetric branch splits
327
+ // the usages first, and `Array.prototype.filter` treats a non-list as array-like and yields `[]`,
328
+ // so both halves reached the constructor already valid and the call minted an unusable PAIR
329
+ // instead of naming the argument. The symmetric branches hand `usages` straight to the
330
+ // constructor, which is why its own door caught those and not these.
331
+ if (keyUsages != null && !_isArray(keyUsages)) {
332
+ throw new WebCryptoError("webcrypto/syntax", "generateKey: keyUsages must be an array of key-usage strings");
333
+ }
266
334
  var usages = keyUsages || [];
267
335
  var name = alg.name;
268
336
 
@@ -282,8 +350,10 @@ SubtleCrypto.prototype.generateKey = async function generateKey(algorithm, extra
282
350
  // Asymmetric key pairs.
283
351
  var pair = _generateKeyPair(alg);
284
352
  var pubAlg = pair.algorithm;
285
- var privUsages = usages.filter(function (u) { return u === "sign" || u === "deriveKey" || u === "deriveBits" || u === "decrypt" || u === "unwrapKey" || u === "decapsulateKey" || u === "decapsulateBits"; });
286
- var pubUsages = usages.filter(function (u) { return u === "verify" || u === "encrypt" || u === "wrapKey" || u === "encapsulateKey" || u === "encapsulateBits"; });
353
+ // Which usages each half of the pair is minted with -- the permission set every later operation
354
+ // is checked against -- so the partition runs through the captured method.
355
+ var privUsages = _filter(usages, function (u) { return u === "sign" || u === "deriveKey" || u === "deriveBits" || u === "decrypt" || u === "unwrapKey" || u === "decapsulateKey" || u === "decapsulateBits"; });
356
+ var pubUsages = _filter(usages, function (u) { return u === "verify" || u === "encrypt" || u === "wrapKey" || u === "encapsulateKey" || u === "encapsulateBits"; });
287
357
  return {
288
358
  privateKey: new CryptoKey("private", extractable, pubAlg, privUsages, pair.privateKey),
289
359
  publicKey: new CryptoKey("public", true, pubAlg, pubUsages, pair.publicKey),
@@ -304,11 +374,11 @@ function _generateKeyPair(alg) {
304
374
  algorithm = { name: _stdName(name), modulusLength: alg.modulusLength || 2048, publicExponent: alg.publicExponent, hash: rsaHash };
305
375
  } else if (name === "ECDSA" || name === "ECDH") {
306
376
  var curve = alg.namedCurve;
307
- if (!CURVE_NODE[curve]) throw new WebCryptoError("webcrypto/not-supported", name + ": unsupported curve " + JSON.stringify(curve));
377
+ if (!CURVE_NODE[curve]) throw new WebCryptoError("webcrypto/not-supported", name + ": unsupported curve " + _stringify(curve));
308
378
  kp = nodeCrypto.generateKeyPairSync("ec", { namedCurve: CURVE_NODE[curve] });
309
379
  algorithm = { name: name, namedCurve: curve };
310
380
  } else if (name === "ED25519" || name === "ED448" || name === "X25519" || name === "X448") {
311
- kp = nodeCrypto.generateKeyPairSync(name.toLowerCase());
381
+ kp = nodeCrypto.generateKeyPairSync(_toLowerCase(name));
312
382
  algorithm = { name: _stdName(name) };
313
383
  } else if (ML_DSA_NODE[name]) {
314
384
  kp = nodeCrypto.generateKeyPairSync(ML_DSA_NODE[name]);
@@ -320,7 +390,7 @@ function _generateKeyPair(alg) {
320
390
  kp = nodeCrypto.generateKeyPairSync(SLH_DSA_NODE[name]);
321
391
  algorithm = { name: name };
322
392
  } else {
323
- throw new WebCryptoError("webcrypto/not-supported", "generateKey: unsupported algorithm " + JSON.stringify(name));
393
+ throw new WebCryptoError("webcrypto/not-supported", "generateKey: unsupported algorithm " + _stringify(name));
324
394
  }
325
395
  return { publicKey: kp.publicKey, privateKey: kp.privateKey, algorithm: algorithm };
326
396
  }
@@ -354,11 +424,11 @@ function _bufToBigIntNum(exp) {
354
424
  if (b.length === 0) {
355
425
  throw new WebCryptoError("webcrypto/syntax", "publicExponent must be a non-empty BigInteger octet string");
356
426
  }
357
- var v = BigInt("0x" + b.toString("hex"));
427
+ var v = _BigInt("0x" + _bufToString(b, "hex"));
358
428
  if (v > 0xffffffffn) {
359
- throw new WebCryptoError("webcrypto/syntax", "publicExponent " + v.toString() + " exceeds the 2^32-1 bound");
429
+ throw new WebCryptoError("webcrypto/syntax", "publicExponent " + _bigIntToString(v) + " exceeds the 2^32-1 bound");
360
430
  }
361
- return Number(v);
431
+ return _Number(v);
362
432
  }
363
433
 
364
434
  SubtleCrypto.prototype.sign = async function sign(algorithm, key, data) {
@@ -366,7 +436,7 @@ SubtleCrypto.prototype.sign = async function sign(algorithm, key, data) {
366
436
  _requireUsage(key, "sign");
367
437
  var buf = _toBuf(data, "sign");
368
438
  var name = alg.name;
369
- if (!SIGN_VERIFY_NAMES[name]) throw new WebCryptoError("webcrypto/not-supported", "sign: unsupported algorithm " + JSON.stringify(name));
439
+ if (!SIGN_VERIFY_NAMES[name]) throw new WebCryptoError("webcrypto/not-supported", "sign: unsupported algorithm " + _stringify(name));
370
440
  _requireAlgMatch(alg, key, "sign");
371
441
  if (name === "RSASSA-PKCS1-V1_5") {
372
442
  return _toArrayBuffer(nodeCrypto.sign(_hashNode(key.algorithm.hash, "sign"), buf, key._handle));
@@ -394,7 +464,7 @@ SubtleCrypto.prototype.sign = async function sign(algorithm, key, data) {
394
464
  hm.update(buf);
395
465
  return _toArrayBuffer(hm.digest());
396
466
  }
397
- throw new WebCryptoError("webcrypto/not-supported", "sign: unsupported algorithm " + JSON.stringify(name));
467
+ throw new WebCryptoError("webcrypto/not-supported", "sign: unsupported algorithm " + _stringify(name));
398
468
  };
399
469
 
400
470
  SubtleCrypto.prototype.verify = async function verify(algorithm, key, signature, data) {
@@ -403,7 +473,7 @@ SubtleCrypto.prototype.verify = async function verify(algorithm, key, signature,
403
473
  var sig = _toBuf(signature, "verify");
404
474
  var buf = _toBuf(data, "verify");
405
475
  var name = alg.name;
406
- if (!SIGN_VERIFY_NAMES[name]) throw new WebCryptoError("webcrypto/not-supported", "verify: unsupported algorithm " + JSON.stringify(name));
476
+ if (!SIGN_VERIFY_NAMES[name]) throw new WebCryptoError("webcrypto/not-supported", "verify: unsupported algorithm " + _stringify(name));
407
477
  _requireAlgMatch(alg, key, "verify");
408
478
  if (name === "RSASSA-PKCS1-V1_5") {
409
479
  return nodeCrypto.verify(_hashNode(key.algorithm.hash, "verify"), buf, key._handle, sig);
@@ -437,7 +507,7 @@ SubtleCrypto.prototype.verify = async function verify(algorithm, key, signature,
437
507
  var digest = hm.digest();
438
508
  return guard.crypto.constantTimeEqual(digest, sig);
439
509
  }
440
- throw new WebCryptoError("webcrypto/not-supported", "verify: unsupported algorithm " + JSON.stringify(name));
510
+ throw new WebCryptoError("webcrypto/not-supported", "verify: unsupported algorithm " + _stringify(name));
441
511
  };
442
512
 
443
513
  // Run a node:crypto AES cipher sequence, converting any raw node fault -- a bad IV length,
@@ -455,7 +525,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
455
525
  _requireUsage(key, "encrypt");
456
526
  var buf = _toBuf(data, "encrypt");
457
527
  var name = alg.name;
458
- if (!ENCRYPT_DECRYPT_NAMES[name]) throw new WebCryptoError("webcrypto/not-supported", "encrypt: unsupported algorithm " + JSON.stringify(name));
528
+ if (!ENCRYPT_DECRYPT_NAMES[name]) throw new WebCryptoError("webcrypto/not-supported", "encrypt: unsupported algorithm " + _stringify(name));
459
529
  _requireAlgMatch(alg, key, "encrypt");
460
530
  if (name === "RSA-OAEP") {
461
531
  return _toArrayBuffer(nodeCrypto.publicEncrypt({
@@ -472,7 +542,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
472
542
  var cipher = nodeCrypto.createCipheriv("aes-" + key.algorithm.length + "-gcm", kb, iv, { authTagLength: (alg.tagLength || 128) / 8 });
473
543
  if (aad) cipher.setAAD(aad);
474
544
  var ct = guard.secret.cipherFinish(cipher, buf, WebCryptoError, "webcrypto/operation", "an AES-GCM encrypt intermediate");
475
- return Buffer.concat([ct, cipher.getAuthTag()]);
545
+ return _bufferConcat([ct, cipher.getAuthTag()]);
476
546
  });
477
547
  }, "encrypt"));
478
548
  }
@@ -495,7 +565,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
495
565
  });
496
566
  }, "encrypt"));
497
567
  }
498
- throw new WebCryptoError("webcrypto/not-supported", "encrypt: unsupported algorithm " + JSON.stringify(name));
568
+ throw new WebCryptoError("webcrypto/not-supported", "encrypt: unsupported algorithm " + _stringify(name));
499
569
  };
500
570
 
501
571
  SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
@@ -503,7 +573,7 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
503
573
  _requireUsage(key, "decrypt");
504
574
  var buf = _toBuf(data, "decrypt");
505
575
  var name = alg.name;
506
- if (!ENCRYPT_DECRYPT_NAMES[name]) throw new WebCryptoError("webcrypto/not-supported", "decrypt: unsupported algorithm " + JSON.stringify(name));
576
+ if (!ENCRYPT_DECRYPT_NAMES[name]) throw new WebCryptoError("webcrypto/not-supported", "decrypt: unsupported algorithm " + _stringify(name));
507
577
  _requireAlgMatch(alg, key, "decrypt");
508
578
  if (name === "RSA-OAEP") {
509
579
  // For a CMS key-transport recipient this plaintext IS the recovered content-encryption key, and
@@ -521,8 +591,10 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
521
591
  var tagLen = (alg.tagLength || 128) / 8;
522
592
  var iv = _toBuf(alg.iv, "AES-GCM iv");
523
593
  if (buf.length < tagLen) throw new WebCryptoError("webcrypto/operation", "decrypt: AES-GCM ciphertext is shorter than its authentication tag");
524
- var ct = buf.subarray(0, buf.length - tagLen);
525
- var tag = buf.subarray(buf.length - tagLen);
594
+ // The split between ciphertext and tag decides which bytes are authenticated, so the window it
595
+ // is taken with is the captured one: a replaced `subarray` hands the tag check other bytes.
596
+ var ct = _subarray(buf, 0, buf.length - tagLen);
597
+ var tag = _subarray(buf, buf.length - tagLen);
526
598
  var gcmAad = alg.additionalData ? _toBuf(alg.additionalData, "AES-GCM aad") : null;
527
599
  return _toArrayBuffer(_runCipher(function () {
528
600
  return _withSecretBytes(key, function (kb) {
@@ -554,7 +626,7 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
554
626
  });
555
627
  }, "decrypt"));
556
628
  }
557
- throw new WebCryptoError("webcrypto/not-supported", "decrypt: unsupported algorithm " + JSON.stringify(name));
629
+ throw new WebCryptoError("webcrypto/not-supported", "decrypt: unsupported algorithm " + _stringify(name));
558
630
  };
559
631
 
560
632
  // _withSecretBytes(key, fn) -- export a secret key's raw material, hand it to fn, and wipe
@@ -607,7 +679,7 @@ function _requireCtrLength128(alg) {
607
679
  // the `length / 8` narrowing in the per-algorithm branches below would
608
680
  // otherwise silently truncate a fractional byte count.
609
681
  function _requireDeriveLength(length, who) {
610
- if (typeof length !== "number" || !isFinite(length) || length <= 0 || length % 8 !== 0) {
682
+ if (typeof length !== "number" || !_isFinite(length) || length <= 0 || length % 8 !== 0) {
611
683
  throw new WebCryptoError("webcrypto/operation", who + ": length must be a positive multiple of 8 bits");
612
684
  }
613
685
  }
@@ -622,7 +694,7 @@ function _requireDeriveLength(length, who) {
622
694
  // Concurrency is CAPPED so many high-iteration jobs cannot monopolize the whole worker pool and starve
623
695
  // unrelated DNS / filesystem / crypto work: at least two pool threads are left free (default pool is four),
624
696
  // and derivations beyond the cap queue and run as slots free. The cap tracks UV_THREADPOOL_SIZE when raised.
625
- var _PBKDF2_MAX_CONCURRENT = Math.max(1, (parseInt(process.env.UV_THREADPOOL_SIZE, 10) || 4) - 2);
697
+ var _PBKDF2_MAX_CONCURRENT = _max(1, (_parseInt(process.env.UV_THREADPOOL_SIZE, 10) || 4) - 2);
626
698
  var _pbkdf2InFlight = 0;
627
699
  var _pbkdf2Waiters = [];
628
700
  function _pbkdf2Async(pw, salt, iterations, keylen, digest) {
@@ -663,7 +735,7 @@ async function _deriveBitsRaw(alg, key, length) {
663
735
  if (length / 8 > secret.length) {
664
736
  throw new WebCryptoError("webcrypto/operation", name + ": requested " + length + " bits but the shared secret has " + (secret.length * 8));
665
737
  }
666
- return _toArrayBuffer(secret.subarray(0, length / 8));
738
+ return _toArrayBuffer(_subarray(secret, 0, length / 8));
667
739
  } finally {
668
740
  guard.secret.zeroize(secret, WebCryptoError, "webcrypto/operation", "the raw key-agreement shared secret");
669
741
  }
@@ -674,8 +746,8 @@ async function _deriveBitsRaw(alg, key, length) {
674
746
  // itself. A controllable allocation, not one of the runtime-internal copies the best-effort
675
747
  // caveat covers, so it is wiped once the derivation has consumed it.
676
748
  return _withSecretBytes(key, function (ikm) {
677
- var derived = nodeCrypto.hkdfSync(_hashNode(alg.hash, "HKDF"), ikm, _toBuf(alg.salt, "HKDF salt"), _toBuf(alg.info || Buffer.alloc(0), "HKDF info"), length / 8);
678
- return derived instanceof ArrayBuffer ? derived : _toArrayBuffer(Buffer.from(derived));
749
+ var derived = nodeCrypto.hkdfSync(_hashNode(alg.hash, "HKDF"), ikm, _toBuf(alg.salt, "HKDF salt"), _toBuf(alg.info || _bufferAlloc(0), "HKDF info"), length / 8);
750
+ return derived instanceof ArrayBuffer ? derived : _toArrayBuffer(_bufferFrom(derived));
679
751
  });
680
752
  }
681
753
  if (name === "PBKDF2") {
@@ -700,13 +772,13 @@ async function _deriveBitsRaw(alg, key, length) {
700
772
  // The base key here HOLDS the ECDH shared secret Z of an RFC 5753 kari, so this export is
701
773
  // exactly as sensitive as the raw agreement secret wiped above.
702
774
  return _withSecretBytes(key, function (z) {
703
- var derived = _x963Kdf(_hashNode(alg.hash, "X963KDF"), z, _toBuf(alg.info || Buffer.alloc(0), "X963KDF SharedInfo"), length / 8);
775
+ var derived = _x963Kdf(_hashNode(alg.hash, "X963KDF"), z, _toBuf(alg.info || _bufferAlloc(0), "X963KDF SharedInfo"), length / 8);
704
776
  // Same as PBKDF2 above: the copy is what the caller receives, so the derived buffer is cleared.
705
777
  try { return _toArrayBuffer(derived); }
706
778
  finally { guard.secret.zeroize(derived, WebCryptoError, "webcrypto/operation", "the X9.63 KDF output"); }
707
779
  });
708
780
  }
709
- throw new WebCryptoError("webcrypto/not-supported", "deriveBits: unsupported algorithm " + JSON.stringify(name));
781
+ throw new WebCryptoError("webcrypto/not-supported", "deriveBits: unsupported algorithm " + _stringify(name));
710
782
  }
711
783
 
712
784
  // The X9.63 single-step KDF counter loop. Bounded by the 2^32 counter range; every input is a
@@ -715,16 +787,16 @@ function _x963Kdf(hashNode, z, sharedInfo, lenBytes) {
715
787
  var blocks = [], counter = 1, got = 0;
716
788
  while (got < lenBytes) {
717
789
  if (counter > 0xffffffff) throw new WebCryptoError("webcrypto/operation", "X963KDF: requested output exceeds the counter range");
718
- var ctr = Buffer.alloc(4); ctr.writeUInt32BE(counter, 0);
790
+ var ctr = _bufferAlloc(4); ctr.writeUInt32BE(counter, 0);
719
791
  var h = nodeCrypto.createHash(hashNode).update(z).update(ctr).update(sharedInfo).digest();
720
- blocks.push(h); got += h.length; counter += 1;
792
+ _push(blocks, h); got += h.length; counter += 1;
721
793
  }
722
794
  // Return an exact-sized buffer the caller wholly owns, not a VIEW over the joined blocks: a
723
795
  // caller clearing what it received would otherwise leave the unused tail of the final digest
724
796
  // block -- derived from the shared secret -- readable behind it. The accumulator and the
725
797
  // per-block digests are cleared here, where they were allocated.
726
- var joined = Buffer.concat(blocks);
727
- var exact = Buffer.alloc(lenBytes);
798
+ var joined = _bufferConcat(blocks);
799
+ var exact = _bufferAlloc(lenBytes);
728
800
  joined.copy(exact, 0, 0, lenBytes);
729
801
  guard.secret.zeroize(joined, WebCryptoError, "webcrypto/operation", "the KDF accumulator");
730
802
  for (var bi = 0; bi < blocks.length; bi++) guard.secret.zeroize(blocks[bi], WebCryptoError, "webcrypto/operation", "a KDF block");
@@ -734,7 +806,7 @@ function _x963Kdf(hashNode, z, sharedInfo, lenBytes) {
734
806
  SubtleCrypto.prototype.deriveBits = async function deriveBits(algorithm, key, length) {
735
807
  var alg = _normalizeAlg(algorithm, "deriveBits");
736
808
  _requireUsage(key, "deriveBits");
737
- if (!DERIVE_NAMES[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "deriveBits: unsupported algorithm " + JSON.stringify(alg.name));
809
+ if (!DERIVE_NAMES[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "deriveBits: unsupported algorithm " + _stringify(alg.name));
738
810
  _requireAlgMatch(alg, key, "deriveBits");
739
811
  return _deriveBitsRaw(alg, key, length);
740
812
  };
@@ -746,11 +818,11 @@ SubtleCrypto.prototype.deriveKey = async function deriveKey(algorithm, baseKey,
746
818
  // here and route the raw derivation past deriveBits' own usage gate.
747
819
  _requireUsage(baseKey, "deriveKey");
748
820
  var alg = _normalizeAlg(algorithm, "deriveKey");
749
- if (!DERIVE_NAMES[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "deriveKey: unsupported algorithm " + JSON.stringify(alg.name));
821
+ if (!DERIVE_NAMES[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "deriveKey: unsupported algorithm " + _stringify(alg.name));
750
822
  _requireAlgMatch(alg, baseKey, "deriveKey");
751
823
  var dk = _normalizeAlg(derivedKeyType, "deriveKey");
752
824
  var bits;
753
- if (dk.name.indexOf("AES") === 0) {
825
+ if (_stringIndexOf(dk.name, "AES") === 0) {
754
826
  // W3C get-key-length for AES: the derivedKeyType MUST carry a length of
755
827
  // 128/192/256. Without this check the derived key would silently take
756
828
  // the size of the raw agreement/KDF output (e.g. a 384-bit "AES" key
@@ -775,7 +847,7 @@ SubtleCrypto.prototype.deriveKey = async function deriveKey(algorithm, baseKey,
775
847
  // failing import too (a bad derivedKeyType is caller-controlled).
776
848
  var raw = await _deriveBitsRaw(alg, baseKey, bits);
777
849
  try { return await this.importKey("raw", raw, dk, extractable, keyUsages); }
778
- finally { guard.secret.zeroize(new Uint8Array(raw), WebCryptoError, "webcrypto/operation", "the derived key material"); }
850
+ finally { guard.secret.zeroize(new _Uint8Array(raw), WebCryptoError, "webcrypto/operation", "the derived key material"); }
779
851
  };
780
852
 
781
853
  // ML-KEM (FIPS 203) key encapsulation over Node's crypto.encapsulate/decapsulate.
@@ -791,9 +863,9 @@ SubtleCrypto.prototype.deriveKey = async function deriveKey(algorithm, baseKey,
791
863
  SubtleCrypto.prototype.encapsulateBits = async function encapsulateBits(algorithm, encapsulationKey) {
792
864
  var alg = _normalizeAlg(algorithm, "encapsulateBits");
793
865
  _requireUsage(encapsulationKey, "encapsulateBits");
794
- if (!ML_KEM_NODE[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "encapsulateBits: unsupported algorithm " + JSON.stringify(alg.name));
866
+ if (!ML_KEM_NODE[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "encapsulateBits: unsupported algorithm " + _stringify(alg.name));
795
867
  _requireAlgMatch(alg, encapsulationKey, "encapsulateBits");
796
- if (encapsulationKey.type !== "public") throw new WebCryptoError("webcrypto/invalid-access", "encapsulateBits requires a public (encapsulation) key, got " + JSON.stringify(encapsulationKey.type));
868
+ if (encapsulationKey.type !== "public") throw new WebCryptoError("webcrypto/invalid-access", "encapsulateBits requires a public (encapsulation) key, got " + _stringify(encapsulationKey.type));
797
869
  var r;
798
870
  try { r = nodeCrypto.encapsulate(encapsulationKey._handle); }
799
871
  catch (e) { throw new WebCryptoError("webcrypto/operation", "encapsulateBits: ML-KEM encapsulation failed", e); }
@@ -814,9 +886,9 @@ SubtleCrypto.prototype.encapsulateBits = async function encapsulateBits(algorith
814
886
  SubtleCrypto.prototype.decapsulateBits = async function decapsulateBits(algorithm, decapsulationKey, ciphertext) {
815
887
  var alg = _normalizeAlg(algorithm, "decapsulateBits");
816
888
  _requireUsage(decapsulationKey, "decapsulateBits");
817
- if (!ML_KEM_NODE[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "decapsulateBits: unsupported algorithm " + JSON.stringify(alg.name));
889
+ if (!ML_KEM_NODE[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "decapsulateBits: unsupported algorithm " + _stringify(alg.name));
818
890
  _requireAlgMatch(alg, decapsulationKey, "decapsulateBits");
819
- if (decapsulationKey.type !== "private") throw new WebCryptoError("webcrypto/invalid-access", "decapsulateBits requires a private (decapsulation) key, got " + JSON.stringify(decapsulationKey.type));
891
+ if (decapsulationKey.type !== "private") throw new WebCryptoError("webcrypto/invalid-access", "decapsulateBits requires a private (decapsulation) key, got " + _stringify(decapsulationKey.type));
820
892
  var ct = _toBuf(ciphertext, "decapsulateBits ciphertext");
821
893
  // FIPS 203 sec. 7.3 makes the ciphertext-length check the ONE per-execution input check a
822
894
  // decapsulating party owes, so it belongs here, at the engine boundary, rather than only in the
@@ -858,25 +930,25 @@ SubtleCrypto.prototype.wrapKey = async function wrapKey(format, key, wrappingKey
858
930
  // exists to protect. It is this function's allocation and is cleared once the wrap has consumed
859
931
  // it, on the delegated branch as well as the AES-KW one.
860
932
  var exported = await this.exportKey(format, key);
861
- var bytes = (format === "jwk") ? Buffer.from(JSON.stringify(exported)) : Buffer.from(exported);
933
+ var bytes = (format === "jwk") ? _bufferFrom(_stringify(exported)) : _bufferFrom(exported);
862
934
  try {
863
935
  var alg = _normalizeAlg(wrapAlgorithm, "wrapKey");
864
936
  _requireUsage(wrappingKey, "wrapKey");
865
- if (alg.name !== "AES-KW" && !ENCRYPT_DECRYPT_NAMES[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "wrapKey: unsupported algorithm " + JSON.stringify(alg.name));
937
+ if (alg.name !== "AES-KW" && !ENCRYPT_DECRYPT_NAMES[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "wrapKey: unsupported algorithm " + _stringify(alg.name));
866
938
  _requireAlgMatch(alg, wrappingKey, "wrapKey");
867
939
  if (alg.name === "AES-KW") {
868
940
  // AES-KW wraps 64-bit blocks (RFC 3394): the serialized key MUST be a multiple of 8
869
941
  // bytes and at least 16. A "jwk" serialization (arbitrary-length JSON) or any other
870
942
  // non-conforming length is an OperationError -- a typed verdict, never a raw node fault.
871
943
  if (bytes.length < 16 || bytes.length % 8 !== 0) {
872
- throw new WebCryptoError("webcrypto/operation", "wrapKey: AES-KW requires the serialized key be a multiple of 8 bytes (>= 16); got " + bytes.length + " -- format " + JSON.stringify(format) + " is not AES-KW-wrappable");
944
+ throw new WebCryptoError("webcrypto/operation", "wrapKey: AES-KW requires the serialized key be a multiple of 8 bytes (>= 16); got " + bytes.length + " -- format " + _stringify(format) + " is not AES-KW-wrappable");
873
945
  }
874
946
  // The mirror of unwrapKey below: in a KEM flow this export is the SENDER's copy of the same
875
947
  // key-encryption key, so leaving it unwiped would keep a full copy of the KEK alive for the
876
948
  // process lifetime and make the wipes the CMS layer performs pointless in the encrypt direction.
877
949
  try {
878
950
  return _withSecretBytes(wrappingKey, function (wkBytes) {
879
- var c = nodeCrypto.createCipheriv("aes" + wrappingKey.algorithm.length + "-wrap", wkBytes, Buffer.from("A6A6A6A6A6A6A6A6", "hex"));
951
+ var c = nodeCrypto.createCipheriv("aes" + wrappingKey.algorithm.length + "-wrap", wkBytes, _bufferFrom("A6A6A6A6A6A6A6A6", "hex"));
880
952
  return _toArrayBuffer(guard.secret.cipherFinish(c, bytes, WebCryptoError, "webcrypto/operation", "an AES-KW wrap intermediate"));
881
953
  });
882
954
  } catch (e) { throw new WebCryptoError("webcrypto/operation", "wrapKey: AES-KW key wrap failed", e); }
@@ -902,7 +974,7 @@ SubtleCrypto.prototype.unwrapKey = async function unwrapKey(format, wrappedKey,
902
974
  // never verify the caller was actually permitted to unwrap (mirrors
903
975
  // wrapKey, which checks before both of its paths).
904
976
  _requireUsage(unwrappingKey, "unwrapKey");
905
- if (alg.name !== "AES-KW" && !ENCRYPT_DECRYPT_NAMES[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "unwrapKey: unsupported algorithm " + JSON.stringify(alg.name));
977
+ if (alg.name !== "AES-KW" && !ENCRYPT_DECRYPT_NAMES[alg.name]) throw new WebCryptoError("webcrypto/not-supported", "unwrapKey: unsupported algorithm " + _stringify(alg.name));
906
978
  _requireAlgMatch(alg, unwrappingKey, "unwrapKey");
907
979
  var bytes;
908
980
  if (alg.name === "AES-KW") {
@@ -921,13 +993,13 @@ SubtleCrypto.prototype.unwrapKey = async function unwrapKey(format, wrappedKey,
921
993
  // would also break the fuzz-harness contract.
922
994
  try {
923
995
  bytes = _withSecretBytes(unwrappingKey, function (kwBytes) {
924
- var d = nodeCrypto.createDecipheriv("aes" + unwrappingKey.algorithm.length + "-wrap", kwBytes, Buffer.from("A6A6A6A6A6A6A6A6", "hex"));
996
+ var d = nodeCrypto.createDecipheriv("aes" + unwrappingKey.algorithm.length + "-wrap", kwBytes, _bufferFrom("A6A6A6A6A6A6A6A6", "hex"));
925
997
  return guard.secret.cipherFinish(d, wrapped, WebCryptoError, "webcrypto/operation", "the unwrapped key material");
926
998
  });
927
999
  } catch (e) { throw new WebCryptoError("webcrypto/operation", "unwrapKey: AES-KW key unwrap failed (integrity or length)", e); }
928
1000
  } else {
929
1001
  var unwrapKeyClone = _cloneWithUsage(unwrappingKey, "decrypt");
930
- bytes = Buffer.from(await this.decrypt(unwrapAlgorithm, unwrapKeyClone, wrappedKey));
1002
+ bytes = _bufferFrom(await this.decrypt(unwrapAlgorithm, unwrapKeyClone, wrappedKey));
931
1003
  }
932
1004
  var keyData;
933
1005
  if (format === "jwk") {
@@ -955,7 +1027,7 @@ SubtleCrypto.prototype.unwrapKey = async function unwrapKey(format, wrappedKey,
955
1027
  };
956
1028
 
957
1029
  function _cloneWithUsage(key, usage) {
958
- var k = new CryptoKey(key.type, key.extractable, key.algorithm, key.usages.concat([usage]), key._handle);
1030
+ var k = new CryptoKey(key.type, key.extractable, key.algorithm, _concat(key.usages, [usage]), key._handle);
959
1031
  return k;
960
1032
  }
961
1033
 
@@ -1034,7 +1106,7 @@ function _validateMlKemInner(innerBytes, sizes) {
1034
1106
  // per-algorithm structural check lives here, at the one import boundary. Only ML-KEM needs it
1035
1107
  // today: the engine ACCEPTS the OpenSSL-legacy bare-seed layout RFC 9935 sec. 6 forbids.
1036
1108
  var PKCS8_INNER_VALIDATORS = {};
1037
- Object.keys(ML_KEM_INNER).forEach(function (o) { PKCS8_INNER_VALIDATORS[o] = function (inner) { _validateMlKemInner(inner, ML_KEM_INNER[o]); }; });
1109
+ _forEach(_keys(ML_KEM_INNER), function (o) { PKCS8_INNER_VALIDATORS[o] = function (inner) { _validateMlKemInner(inner, ML_KEM_INNER[o]); }; });
1038
1110
 
1039
1111
  function _preValidatePkcs8(p8, name) {
1040
1112
  if (!ML_KEM_NODE[name]) return; // only the ML-KEM CHOICE carries the bare-seed hazard
@@ -1090,7 +1162,7 @@ SubtleCrypto.prototype.importKey = async function importKey(format, keyData, alg
1090
1162
  // A JWK is a JSON object; null / undefined / an array / a primitive (incl. the JSON token
1091
1163
  // `null` from an unwrapKey over non-authenticating ciphertext) fails closed as a typed
1092
1164
  // DataError, never a raw property-access TypeError.
1093
- if (jwk === null || typeof jwk !== "object" || Array.isArray(jwk)) {
1165
+ if (jwk === null || typeof jwk !== "object" || _isArray(jwk)) {
1094
1166
  throw new WebCryptoError("webcrypto/data", "importKey jwk: keyData must be a JsonWebKey object");
1095
1167
  }
1096
1168
  if (jwk.kty === "oct") {
@@ -1109,12 +1181,12 @@ SubtleCrypto.prototype.importKey = async function importKey(format, keyData, alg
1109
1181
  // unrecognized member to be ignored, so a member of that name on an EC or OKP JWK is an
1110
1182
  // extension this implementation has no meaning for -- reading it as private material there
1111
1183
  // would turn a valid public-key import into a failure.
1112
- var isPrivate = Object.prototype.hasOwnProperty.call(jwk, "d") ||
1113
- (jwk.kty === "AKP" && Object.prototype.hasOwnProperty.call(jwk, "priv"));
1184
+ var isPrivate = _hasOwn(jwk, "d") ||
1185
+ (jwk.kty === "AKP" && _hasOwn(jwk, "priv"));
1114
1186
  var ko = _nodeKey(function () { return isPrivate ? nodeCrypto.createPrivateKey({ key: jwk, format: "jwk" }) : nodeCrypto.createPublicKey({ key: jwk, format: "jwk" }); }, "importKey jwk");
1115
1187
  return new CryptoKey(isPrivate ? "private" : "public", isPrivate ? extractable : true, _algFromImport(name, alg, ko), usages, ko);
1116
1188
  }
1117
- throw new WebCryptoError("webcrypto/not-supported", "importKey: unsupported format " + JSON.stringify(format));
1189
+ throw new WebCryptoError("webcrypto/not-supported", "importKey: unsupported format " + _stringify(format));
1118
1190
  };
1119
1191
 
1120
1192
  function _importRawPublic(name, alg, raw, extractable, usages) {
@@ -1128,11 +1200,11 @@ function _importRawPublic(name, alg, raw, extractable, usages) {
1128
1200
  if (name === "ECDSA" || name === "ECDH") {
1129
1201
  var fb = CURVE_FIELD_BYTES[alg.namedCurve];
1130
1202
  if (!fb || raw[0] !== 0x04 || raw.length !== 1 + 2 * fb) throw new WebCryptoError("webcrypto/data", "importKey raw EC: expected an uncompressed point for " + alg.namedCurve);
1131
- var ecjwk = { kty: "EC", crv: alg.namedCurve, x: _bufToB64url(raw.subarray(1, 1 + fb)), y: _bufToB64url(raw.subarray(1 + fb)) };
1203
+ var ecjwk = { kty: "EC", crv: alg.namedCurve, x: _bufToB64url(_subarray(raw, 1, 1 + fb)), y: _bufToB64url(_subarray(raw, 1 + fb)) };
1132
1204
  var eck = nodeCrypto.createPublicKey({ key: ecjwk, format: "jwk" });
1133
1205
  return new CryptoKey("public", true, { name: name, namedCurve: alg.namedCurve }, usages, eck);
1134
1206
  }
1135
- throw new WebCryptoError("webcrypto/not-supported", "importKey raw: unsupported public-key algorithm " + JSON.stringify(name));
1207
+ throw new WebCryptoError("webcrypto/not-supported", "importKey raw: unsupported public-key algorithm " + _stringify(name));
1136
1208
  }
1137
1209
 
1138
1210
  // The node asymmetricKeyType(s) each imported asymmetric algorithm requires. The key TYPE
@@ -1149,7 +1221,7 @@ var IMPORT_KEY_TYPE = {
1149
1221
  // algorithm name maps to exactly its node asymmetricKeyType, so an RSA (or any) key imported
1150
1222
  // under an ML-DSA / ML-KEM / SLH-DSA name is a DataError, not a mislabeled PQC CryptoKey.
1151
1223
  [ML_DSA_NODE, ML_KEM_NODE, SLH_DSA_NODE].forEach(function (m) {
1152
- Object.keys(m).forEach(function (webName) { var t = {}; t[m[webName]] = 1; IMPORT_KEY_TYPE[webName] = t; });
1224
+ _forEach(_keys(m), function (webName) { var t = {}; t[m[webName]] = 1; IMPORT_KEY_TYPE[webName] = t; });
1153
1225
  });
1154
1226
  function _algFromImport(name, alg, keyObject) {
1155
1227
  var wantType = IMPORT_KEY_TYPE[name];
@@ -1169,8 +1241,8 @@ function _algFromImport(name, alg, keyObject) {
1169
1241
  throw new WebCryptoError("webcrypto/not-supported", name + ": imported key uses an unsupported EC curve");
1170
1242
  }
1171
1243
  if (alg.namedCurve && alg.namedCurve !== actualCurve) {
1172
- throw new WebCryptoError("webcrypto/data", name + ": importKey namedCurve " + JSON.stringify(alg.namedCurve) +
1173
- " does not match the imported key's curve " + JSON.stringify(actualCurve));
1244
+ throw new WebCryptoError("webcrypto/data", name + ": importKey namedCurve " + _stringify(alg.namedCurve) +
1245
+ " does not match the imported key's curve " + _stringify(actualCurve));
1174
1246
  }
1175
1247
  return { name: name, namedCurve: actualCurve };
1176
1248
  }
@@ -1243,13 +1315,13 @@ SubtleCrypto.prototype.exportKey = async function exportKey(format, key) {
1243
1315
  }
1244
1316
  return _toArrayBuffer(_rawPublic(key));
1245
1317
  }
1246
- throw new WebCryptoError("webcrypto/not-supported", "exportKey: unsupported format " + JSON.stringify(format));
1318
+ throw new WebCryptoError("webcrypto/not-supported", "exportKey: unsupported format " + _stringify(format));
1247
1319
  };
1248
1320
 
1249
1321
  function _rawPublic(key) {
1250
1322
  var jwk = key._handle.export({ format: "jwk" });
1251
1323
  if (jwk.kty === "OKP") return _b64urlToBuf(jwk.x);
1252
- if (jwk.kty === "EC") return Buffer.concat([Buffer.from([0x04]), _b64urlToBuf(jwk.x), _b64urlToBuf(jwk.y)]);
1324
+ if (jwk.kty === "EC") return _bufferConcat([_bufferFrom([0x04]), _b64urlToBuf(jwk.x), _b64urlToBuf(jwk.y)]);
1253
1325
  throw new WebCryptoError("webcrypto/not-supported", "exportKey raw: unsupported key type " + jwk.kty);
1254
1326
  }
1255
1327
 
@@ -1275,7 +1347,10 @@ function Crypto() {
1275
1347
  }
1276
1348
 
1277
1349
  Crypto.prototype.getRandomValues = function getRandomValues(typedArray) {
1278
- if (!ArrayBuffer.isView(typedArray) || typedArray instanceof Float32Array || typedArray instanceof Float64Array || typedArray instanceof DataView) {
1350
+ // The kinds W3C WebCrypto refuses here are settled from the value's internal slot, not from an
1351
+ // `instanceof` against a replaceable global: replace `Float32Array` after load and the comparison
1352
+ // is against a different constructor, so a real Float32Array passes a check written to reject it.
1353
+ if (!_isView(typedArray) || _types.isFloat32Array(typedArray) || _types.isFloat64Array(typedArray) || _types.isDataView(typedArray)) {
1279
1354
  throw new WebCryptoError("webcrypto/data", "getRandomValues: expected an integer TypedArray");
1280
1355
  }
1281
1356
  // Re-view the (already integer-TypedArray-validated) output buffer through the OUTPUT door --
@@ -1327,14 +1402,14 @@ function decompressEcPoint(sec1Compressed, nodeCurve, E, code) {
1327
1402
  var _crypto = new Crypto();
1328
1403
  // Null-prototype: is caller-supplied, and an inherited member ("constructor", "toString")
1329
1404
  // would otherwise resolve to a truthy non-format and slip past the check below.
1330
- var _EXPORT_FORMAT = Object.assign(Object.create(null), { "private": "pkcs8", "public": "spki", "secret": "raw" });
1405
+ var _EXPORT_FORMAT = _assign(_create(null), { "private": "pkcs8", "public": "spki", "secret": "raw" });
1331
1406
 
1332
1407
  // @internal
1333
1408
  // True for any object shaped like a WebCrypto CryptoKey, whichever implementation minted it.
1334
1409
  function isCryptoKeyLike(x) {
1335
1410
  return !!x && typeof x === "object" && typeof x.type === "string" &&
1336
1411
  typeof x.extractable === "boolean" && !!x.algorithm && typeof x.algorithm === "object" &&
1337
- typeof x.algorithm.name === "string" && Array.isArray(x.usages);
1412
+ typeof x.algorithm.name === "string" && _isArray(x.usages);
1338
1413
  }
1339
1414
 
1340
1415
  // @internal
@@ -1346,9 +1421,9 @@ function exportAnyKey(key, E, code) {
1346
1421
  var format = _EXPORT_FORMAT[key && key.type];
1347
1422
  if (!format) throw E(code, "a CryptoKey with a private, public, or secret type is required");
1348
1423
  if (key instanceof CryptoKey) {
1349
- return Promise.resolve()
1424
+ return _resolve(Promise)
1350
1425
  .then(function () { return _crypto.subtle.exportKey(format, key); })
1351
- .then(function (b) { return Buffer.from(b); });
1426
+ .then(function (b) { return _bufferFrom(b); });
1352
1427
  }
1353
1428
  if (!key.extractable) {
1354
1429
  throw E(code, "the CryptoKey comes from a different WebCrypto implementation and is not extractable, so its key material cannot be reached; import it through pki.webcrypto.subtle, or pass the key as DER");
@@ -1360,18 +1435,18 @@ function exportAnyKey(key, E, code) {
1360
1435
  // key's own extractable promise is this branch's responsibility, not the crypto library's.
1361
1436
  var handle = key._handle;
1362
1437
  if (handle instanceof nodeCrypto.KeyObject && handle.type === key.type) {
1363
- return Promise.resolve().then(function () {
1438
+ return _resolve(Promise).then(function () {
1364
1439
  return format === "raw" ? handle.export() : handle.export({ format: "der", type: format });
1365
- }).then(function (b) { return Buffer.from(b); }, function (e) {
1440
+ }).then(function (b) { return _bufferFrom(b); }, function (e) {
1366
1441
  throw E(code, "the CryptoKey comes from a different copy of this WebCrypto engine and its key material could not be read; import it through pki.webcrypto.subtle, or pass the key as DER", e);
1367
1442
  });
1368
1443
  }
1369
1444
  // Otherwise the only remaining implementation whose keys are reachable from this process is the
1370
1445
  // platform's own. A third party's -- a browser's, a userland polyfill's -- keeps its material
1371
1446
  // behind its own SubtleCrypto, which nothing here holds a reference to, so it is refused below.
1372
- return Promise.resolve()
1447
+ return _resolve(Promise)
1373
1448
  .then(function () { return nodeCrypto.webcrypto.subtle.exportKey(format, key); })
1374
- .then(function (b) { return Buffer.from(b); }, function (e) {
1449
+ .then(function (b) { return _bufferFrom(b); }, function (e) {
1375
1450
  throw E(code, "the CryptoKey comes from a different WebCrypto implementation and could not be exported for re-import; import it through pki.webcrypto.subtle, or pass the key as DER", e);
1376
1451
  });
1377
1452
  }
@@ -1381,19 +1456,19 @@ function exportAnyKey(key, E, code) {
1381
1456
  // key of its own keeps working -- and a foreign one is re-imported. `importParams` may be null, in
1382
1457
  // which case the key's own `algorithm` is used, which is what the key actually is.
1383
1458
  function adoptKey(key, importParams, usages, E, code) {
1384
- if (key instanceof CryptoKey) return Promise.resolve(key);
1459
+ if (key instanceof CryptoKey) return _resolve(Promise, key);
1385
1460
  // A key's usages are a capability restriction it carries, and re-importing it is the one moment
1386
1461
  // that restriction could be widened -- the new key is created with the usages the CALLER wants,
1387
1462
  // not the ones the original was created with. Require every one of them up front, so an adopted
1388
1463
  // key can do no more than it could where it came from, and a verify-only key is refused here
1389
1464
  // exactly as this engine's own verify-only key is refused by _requireUsage.
1390
- if (!Array.isArray(key.usages)) throw E(code, "a CryptoKey carrying its permitted usages is required");
1465
+ if (!_isArray(key.usages)) throw E(code, "a CryptoKey carrying its permitted usages is required");
1391
1466
  for (var i = 0; i < usages.length; i++) {
1392
- if (key.usages.indexOf(usages[i]) === -1) {
1393
- throw E(code, "the CryptoKey is not permitted for '" + usages[i] + "' (usages: " + key.usages.join(",") + ")");
1467
+ if (_indexOf(key.usages, usages[i]) === -1) {
1468
+ throw E(code, "the CryptoKey is not permitted for '" + usages[i] + "' (usages: " + _join(key.usages, ",") + ")");
1394
1469
  }
1395
1470
  }
1396
- return Promise.resolve()
1471
+ return _resolve(Promise)
1397
1472
  .then(function () { return exportAnyKey(key, E, code); })
1398
1473
  .then(function (der) {
1399
1474
  return _crypto.subtle.importKey(_EXPORT_FORMAT[key.type], der, importParams || key.algorithm, false, usages);