11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci Array, 51cb0ef41Sopenharmony_ci ArrayBufferPrototypeGetByteLength, 61cb0ef41Sopenharmony_ci ArrayPrototypeForEach, 71cb0ef41Sopenharmony_ci ArrayPrototypePush, 81cb0ef41Sopenharmony_ci ArrayPrototypeShift, 91cb0ef41Sopenharmony_ci ArrayPrototypeSplice, 101cb0ef41Sopenharmony_ci BigInt, 111cb0ef41Sopenharmony_ci BigIntPrototypeToString, 121cb0ef41Sopenharmony_ci DataView, 131cb0ef41Sopenharmony_ci DataViewPrototypeGetUint8, 141cb0ef41Sopenharmony_ci FunctionPrototypeBind, 151cb0ef41Sopenharmony_ci FunctionPrototypeCall, 161cb0ef41Sopenharmony_ci MathMin, 171cb0ef41Sopenharmony_ci NumberIsNaN, 181cb0ef41Sopenharmony_ci NumberIsSafeInteger, 191cb0ef41Sopenharmony_ci NumberPrototypeToString, 201cb0ef41Sopenharmony_ci StringFromCharCodeApply, 211cb0ef41Sopenharmony_ci StringPrototypePadStart, 221cb0ef41Sopenharmony_ci} = primordials; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ciconst { 251cb0ef41Sopenharmony_ci RandomBytesJob, 261cb0ef41Sopenharmony_ci RandomPrimeJob, 271cb0ef41Sopenharmony_ci CheckPrimeJob, 281cb0ef41Sopenharmony_ci kCryptoJobAsync, 291cb0ef41Sopenharmony_ci kCryptoJobSync, 301cb0ef41Sopenharmony_ci secureBuffer, 311cb0ef41Sopenharmony_ci} = internalBinding('crypto'); 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ciconst { 341cb0ef41Sopenharmony_ci kEmptyObject, 351cb0ef41Sopenharmony_ci lazyDOMException, 361cb0ef41Sopenharmony_ci} = require('internal/util'); 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ciconst { Buffer, kMaxLength } = require('buffer'); 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ciconst { 411cb0ef41Sopenharmony_ci codes: { 421cb0ef41Sopenharmony_ci ERR_INVALID_ARG_TYPE, 431cb0ef41Sopenharmony_ci ERR_MISSING_ARGS, 441cb0ef41Sopenharmony_ci ERR_OUT_OF_RANGE, 451cb0ef41Sopenharmony_ci ERR_OPERATION_FAILED, 461cb0ef41Sopenharmony_ci }, 471cb0ef41Sopenharmony_ci} = require('internal/errors'); 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ciconst { 501cb0ef41Sopenharmony_ci validateNumber, 511cb0ef41Sopenharmony_ci validateBoolean, 521cb0ef41Sopenharmony_ci validateFunction, 531cb0ef41Sopenharmony_ci validateInt32, 541cb0ef41Sopenharmony_ci validateObject, 551cb0ef41Sopenharmony_ci} = require('internal/validators'); 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ciconst { 581cb0ef41Sopenharmony_ci isArrayBufferView, 591cb0ef41Sopenharmony_ci isAnyArrayBuffer, 601cb0ef41Sopenharmony_ci isTypedArray, 611cb0ef41Sopenharmony_ci isFloat32Array, 621cb0ef41Sopenharmony_ci isFloat64Array, 631cb0ef41Sopenharmony_ci} = require('internal/util/types'); 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ciconst { FastBuffer } = require('internal/buffer'); 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ciconst kMaxInt32 = 2 ** 31 - 1; 681cb0ef41Sopenharmony_ciconst kMaxPossibleLength = MathMin(kMaxLength, kMaxInt32); 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_cifunction assertOffset(offset, elementSize, length) { 711cb0ef41Sopenharmony_ci validateNumber(offset, 'offset'); 721cb0ef41Sopenharmony_ci offset *= elementSize; 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci const maxLength = MathMin(length, kMaxPossibleLength); 751cb0ef41Sopenharmony_ci if (NumberIsNaN(offset) || offset > maxLength || offset < 0) { 761cb0ef41Sopenharmony_ci throw new ERR_OUT_OF_RANGE('offset', `>= 0 && <= ${maxLength}`, offset); 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci return offset >>> 0; // Convert to uint32. 801cb0ef41Sopenharmony_ci} 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_cifunction assertSize(size, elementSize, offset, length) { 831cb0ef41Sopenharmony_ci validateNumber(size, 'size'); 841cb0ef41Sopenharmony_ci size *= elementSize; 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci if (NumberIsNaN(size) || size > kMaxPossibleLength || size < 0) { 871cb0ef41Sopenharmony_ci throw new ERR_OUT_OF_RANGE('size', 881cb0ef41Sopenharmony_ci `>= 0 && <= ${kMaxPossibleLength}`, size); 891cb0ef41Sopenharmony_ci } 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci if (size + offset > length) { 921cb0ef41Sopenharmony_ci throw new ERR_OUT_OF_RANGE('size + offset', `<= ${length}`, size + offset); 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci return size >>> 0; // Convert to uint32. 961cb0ef41Sopenharmony_ci} 971cb0ef41Sopenharmony_ci 981cb0ef41Sopenharmony_cifunction randomBytes(size, callback) { 991cb0ef41Sopenharmony_ci size = assertSize(size, 1, 0, Infinity); 1001cb0ef41Sopenharmony_ci if (callback !== undefined) { 1011cb0ef41Sopenharmony_ci validateFunction(callback, 'callback'); 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci const buf = new FastBuffer(size); 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci if (callback === undefined) { 1071cb0ef41Sopenharmony_ci randomFillSync(buf.buffer, 0, size); 1081cb0ef41Sopenharmony_ci return buf; 1091cb0ef41Sopenharmony_ci } 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci // Keep the callback as a regular function so this is propagated. 1121cb0ef41Sopenharmony_ci randomFill(buf.buffer, 0, size, function(error) { 1131cb0ef41Sopenharmony_ci if (error) return FunctionPrototypeCall(callback, this, error); 1141cb0ef41Sopenharmony_ci FunctionPrototypeCall(callback, this, null, buf); 1151cb0ef41Sopenharmony_ci }); 1161cb0ef41Sopenharmony_ci} 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_cifunction randomFillSync(buf, offset = 0, size) { 1191cb0ef41Sopenharmony_ci if (!isAnyArrayBuffer(buf) && !isArrayBufferView(buf)) { 1201cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE( 1211cb0ef41Sopenharmony_ci 'buf', 1221cb0ef41Sopenharmony_ci ['ArrayBuffer', 'ArrayBufferView'], 1231cb0ef41Sopenharmony_ci buf); 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci const elementSize = buf.BYTES_PER_ELEMENT || 1; 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci offset = assertOffset(offset, elementSize, buf.byteLength); 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci if (size === undefined) { 1311cb0ef41Sopenharmony_ci size = buf.byteLength - offset; 1321cb0ef41Sopenharmony_ci } else { 1331cb0ef41Sopenharmony_ci size = assertSize(size, elementSize, offset, buf.byteLength); 1341cb0ef41Sopenharmony_ci } 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci if (size === 0) 1371cb0ef41Sopenharmony_ci return buf; 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci const job = new RandomBytesJob( 1401cb0ef41Sopenharmony_ci kCryptoJobSync, 1411cb0ef41Sopenharmony_ci buf, 1421cb0ef41Sopenharmony_ci offset, 1431cb0ef41Sopenharmony_ci size); 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci const err = job.run()[0]; 1461cb0ef41Sopenharmony_ci if (err) 1471cb0ef41Sopenharmony_ci throw err; 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci return buf; 1501cb0ef41Sopenharmony_ci} 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_cifunction randomFill(buf, offset, size, callback) { 1531cb0ef41Sopenharmony_ci if (!isAnyArrayBuffer(buf) && !isArrayBufferView(buf)) { 1541cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE( 1551cb0ef41Sopenharmony_ci 'buf', 1561cb0ef41Sopenharmony_ci ['ArrayBuffer', 'ArrayBufferView'], 1571cb0ef41Sopenharmony_ci buf); 1581cb0ef41Sopenharmony_ci } 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci const elementSize = buf.BYTES_PER_ELEMENT || 1; 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci if (typeof offset === 'function') { 1631cb0ef41Sopenharmony_ci callback = offset; 1641cb0ef41Sopenharmony_ci offset = 0; 1651cb0ef41Sopenharmony_ci // Size is a length here, assertSize() call turns it into a number of bytes 1661cb0ef41Sopenharmony_ci size = buf.length; 1671cb0ef41Sopenharmony_ci } else if (typeof size === 'function') { 1681cb0ef41Sopenharmony_ci callback = size; 1691cb0ef41Sopenharmony_ci size = buf.length - offset; 1701cb0ef41Sopenharmony_ci } else { 1711cb0ef41Sopenharmony_ci validateFunction(callback, 'callback'); 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci offset = assertOffset(offset, elementSize, buf.byteLength); 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci if (size === undefined) { 1771cb0ef41Sopenharmony_ci size = buf.byteLength - offset; 1781cb0ef41Sopenharmony_ci } else { 1791cb0ef41Sopenharmony_ci size = assertSize(size, elementSize, offset, buf.byteLength); 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci if (size === 0) { 1831cb0ef41Sopenharmony_ci callback(null, buf); 1841cb0ef41Sopenharmony_ci return; 1851cb0ef41Sopenharmony_ci } 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci const job = new RandomBytesJob( 1881cb0ef41Sopenharmony_ci kCryptoJobAsync, 1891cb0ef41Sopenharmony_ci buf, 1901cb0ef41Sopenharmony_ci offset, 1911cb0ef41Sopenharmony_ci size); 1921cb0ef41Sopenharmony_ci job.ondone = FunctionPrototypeBind(onJobDone, job, buf, callback); 1931cb0ef41Sopenharmony_ci job.run(); 1941cb0ef41Sopenharmony_ci} 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci// Largest integer we can read from a buffer. 1971cb0ef41Sopenharmony_ci// e.g.: Buffer.from("ff".repeat(6), "hex").readUIntBE(0, 6); 1981cb0ef41Sopenharmony_ciconst RAND_MAX = 0xFFFF_FFFF_FFFF; 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci// Cache random data to use in randomInt. The cache size must be evenly 2011cb0ef41Sopenharmony_ci// divisible by 6 because each attempt to obtain a random int uses 6 bytes. 2021cb0ef41Sopenharmony_ciconst randomCache = new FastBuffer(6 * 1024); 2031cb0ef41Sopenharmony_cilet randomCacheOffset = randomCache.length; 2041cb0ef41Sopenharmony_cilet asyncCacheFillInProgress = false; 2051cb0ef41Sopenharmony_ciconst asyncCachePendingTasks = []; 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci// Generates an integer in [min, max) range where min is inclusive and max is 2081cb0ef41Sopenharmony_ci// exclusive. 2091cb0ef41Sopenharmony_cifunction randomInt(min, max, callback) { 2101cb0ef41Sopenharmony_ci // Detect optional min syntax 2111cb0ef41Sopenharmony_ci // randomInt(max) 2121cb0ef41Sopenharmony_ci // randomInt(max, callback) 2131cb0ef41Sopenharmony_ci const minNotSpecified = typeof max === 'undefined' || 2141cb0ef41Sopenharmony_ci typeof max === 'function'; 2151cb0ef41Sopenharmony_ci 2161cb0ef41Sopenharmony_ci if (minNotSpecified) { 2171cb0ef41Sopenharmony_ci callback = max; 2181cb0ef41Sopenharmony_ci max = min; 2191cb0ef41Sopenharmony_ci min = 0; 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci const isSync = typeof callback === 'undefined'; 2231cb0ef41Sopenharmony_ci if (!isSync) { 2241cb0ef41Sopenharmony_ci validateFunction(callback, 'callback'); 2251cb0ef41Sopenharmony_ci } 2261cb0ef41Sopenharmony_ci if (!NumberIsSafeInteger(min)) { 2271cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE('min', 'a safe integer', min); 2281cb0ef41Sopenharmony_ci } 2291cb0ef41Sopenharmony_ci if (!NumberIsSafeInteger(max)) { 2301cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE('max', 'a safe integer', max); 2311cb0ef41Sopenharmony_ci } 2321cb0ef41Sopenharmony_ci if (max <= min) { 2331cb0ef41Sopenharmony_ci throw new ERR_OUT_OF_RANGE( 2341cb0ef41Sopenharmony_ci 'max', `greater than the value of "min" (${min})`, max, 2351cb0ef41Sopenharmony_ci ); 2361cb0ef41Sopenharmony_ci } 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ci // First we generate a random int between [0..range) 2391cb0ef41Sopenharmony_ci const range = max - min; 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci if (!(range <= RAND_MAX)) { 2421cb0ef41Sopenharmony_ci throw new ERR_OUT_OF_RANGE(`max${minNotSpecified ? '' : ' - min'}`, 2431cb0ef41Sopenharmony_ci `<= ${RAND_MAX}`, range); 2441cb0ef41Sopenharmony_ci } 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci // For (x % range) to produce an unbiased value greater than or equal to 0 and 2471cb0ef41Sopenharmony_ci // less than range, x must be drawn randomly from the set of integers greater 2481cb0ef41Sopenharmony_ci // than or equal to 0 and less than randLimit. 2491cb0ef41Sopenharmony_ci const randLimit = RAND_MAX - (RAND_MAX % range); 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ci // If we don't have a callback, or if there is still data in the cache, we can 2521cb0ef41Sopenharmony_ci // do this synchronously, which is super fast. 2531cb0ef41Sopenharmony_ci while (isSync || (randomCacheOffset < randomCache.length)) { 2541cb0ef41Sopenharmony_ci if (randomCacheOffset === randomCache.length) { 2551cb0ef41Sopenharmony_ci // This might block the thread for a bit, but we are in sync mode. 2561cb0ef41Sopenharmony_ci randomFillSync(randomCache); 2571cb0ef41Sopenharmony_ci randomCacheOffset = 0; 2581cb0ef41Sopenharmony_ci } 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci const x = randomCache.readUIntBE(randomCacheOffset, 6); 2611cb0ef41Sopenharmony_ci randomCacheOffset += 6; 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci if (x < randLimit) { 2641cb0ef41Sopenharmony_ci const n = (x % range) + min; 2651cb0ef41Sopenharmony_ci if (isSync) return n; 2661cb0ef41Sopenharmony_ci process.nextTick(callback, undefined, n); 2671cb0ef41Sopenharmony_ci return; 2681cb0ef41Sopenharmony_ci } 2691cb0ef41Sopenharmony_ci } 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci // At this point, we are in async mode with no data in the cache. We cannot 2721cb0ef41Sopenharmony_ci // simply refill the cache, because another async call to randomInt might 2731cb0ef41Sopenharmony_ci // already be doing that. Instead, queue this call for when the cache has 2741cb0ef41Sopenharmony_ci // been refilled. 2751cb0ef41Sopenharmony_ci ArrayPrototypePush(asyncCachePendingTasks, { min, max, callback }); 2761cb0ef41Sopenharmony_ci asyncRefillRandomIntCache(); 2771cb0ef41Sopenharmony_ci} 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_cifunction asyncRefillRandomIntCache() { 2801cb0ef41Sopenharmony_ci if (asyncCacheFillInProgress) 2811cb0ef41Sopenharmony_ci return; 2821cb0ef41Sopenharmony_ci 2831cb0ef41Sopenharmony_ci asyncCacheFillInProgress = true; 2841cb0ef41Sopenharmony_ci randomFill(randomCache, (err) => { 2851cb0ef41Sopenharmony_ci asyncCacheFillInProgress = false; 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci const tasks = asyncCachePendingTasks; 2881cb0ef41Sopenharmony_ci const errorReceiver = err && ArrayPrototypeShift(tasks); 2891cb0ef41Sopenharmony_ci if (!err) 2901cb0ef41Sopenharmony_ci randomCacheOffset = 0; 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci // Restart all pending tasks. If an error occurred, we only notify a single 2931cb0ef41Sopenharmony_ci // callback (errorReceiver) about it. This way, every async call to 2941cb0ef41Sopenharmony_ci // randomInt has a chance of being successful, and it avoids complex 2951cb0ef41Sopenharmony_ci // exception handling here. 2961cb0ef41Sopenharmony_ci ArrayPrototypeForEach(ArrayPrototypeSplice(tasks, 0), (task) => { 2971cb0ef41Sopenharmony_ci randomInt(task.min, task.max, task.callback); 2981cb0ef41Sopenharmony_ci }); 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_ci // This is the only call that might throw, and is therefore done at the end. 3011cb0ef41Sopenharmony_ci if (errorReceiver) 3021cb0ef41Sopenharmony_ci errorReceiver.callback(err); 3031cb0ef41Sopenharmony_ci }); 3041cb0ef41Sopenharmony_ci} 3051cb0ef41Sopenharmony_ci 3061cb0ef41Sopenharmony_ci 3071cb0ef41Sopenharmony_cifunction onJobDone(buf, callback, error) { 3081cb0ef41Sopenharmony_ci if (error) return FunctionPrototypeCall(callback, this, error); 3091cb0ef41Sopenharmony_ci FunctionPrototypeCall(callback, this, null, buf); 3101cb0ef41Sopenharmony_ci} 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci// Really just the Web Crypto API alternative 3131cb0ef41Sopenharmony_ci// to require('crypto').randomFillSync() with an 3141cb0ef41Sopenharmony_ci// additional limitation that the input buffer is 3151cb0ef41Sopenharmony_ci// not allowed to exceed 65536 bytes, and can only 3161cb0ef41Sopenharmony_ci// be an integer-type TypedArray. 3171cb0ef41Sopenharmony_cifunction getRandomValues(data) { 3181cb0ef41Sopenharmony_ci if (arguments.length < 1) 3191cb0ef41Sopenharmony_ci throw new ERR_MISSING_ARGS('typedArray'); 3201cb0ef41Sopenharmony_ci if (!isTypedArray(data) || 3211cb0ef41Sopenharmony_ci isFloat32Array(data) || 3221cb0ef41Sopenharmony_ci isFloat64Array(data)) { 3231cb0ef41Sopenharmony_ci // Ordinarily this would be an ERR_INVALID_ARG_TYPE. However, 3241cb0ef41Sopenharmony_ci // the Web Crypto API and web platform tests expect this to 3251cb0ef41Sopenharmony_ci // be a DOMException with type TypeMismatchError. 3261cb0ef41Sopenharmony_ci throw lazyDOMException( 3271cb0ef41Sopenharmony_ci 'The data argument must be an integer-type TypedArray', 3281cb0ef41Sopenharmony_ci 'TypeMismatchError'); 3291cb0ef41Sopenharmony_ci } 3301cb0ef41Sopenharmony_ci if (data.byteLength > 65536) { 3311cb0ef41Sopenharmony_ci throw lazyDOMException( 3321cb0ef41Sopenharmony_ci 'The requested length exceeds 65,536 bytes', 3331cb0ef41Sopenharmony_ci 'QuotaExceededError'); 3341cb0ef41Sopenharmony_ci } 3351cb0ef41Sopenharmony_ci randomFillSync(data, 0); 3361cb0ef41Sopenharmony_ci return data; 3371cb0ef41Sopenharmony_ci} 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci// Implements an RFC 4122 version 4 random UUID. 3401cb0ef41Sopenharmony_ci// To improve performance, random data is generated in batches 3411cb0ef41Sopenharmony_ci// large enough to cover kBatchSize UUID's at a time. The uuidData 3421cb0ef41Sopenharmony_ci// buffer is reused. Each call to randomUUID() consumes 16 bytes 3431cb0ef41Sopenharmony_ci// from the buffer. 3441cb0ef41Sopenharmony_ci 3451cb0ef41Sopenharmony_ciconst kBatchSize = 128; 3461cb0ef41Sopenharmony_cilet uuidData; 3471cb0ef41Sopenharmony_cilet uuidNotBuffered; 3481cb0ef41Sopenharmony_cilet uuidBatch = 0; 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_cilet hexBytesCache; 3511cb0ef41Sopenharmony_cifunction getHexBytes() { 3521cb0ef41Sopenharmony_ci if (hexBytesCache === undefined) { 3531cb0ef41Sopenharmony_ci hexBytesCache = new Array(256); 3541cb0ef41Sopenharmony_ci for (let i = 0; i < hexBytesCache.length; i++) { 3551cb0ef41Sopenharmony_ci const hex = NumberPrototypeToString(i, 16); 3561cb0ef41Sopenharmony_ci hexBytesCache[i] = StringPrototypePadStart(hex, 2, '0'); 3571cb0ef41Sopenharmony_ci } 3581cb0ef41Sopenharmony_ci } 3591cb0ef41Sopenharmony_ci return hexBytesCache; 3601cb0ef41Sopenharmony_ci} 3611cb0ef41Sopenharmony_ci 3621cb0ef41Sopenharmony_cifunction serializeUUID(buf, offset = 0) { 3631cb0ef41Sopenharmony_ci const kHexBytes = getHexBytes(); 3641cb0ef41Sopenharmony_ci // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 3651cb0ef41Sopenharmony_ci return kHexBytes[buf[offset]] + 3661cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 1]] + 3671cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 2]] + 3681cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 3]] + 3691cb0ef41Sopenharmony_ci '-' + 3701cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 4]] + 3711cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 5]] + 3721cb0ef41Sopenharmony_ci '-' + 3731cb0ef41Sopenharmony_ci kHexBytes[(buf[offset + 6] & 0x0f) | 0x40] + 3741cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 7]] + 3751cb0ef41Sopenharmony_ci '-' + 3761cb0ef41Sopenharmony_ci kHexBytes[(buf[offset + 8] & 0x3f) | 0x80] + 3771cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 9]] + 3781cb0ef41Sopenharmony_ci '-' + 3791cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 10]] + 3801cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 11]] + 3811cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 12]] + 3821cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 13]] + 3831cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 14]] + 3841cb0ef41Sopenharmony_ci kHexBytes[buf[offset + 15]]; 3851cb0ef41Sopenharmony_ci} 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_cifunction getBufferedUUID() { 3881cb0ef41Sopenharmony_ci uuidData ??= secureBuffer(16 * kBatchSize); 3891cb0ef41Sopenharmony_ci if (uuidData === undefined) 3901cb0ef41Sopenharmony_ci throw new ERR_OPERATION_FAILED('Out of memory'); 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ci if (uuidBatch === 0) randomFillSync(uuidData); 3931cb0ef41Sopenharmony_ci uuidBatch = (uuidBatch + 1) % kBatchSize; 3941cb0ef41Sopenharmony_ci return serializeUUID(uuidData, uuidBatch * 16); 3951cb0ef41Sopenharmony_ci} 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_cifunction getUnbufferedUUID() { 3981cb0ef41Sopenharmony_ci uuidNotBuffered ??= secureBuffer(16); 3991cb0ef41Sopenharmony_ci if (uuidNotBuffered === undefined) 4001cb0ef41Sopenharmony_ci throw new ERR_OPERATION_FAILED('Out of memory'); 4011cb0ef41Sopenharmony_ci randomFillSync(uuidNotBuffered); 4021cb0ef41Sopenharmony_ci return serializeUUID(uuidNotBuffered); 4031cb0ef41Sopenharmony_ci} 4041cb0ef41Sopenharmony_ci 4051cb0ef41Sopenharmony_cifunction randomUUID(options) { 4061cb0ef41Sopenharmony_ci if (options !== undefined) 4071cb0ef41Sopenharmony_ci validateObject(options, 'options'); 4081cb0ef41Sopenharmony_ci const { 4091cb0ef41Sopenharmony_ci disableEntropyCache = false, 4101cb0ef41Sopenharmony_ci } = options || kEmptyObject; 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_ci validateBoolean(disableEntropyCache, 'options.disableEntropyCache'); 4131cb0ef41Sopenharmony_ci 4141cb0ef41Sopenharmony_ci return disableEntropyCache ? getUnbufferedUUID() : getBufferedUUID(); 4151cb0ef41Sopenharmony_ci} 4161cb0ef41Sopenharmony_ci 4171cb0ef41Sopenharmony_cifunction createRandomPrimeJob(type, size, options) { 4181cb0ef41Sopenharmony_ci validateObject(options, 'options'); 4191cb0ef41Sopenharmony_ci 4201cb0ef41Sopenharmony_ci const { 4211cb0ef41Sopenharmony_ci safe = false, 4221cb0ef41Sopenharmony_ci bigint = false, 4231cb0ef41Sopenharmony_ci } = options; 4241cb0ef41Sopenharmony_ci let { 4251cb0ef41Sopenharmony_ci add, 4261cb0ef41Sopenharmony_ci rem, 4271cb0ef41Sopenharmony_ci } = options; 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_ci validateBoolean(safe, 'options.safe'); 4301cb0ef41Sopenharmony_ci validateBoolean(bigint, 'options.bigint'); 4311cb0ef41Sopenharmony_ci 4321cb0ef41Sopenharmony_ci if (add !== undefined) { 4331cb0ef41Sopenharmony_ci if (typeof add === 'bigint') { 4341cb0ef41Sopenharmony_ci add = unsignedBigIntToBuffer(add, 'options.add'); 4351cb0ef41Sopenharmony_ci } else if (!isAnyArrayBuffer(add) && !isArrayBufferView(add)) { 4361cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE( 4371cb0ef41Sopenharmony_ci 'options.add', 4381cb0ef41Sopenharmony_ci [ 4391cb0ef41Sopenharmony_ci 'ArrayBuffer', 4401cb0ef41Sopenharmony_ci 'TypedArray', 4411cb0ef41Sopenharmony_ci 'Buffer', 4421cb0ef41Sopenharmony_ci 'DataView', 4431cb0ef41Sopenharmony_ci 'bigint', 4441cb0ef41Sopenharmony_ci ], 4451cb0ef41Sopenharmony_ci add); 4461cb0ef41Sopenharmony_ci } 4471cb0ef41Sopenharmony_ci } 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_ci if (rem !== undefined) { 4501cb0ef41Sopenharmony_ci if (typeof rem === 'bigint') { 4511cb0ef41Sopenharmony_ci rem = unsignedBigIntToBuffer(rem, 'options.rem'); 4521cb0ef41Sopenharmony_ci } else if (!isAnyArrayBuffer(rem) && !isArrayBufferView(rem)) { 4531cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE( 4541cb0ef41Sopenharmony_ci 'options.rem', 4551cb0ef41Sopenharmony_ci [ 4561cb0ef41Sopenharmony_ci 'ArrayBuffer', 4571cb0ef41Sopenharmony_ci 'TypedArray', 4581cb0ef41Sopenharmony_ci 'Buffer', 4591cb0ef41Sopenharmony_ci 'DataView', 4601cb0ef41Sopenharmony_ci 'bigint', 4611cb0ef41Sopenharmony_ci ], 4621cb0ef41Sopenharmony_ci rem); 4631cb0ef41Sopenharmony_ci } 4641cb0ef41Sopenharmony_ci } 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ci const job = new RandomPrimeJob(type, size, safe, add, rem); 4671cb0ef41Sopenharmony_ci job.result = bigint ? arrayBufferToUnsignedBigInt : (p) => p; 4681cb0ef41Sopenharmony_ci return job; 4691cb0ef41Sopenharmony_ci} 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_cifunction generatePrime(size, options, callback) { 4721cb0ef41Sopenharmony_ci validateInt32(size, 'size', 1); 4731cb0ef41Sopenharmony_ci if (typeof options === 'function') { 4741cb0ef41Sopenharmony_ci callback = options; 4751cb0ef41Sopenharmony_ci options = kEmptyObject; 4761cb0ef41Sopenharmony_ci } 4771cb0ef41Sopenharmony_ci validateFunction(callback, 'callback'); 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ci const job = createRandomPrimeJob(kCryptoJobAsync, size, options); 4801cb0ef41Sopenharmony_ci job.ondone = (err, prime) => { 4811cb0ef41Sopenharmony_ci if (err) { 4821cb0ef41Sopenharmony_ci callback(err); 4831cb0ef41Sopenharmony_ci return; 4841cb0ef41Sopenharmony_ci } 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci callback( 4871cb0ef41Sopenharmony_ci undefined, 4881cb0ef41Sopenharmony_ci job.result(prime)); 4891cb0ef41Sopenharmony_ci }; 4901cb0ef41Sopenharmony_ci job.run(); 4911cb0ef41Sopenharmony_ci} 4921cb0ef41Sopenharmony_ci 4931cb0ef41Sopenharmony_cifunction generatePrimeSync(size, options = kEmptyObject) { 4941cb0ef41Sopenharmony_ci validateInt32(size, 'size', 1); 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_ci const job = createRandomPrimeJob(kCryptoJobSync, size, options); 4971cb0ef41Sopenharmony_ci const { 0: err, 1: prime } = job.run(); 4981cb0ef41Sopenharmony_ci if (err) 4991cb0ef41Sopenharmony_ci throw err; 5001cb0ef41Sopenharmony_ci return job.result(prime); 5011cb0ef41Sopenharmony_ci} 5021cb0ef41Sopenharmony_ci 5031cb0ef41Sopenharmony_ci/** 5041cb0ef41Sopenharmony_ci * 48 is the ASCII code for '0', 97 is the ASCII code for 'a'. 5051cb0ef41Sopenharmony_ci * @param {number} number An integer between 0 and 15. 5061cb0ef41Sopenharmony_ci * @returns {number} corresponding to the ASCII code of the hex representation 5071cb0ef41Sopenharmony_ci * of the parameter. 5081cb0ef41Sopenharmony_ci */ 5091cb0ef41Sopenharmony_ciconst numberToHexCharCode = (number) => (number < 10 ? 48 : 87) + number; 5101cb0ef41Sopenharmony_ci 5111cb0ef41Sopenharmony_ci/** 5121cb0ef41Sopenharmony_ci * @param {ArrayBuffer} buf An ArrayBuffer. 5131cb0ef41Sopenharmony_ci * @return {bigint} 5141cb0ef41Sopenharmony_ci */ 5151cb0ef41Sopenharmony_cifunction arrayBufferToUnsignedBigInt(buf) { 5161cb0ef41Sopenharmony_ci const length = ArrayBufferPrototypeGetByteLength(buf); 5171cb0ef41Sopenharmony_ci const chars = Array(length * 2); 5181cb0ef41Sopenharmony_ci const view = new DataView(buf); 5191cb0ef41Sopenharmony_ci 5201cb0ef41Sopenharmony_ci for (let i = 0; i < length; i++) { 5211cb0ef41Sopenharmony_ci const val = DataViewPrototypeGetUint8(view, i); 5221cb0ef41Sopenharmony_ci chars[2 * i] = numberToHexCharCode(val >> 4); 5231cb0ef41Sopenharmony_ci chars[2 * i + 1] = numberToHexCharCode(val & 0xf); 5241cb0ef41Sopenharmony_ci } 5251cb0ef41Sopenharmony_ci 5261cb0ef41Sopenharmony_ci return BigInt(`0x${StringFromCharCodeApply(chars)}`); 5271cb0ef41Sopenharmony_ci} 5281cb0ef41Sopenharmony_ci 5291cb0ef41Sopenharmony_cifunction unsignedBigIntToBuffer(bigint, name) { 5301cb0ef41Sopenharmony_ci if (bigint < 0) { 5311cb0ef41Sopenharmony_ci throw new ERR_OUT_OF_RANGE(name, '>= 0', bigint); 5321cb0ef41Sopenharmony_ci } 5331cb0ef41Sopenharmony_ci 5341cb0ef41Sopenharmony_ci const hex = BigIntPrototypeToString(bigint, 16); 5351cb0ef41Sopenharmony_ci const padded = StringPrototypePadStart(hex, hex.length + (hex.length % 2), 0); 5361cb0ef41Sopenharmony_ci return Buffer.from(padded, 'hex'); 5371cb0ef41Sopenharmony_ci} 5381cb0ef41Sopenharmony_ci 5391cb0ef41Sopenharmony_cifunction checkPrime(candidate, options = kEmptyObject, callback) { 5401cb0ef41Sopenharmony_ci if (typeof candidate === 'bigint') 5411cb0ef41Sopenharmony_ci candidate = unsignedBigIntToBuffer(candidate, 'candidate'); 5421cb0ef41Sopenharmony_ci if (!isAnyArrayBuffer(candidate) && !isArrayBufferView(candidate)) { 5431cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE( 5441cb0ef41Sopenharmony_ci 'candidate', 5451cb0ef41Sopenharmony_ci [ 5461cb0ef41Sopenharmony_ci 'ArrayBuffer', 5471cb0ef41Sopenharmony_ci 'TypedArray', 5481cb0ef41Sopenharmony_ci 'Buffer', 5491cb0ef41Sopenharmony_ci 'DataView', 5501cb0ef41Sopenharmony_ci 'bigint', 5511cb0ef41Sopenharmony_ci ], 5521cb0ef41Sopenharmony_ci candidate, 5531cb0ef41Sopenharmony_ci ); 5541cb0ef41Sopenharmony_ci } 5551cb0ef41Sopenharmony_ci if (typeof options === 'function') { 5561cb0ef41Sopenharmony_ci callback = options; 5571cb0ef41Sopenharmony_ci options = kEmptyObject; 5581cb0ef41Sopenharmony_ci } 5591cb0ef41Sopenharmony_ci validateFunction(callback, 'callback'); 5601cb0ef41Sopenharmony_ci validateObject(options, 'options'); 5611cb0ef41Sopenharmony_ci const { 5621cb0ef41Sopenharmony_ci checks = 0, 5631cb0ef41Sopenharmony_ci } = options; 5641cb0ef41Sopenharmony_ci 5651cb0ef41Sopenharmony_ci // The checks option is unsigned but must fit into a signed C int for OpenSSL. 5661cb0ef41Sopenharmony_ci validateInt32(checks, 'options.checks', 0); 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_ci const job = new CheckPrimeJob(kCryptoJobAsync, candidate, checks); 5691cb0ef41Sopenharmony_ci job.ondone = callback; 5701cb0ef41Sopenharmony_ci job.run(); 5711cb0ef41Sopenharmony_ci} 5721cb0ef41Sopenharmony_ci 5731cb0ef41Sopenharmony_cifunction checkPrimeSync(candidate, options = kEmptyObject) { 5741cb0ef41Sopenharmony_ci if (typeof candidate === 'bigint') 5751cb0ef41Sopenharmony_ci candidate = unsignedBigIntToBuffer(candidate, 'candidate'); 5761cb0ef41Sopenharmony_ci if (!isAnyArrayBuffer(candidate) && !isArrayBufferView(candidate)) { 5771cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE( 5781cb0ef41Sopenharmony_ci 'candidate', 5791cb0ef41Sopenharmony_ci [ 5801cb0ef41Sopenharmony_ci 'ArrayBuffer', 5811cb0ef41Sopenharmony_ci 'TypedArray', 5821cb0ef41Sopenharmony_ci 'Buffer', 5831cb0ef41Sopenharmony_ci 'DataView', 5841cb0ef41Sopenharmony_ci 'bigint', 5851cb0ef41Sopenharmony_ci ], 5861cb0ef41Sopenharmony_ci candidate, 5871cb0ef41Sopenharmony_ci ); 5881cb0ef41Sopenharmony_ci } 5891cb0ef41Sopenharmony_ci validateObject(options, 'options'); 5901cb0ef41Sopenharmony_ci const { 5911cb0ef41Sopenharmony_ci checks = 0, 5921cb0ef41Sopenharmony_ci } = options; 5931cb0ef41Sopenharmony_ci 5941cb0ef41Sopenharmony_ci // The checks option is unsigned but must fit into a signed C int for OpenSSL. 5951cb0ef41Sopenharmony_ci validateInt32(checks, 'options.checks', 0); 5961cb0ef41Sopenharmony_ci 5971cb0ef41Sopenharmony_ci const job = new CheckPrimeJob(kCryptoJobSync, candidate, checks); 5981cb0ef41Sopenharmony_ci const { 0: err, 1: result } = job.run(); 5991cb0ef41Sopenharmony_ci if (err) 6001cb0ef41Sopenharmony_ci throw err; 6011cb0ef41Sopenharmony_ci 6021cb0ef41Sopenharmony_ci return result; 6031cb0ef41Sopenharmony_ci} 6041cb0ef41Sopenharmony_ci 6051cb0ef41Sopenharmony_cimodule.exports = { 6061cb0ef41Sopenharmony_ci checkPrime, 6071cb0ef41Sopenharmony_ci checkPrimeSync, 6081cb0ef41Sopenharmony_ci randomBytes, 6091cb0ef41Sopenharmony_ci randomFill, 6101cb0ef41Sopenharmony_ci randomFillSync, 6111cb0ef41Sopenharmony_ci randomInt, 6121cb0ef41Sopenharmony_ci getRandomValues, 6131cb0ef41Sopenharmony_ci randomUUID, 6141cb0ef41Sopenharmony_ci generatePrime, 6151cb0ef41Sopenharmony_ci generatePrimeSync, 6161cb0ef41Sopenharmony_ci}; 617