1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22// Flags: --pending-deprecation 23'use strict'; 24const common = require('../common'); 25 26if (!common.hasCrypto) 27 common.skip('missing crypto'); 28 29const assert = require('assert'); 30const crypto = require('crypto'); 31const { kMaxLength } = require('buffer'); 32const { inspect } = require('util'); 33 34const kMaxUint32 = Math.pow(2, 32) - 1; 35const kMaxPossibleLength = Math.min(kMaxLength, kMaxUint32); 36 37common.expectWarning('DeprecationWarning', 38 'crypto.pseudoRandomBytes is deprecated.', 'DEP0115'); 39 40{ 41 [crypto.randomBytes, crypto.pseudoRandomBytes].forEach((f) => { 42 [undefined, null, false, true, {}, []].forEach((value) => { 43 const errObj = { 44 code: 'ERR_INVALID_ARG_TYPE', 45 name: 'TypeError', 46 message: 'The "size" argument must be of type number.' + 47 common.invalidArgTypeHelper(value) 48 }; 49 assert.throws(() => f(value), errObj); 50 assert.throws(() => f(value, common.mustNotCall()), errObj); 51 }); 52 53 [-1, NaN, 2 ** 32].forEach((value) => { 54 const errObj = { 55 code: 'ERR_OUT_OF_RANGE', 56 name: 'RangeError', 57 message: 'The value of "size" is out of range. It must be >= 0 && <= ' + 58 `${kMaxPossibleLength}. Received ${value}` 59 }; 60 assert.throws(() => f(value), errObj); 61 assert.throws(() => f(value, common.mustNotCall()), errObj); 62 }); 63 64 [0, 1, 2, 4, 16, 256, 1024, 101.2].forEach((len) => { 65 f(len, common.mustCall((ex, buf) => { 66 assert.strictEqual(ex, null); 67 assert.strictEqual(buf.length, Math.floor(len)); 68 assert.ok(Buffer.isBuffer(buf)); 69 })); 70 }); 71 }); 72} 73 74{ 75 const buf = Buffer.alloc(10); 76 const before = buf.toString('hex'); 77 const after = crypto.randomFillSync(buf).toString('hex'); 78 assert.notStrictEqual(before, after); 79} 80 81{ 82 const buf = new Uint8Array(new Array(10).fill(0)); 83 const before = Buffer.from(buf).toString('hex'); 84 crypto.randomFillSync(buf); 85 const after = Buffer.from(buf).toString('hex'); 86 assert.notStrictEqual(before, after); 87} 88 89{ 90 [ 91 new Uint16Array(10), 92 new Uint32Array(10), 93 new Float32Array(10), 94 new Float64Array(10), 95 new DataView(new ArrayBuffer(10)) 96 ].forEach((buf) => { 97 const before = Buffer.from(buf.buffer).toString('hex'); 98 crypto.randomFillSync(buf); 99 const after = Buffer.from(buf.buffer).toString('hex'); 100 assert.notStrictEqual(before, after); 101 }); 102} 103 104{ 105 const buf = Buffer.alloc(10); 106 const before = buf.toString('hex'); 107 crypto.randomFill(buf, common.mustCall((err, buf) => { 108 assert.ifError(err); 109 const after = buf.toString('hex'); 110 assert.notStrictEqual(before, after); 111 })); 112} 113 114{ 115 const buf = new Uint8Array(new Array(10).fill(0)); 116 const before = Buffer.from(buf).toString('hex'); 117 crypto.randomFill(buf, common.mustCall((err, buf) => { 118 assert.ifError(err); 119 const after = Buffer.from(buf).toString('hex'); 120 assert.notStrictEqual(before, after); 121 })); 122} 123 124{ 125 [ 126 new Uint16Array(10), 127 new Uint32Array(10), 128 new Float32Array(10), 129 new Float64Array(10), 130 new DataView(new ArrayBuffer(10)) 131 ].forEach((buf) => { 132 const before = Buffer.from(buf.buffer).toString('hex'); 133 crypto.randomFill(buf, common.mustCall((err, buf) => { 134 assert.ifError(err); 135 const after = Buffer.from(buf.buffer).toString('hex'); 136 assert.notStrictEqual(before, after); 137 })); 138 }); 139} 140 141{ 142 const buf = Buffer.alloc(10); 143 const before = buf.toString('hex'); 144 crypto.randomFillSync(buf, 5, 5); 145 const after = buf.toString('hex'); 146 assert.notStrictEqual(before, after); 147 assert.deepStrictEqual(before.slice(0, 5), after.slice(0, 5)); 148} 149 150{ 151 const buf = new Uint8Array(new Array(10).fill(0)); 152 const before = Buffer.from(buf).toString('hex'); 153 crypto.randomFillSync(buf, 5, 5); 154 const after = Buffer.from(buf).toString('hex'); 155 assert.notStrictEqual(before, after); 156 assert.deepStrictEqual(before.slice(0, 5), after.slice(0, 5)); 157} 158 159{ 160 const buf = Buffer.alloc(10); 161 const before = buf.toString('hex'); 162 crypto.randomFillSync(buf, 5); 163 const after = buf.toString('hex'); 164 assert.notStrictEqual(before, after); 165 assert.deepStrictEqual(before.slice(0, 5), after.slice(0, 5)); 166} 167 168{ 169 const buf = Buffer.alloc(10); 170 const before = buf.toString('hex'); 171 crypto.randomFill(buf, 5, 5, common.mustCall((err, buf) => { 172 assert.ifError(err); 173 const after = buf.toString('hex'); 174 assert.notStrictEqual(before, after); 175 assert.deepStrictEqual(before.slice(0, 5), after.slice(0, 5)); 176 })); 177} 178 179{ 180 const buf = new Uint8Array(new Array(10).fill(0)); 181 const before = Buffer.from(buf).toString('hex'); 182 crypto.randomFill(buf, 5, 5, common.mustCall((err, buf) => { 183 assert.ifError(err); 184 const after = Buffer.from(buf).toString('hex'); 185 assert.notStrictEqual(before, after); 186 assert.deepStrictEqual(before.slice(0, 5), after.slice(0, 5)); 187 })); 188} 189 190{ 191 [ 192 Buffer.alloc(10), 193 new Uint8Array(new Array(10).fill(0)) 194 ].forEach((buf) => { 195 const len = Buffer.byteLength(buf); 196 assert.strictEqual(len, 10, `Expected byteLength of 10, got ${len}`); 197 198 const typeErrObj = { 199 code: 'ERR_INVALID_ARG_TYPE', 200 name: 'TypeError', 201 message: 'The "offset" argument must be of type number. ' + 202 "Received type string ('test')" 203 }; 204 205 assert.throws(() => crypto.randomFillSync(buf, 'test'), typeErrObj); 206 207 assert.throws( 208 () => crypto.randomFill(buf, 'test', common.mustNotCall()), 209 typeErrObj); 210 211 typeErrObj.message = typeErrObj.message.replace('offset', 'size'); 212 assert.throws(() => crypto.randomFillSync(buf, 0, 'test'), typeErrObj); 213 214 assert.throws( 215 () => crypto.randomFill(buf, 0, 'test', common.mustNotCall()), 216 typeErrObj 217 ); 218 219 [NaN, kMaxPossibleLength + 1, -10, (-1 >>> 0) + 1].forEach((offsetSize) => { 220 const errObj = { 221 code: 'ERR_OUT_OF_RANGE', 222 name: 'RangeError', 223 message: 'The value of "offset" is out of range. ' + 224 `It must be >= 0 && <= 10. Received ${offsetSize}` 225 }; 226 227 assert.throws(() => crypto.randomFillSync(buf, offsetSize), errObj); 228 229 assert.throws( 230 () => crypto.randomFill(buf, offsetSize, common.mustNotCall()), 231 errObj); 232 233 errObj.message = 'The value of "size" is out of range. It must be >= ' + 234 `0 && <= ${kMaxPossibleLength}. Received ${offsetSize}`; 235 assert.throws(() => crypto.randomFillSync(buf, 1, offsetSize), errObj); 236 237 assert.throws( 238 () => crypto.randomFill(buf, 1, offsetSize, common.mustNotCall()), 239 errObj 240 ); 241 }); 242 243 const rangeErrObj = { 244 code: 'ERR_OUT_OF_RANGE', 245 name: 'RangeError', 246 message: 'The value of "size + offset" is out of range. ' + 247 'It must be <= 10. Received 11' 248 }; 249 assert.throws(() => crypto.randomFillSync(buf, 1, 10), rangeErrObj); 250 251 assert.throws( 252 () => crypto.randomFill(buf, 1, 10, common.mustNotCall()), 253 rangeErrObj 254 ); 255 }); 256} 257 258// https://github.com/nodejs/node-v0.x-archive/issues/5126, 259// "FATAL ERROR: v8::Object::SetIndexedPropertiesToExternalArrayData() length 260// exceeds max acceptable value" 261assert.throws( 262 () => crypto.randomBytes((-1 >>> 0) + 1), 263 { 264 code: 'ERR_OUT_OF_RANGE', 265 name: 'RangeError', 266 message: 'The value of "size" is out of range. ' + 267 `It must be >= 0 && <= ${kMaxPossibleLength}. Received 4294967296` 268 } 269); 270 271[1, true, NaN, null, undefined, {}, []].forEach((i) => { 272 const buf = Buffer.alloc(10); 273 assert.throws( 274 () => crypto.randomFillSync(i), 275 { 276 code: 'ERR_INVALID_ARG_TYPE', 277 name: 'TypeError' 278 } 279 ); 280 assert.throws( 281 () => crypto.randomFill(i, common.mustNotCall()), 282 { 283 code: 'ERR_INVALID_ARG_TYPE', 284 name: 'TypeError' 285 } 286 ); 287 assert.throws( 288 () => crypto.randomFill(buf, 0, 10, i), 289 { 290 code: 'ERR_INVALID_CALLBACK', 291 name: 'TypeError', 292 message: `Callback must be a function. Received ${inspect(i)}` 293 }); 294}); 295 296[1, true, NaN, null, {}, []].forEach((i) => { 297 assert.throws( 298 () => crypto.randomBytes(1, i), 299 { 300 code: 'ERR_INVALID_CALLBACK', 301 name: 'TypeError', 302 message: `Callback must be a function. Received ${inspect(i)}` 303 } 304 ); 305}); 306 307 308['pseudoRandomBytes', 'prng', 'rng'].forEach((f) => { 309 const desc = Object.getOwnPropertyDescriptor(crypto, f); 310 assert.ok(desc); 311 assert.strictEqual(desc.configurable, true); 312 assert.strictEqual(desc.writable, true); 313 assert.strictEqual(desc.enumerable, false); 314}); 315 316 317{ 318 // Asynchronous API 319 const randomInts = []; 320 for (let i = 0; i < 100; i++) { 321 crypto.randomInt(3, common.mustCall((err, n) => { 322 assert.ifError(err); 323 assert.ok(n >= 0); 324 assert.ok(n < 3); 325 randomInts.push(n); 326 if (randomInts.length === 100) { 327 assert.ok(!randomInts.includes(-1)); 328 assert.ok(randomInts.includes(0)); 329 assert.ok(randomInts.includes(1)); 330 assert.ok(randomInts.includes(2)); 331 assert.ok(!randomInts.includes(3)); 332 } 333 })); 334 } 335} 336{ 337 // Synchronous API 338 const randomInts = []; 339 for (let i = 0; i < 100; i++) { 340 const n = crypto.randomInt(3); 341 assert.ok(n >= 0); 342 assert.ok(n < 3); 343 randomInts.push(n); 344 } 345 346 assert.ok(!randomInts.includes(-1)); 347 assert.ok(randomInts.includes(0)); 348 assert.ok(randomInts.includes(1)); 349 assert.ok(randomInts.includes(2)); 350 assert.ok(!randomInts.includes(3)); 351} 352{ 353 // Positive range 354 const randomInts = []; 355 for (let i = 0; i < 100; i++) { 356 crypto.randomInt(1, 3, common.mustCall((err, n) => { 357 assert.ifError(err); 358 assert.ok(n >= 1); 359 assert.ok(n < 3); 360 randomInts.push(n); 361 if (randomInts.length === 100) { 362 assert.ok(!randomInts.includes(0)); 363 assert.ok(randomInts.includes(1)); 364 assert.ok(randomInts.includes(2)); 365 assert.ok(!randomInts.includes(3)); 366 } 367 })); 368 } 369} 370{ 371 // Negative range 372 const randomInts = []; 373 for (let i = 0; i < 100; i++) { 374 crypto.randomInt(-10, -8, common.mustCall((err, n) => { 375 assert.ifError(err); 376 assert.ok(n >= -10); 377 assert.ok(n < -8); 378 randomInts.push(n); 379 if (randomInts.length === 100) { 380 assert.ok(!randomInts.includes(-11)); 381 assert.ok(randomInts.includes(-10)); 382 assert.ok(randomInts.includes(-9)); 383 assert.ok(!randomInts.includes(-8)); 384 } 385 })); 386 } 387} 388{ 389 390 ['10', true, NaN, null, {}, []].forEach((i) => { 391 const invalidMinError = { 392 code: 'ERR_INVALID_ARG_TYPE', 393 name: 'TypeError', 394 message: 'The "min" argument must be a safe integer.' + 395 `${common.invalidArgTypeHelper(i)}`, 396 }; 397 const invalidMaxError = { 398 code: 'ERR_INVALID_ARG_TYPE', 399 name: 'TypeError', 400 message: 'The "max" argument must be a safe integer.' + 401 `${common.invalidArgTypeHelper(i)}`, 402 }; 403 404 assert.throws( 405 () => crypto.randomInt(i, 100), 406 invalidMinError 407 ); 408 assert.throws( 409 () => crypto.randomInt(i, 100, common.mustNotCall()), 410 invalidMinError 411 ); 412 assert.throws( 413 () => crypto.randomInt(i), 414 invalidMaxError 415 ); 416 assert.throws( 417 () => crypto.randomInt(i, common.mustNotCall()), 418 invalidMaxError 419 ); 420 assert.throws( 421 () => crypto.randomInt(0, i, common.mustNotCall()), 422 invalidMaxError 423 ); 424 assert.throws( 425 () => crypto.randomInt(0, i), 426 invalidMaxError 427 ); 428 }); 429 430 const maxInt = Number.MAX_SAFE_INTEGER; 431 const minInt = Number.MIN_SAFE_INTEGER; 432 433 crypto.randomInt(minInt, minInt + 5, common.mustCall()); 434 crypto.randomInt(maxInt - 5, maxInt, common.mustCall()); 435 436 assert.throws( 437 () => crypto.randomInt(minInt - 1, minInt + 5, common.mustNotCall()), 438 { 439 code: 'ERR_INVALID_ARG_TYPE', 440 name: 'TypeError', 441 message: 'The "min" argument must be a safe integer.' + 442 `${common.invalidArgTypeHelper(minInt - 1)}`, 443 } 444 ); 445 446 assert.throws( 447 () => crypto.randomInt(maxInt + 1, common.mustNotCall()), 448 { 449 code: 'ERR_INVALID_ARG_TYPE', 450 name: 'TypeError', 451 message: 'The "max" argument must be a safe integer.' + 452 `${common.invalidArgTypeHelper(maxInt + 1)}`, 453 } 454 ); 455 456 crypto.randomInt(1, common.mustCall()); 457 crypto.randomInt(0, 1, common.mustCall()); 458 for (const arg of [[0], [1, 1], [3, 2], [-5, -5], [11, -10]]) { 459 assert.throws(() => crypto.randomInt(...arg, common.mustNotCall()), { 460 code: 'ERR_OUT_OF_RANGE', 461 name: 'RangeError', 462 message: 'The value of "max" is out of range. It must be greater than ' + 463 `the value of "min" (${arg[arg.length - 2] || 0}). ` + 464 `Received ${arg[arg.length - 1]}` 465 }); 466 } 467 468 const MAX_RANGE = 0xFFFF_FFFF_FFFF; 469 crypto.randomInt(MAX_RANGE, common.mustCall()); 470 crypto.randomInt(1, MAX_RANGE + 1, common.mustCall()); 471 assert.throws( 472 () => crypto.randomInt(1, MAX_RANGE + 2, common.mustNotCall()), 473 { 474 code: 'ERR_OUT_OF_RANGE', 475 name: 'RangeError', 476 message: 'The value of "max - min" is out of range. ' + 477 `It must be <= ${MAX_RANGE}. ` + 478 'Received 281_474_976_710_656' 479 } 480 ); 481 482 assert.throws(() => crypto.randomInt(MAX_RANGE + 1, common.mustNotCall()), { 483 code: 'ERR_OUT_OF_RANGE', 484 name: 'RangeError', 485 message: 'The value of "max" is out of range. ' + 486 `It must be <= ${MAX_RANGE}. ` + 487 'Received 281_474_976_710_656' 488 }); 489 490 [true, NaN, null, {}, [], 10].forEach((i) => { 491 const cbError = { 492 code: 'ERR_INVALID_CALLBACK', 493 name: 'TypeError', 494 message: `Callback must be a function. Received ${inspect(i)}` 495 }; 496 assert.throws(() => crypto.randomInt(0, 1, i), cbError); 497 }); 498} 499