generator.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Copyright 2018 Scytl Secure Electronic Voting SA
  3. *
  4. * All rights reserved
  5. *
  6. * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
  7. */
  8. /* jshint node:true */
  9. 'use strict';
  10. var validator = require('./input-validator');
  11. var constants = require('./constants');
  12. var codec = require('scytl-codec');
  13. var forge = require('node-forge');
  14. var BigInteger = forge.jsbn.BigInteger;
  15. module.exports = SecureRandomGenerator;
  16. /**
  17. * @class SecureRandomGenerator
  18. * @classdesc The secure random generator API. To instantiate this object, use
  19. * the method {@link SecureRandomService.newRandomGenerator}.
  20. * @hideconstructor
  21. * @param {Prng}
  22. * prng The pseudo-random number generator (PRNG) to use.
  23. * @param {Object}
  24. * [options] An object containing optional arguments.
  25. * @param {number}
  26. * [options.maxNumBytes=512] The maximum number of bytes that can be
  27. * randomly generated per call.
  28. * @param {number}
  29. * [options.maxNumDigits=512] The maximum number of BigInteger digits
  30. * that can be randomly generated per call.
  31. */
  32. function SecureRandomGenerator(prng, options) {
  33. options = options || {};
  34. var maxNumBytes_ =
  35. options.maxNumBytes || constants.SECURE_RANDOM_MAX_NUM_BYTES;
  36. var maxNumDigits_ =
  37. options.maxNumDigits || constants.SECURE_RANDOM_MAX_NUM_DIGITS;
  38. /**
  39. * Generates some random bytes.
  40. *
  41. * @function nextBytes
  42. * @memberof SecureRandomGenerator
  43. * @param {number}
  44. * numBytes The number of bytes to generate.
  45. * @return {Uint8Array} The random bytes.
  46. * @throws {Error}
  47. * If the input data validation fails.
  48. */
  49. this.nextBytes = function(numBytes) {
  50. checkData(numBytes, maxNumBytes_, 'Number of bytes to randomly generate');
  51. return prng.nextBytes(numBytes);
  52. };
  53. /**
  54. * Generates a random positive BigInteger object, with a specified maximum
  55. * number of bits.
  56. *
  57. * @function nextBigInteger
  58. * @memberof SecureRandomGenerator
  59. * @param {number}
  60. * maxNumBits The maximum number of bits in the BigInteger
  61. * object.
  62. * @returns {BigInteger} The random BigInteger object.
  63. * @throws {Error}
  64. * If the input data validation fails.
  65. */
  66. this.nextBigInteger = function(maxNumBits) {
  67. validator.checkIsPositiveNumber(
  68. maxNumBits,
  69. 'Maximum number of bits in BigInteger to randomly generate');
  70. // Find minimum number of bytes needed for maximum number of bits.
  71. var numBytes = Math.ceil(maxNumBits / 8);
  72. var numExcessBits = 8 - (maxNumBits % 8);
  73. var randomBytes = prng.nextBytes(numBytes);
  74. var randomByteArray = Array.apply([], randomBytes);
  75. randomByteArray.unshift(0);
  76. var generatedBigInteger = codec.bytesToBigInteger(randomBytes);
  77. return generatedBigInteger.shiftRight(numExcessBits);
  78. };
  79. /**
  80. * Generates a random positive BigInteger object, with a specified maximum
  81. * number of digits.
  82. *
  83. * @function nextBigIntegerByDigits
  84. * @memberof SecureRandomGenerator
  85. * @param {number}
  86. * numDigits The maximum number of digits in the BigInteger
  87. * object value.
  88. * @returns {BigInteger} The random BigInteger object.
  89. * @throws {Error}
  90. * If the input data validation fails.
  91. */
  92. this.nextBigIntegerByDigits = function(numDigits) {
  93. checkData(
  94. numDigits, maxNumDigits_,
  95. 'Number of digits in BigInteger to randomly generate');
  96. // Variable n is largest possible number for given number of digits. For
  97. // instance, for 3 digits, n would be 999.
  98. var n = ((new BigInteger('10')).pow(numDigits)).subtract(BigInteger.ONE);
  99. // Get number of bits needed to represent n.
  100. var numBits = n.bitLength();
  101. // Get minimum number of bytes needed to represent n.
  102. var numBytes = Math.ceil(numBits / 8);
  103. // Continuously generate numbers until number is found that is smaller than
  104. // n. Note: This will take just one round if number of bits is a multiple
  105. // of 8.
  106. var generatedBigInteger;
  107. do {
  108. var randomBytes = prng.nextBytes(numBytes);
  109. var randomByteArray = Array.apply([], randomBytes);
  110. randomByteArray.unshift(0);
  111. generatedBigInteger = codec.bytesToBigInteger(randomBytes);
  112. } while ((generatedBigInteger.compareTo(BigInteger.ZERO) <= 0) ||
  113. (generatedBigInteger.compareTo(n) > 0));
  114. return generatedBigInteger;
  115. };
  116. /**
  117. * Implementation of the method <code>getBytesSync</code> so that this random
  118. * generator can be used directly by Forge.
  119. *
  120. * @function getBytesSync
  121. * @memberof SecureRandomGenerator
  122. * @private
  123. * @param {number}
  124. * numBytes The number of bytes to generate.
  125. * @returns {string} The random bytes, in binary encoded format.
  126. */
  127. this.getBytesSync = function(numBytes) {
  128. return codec.binaryEncode(this.nextBytes(numBytes));
  129. };
  130. function checkData(num, max, label) {
  131. validator.checkIsPositiveNumber(num, label);
  132. if (num > max) {
  133. throw new Error(
  134. 'Expected ' + label + ' to be less than or equal to ' + max +
  135. ' ; Found: ' + num);
  136. }
  137. }
  138. }