123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- /*
- * Copyright 2018 Scytl Secure Electronic Voting SA
- *
- * All rights reserved
- *
- * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
- */
- /* jshint node:true */
- 'use strict';
- var validator = require('./input-validator');
- var constants = require('./constants');
- var codec = require('scytl-codec');
- var forge = require('node-forge');
- var BigInteger = forge.jsbn.BigInteger;
- module.exports = SecureRandomGenerator;
- /**
- * @class SecureRandomGenerator
- * @classdesc The secure random generator API. To instantiate this object, use
- * the method {@link SecureRandomService.newRandomGenerator}.
- * @hideconstructor
- * @param {Prng}
- * prng The pseudo-random number generator (PRNG) to use.
- * @param {Object}
- * [options] An object containing optional arguments.
- * @param {number}
- * [options.maxNumBytes=512] The maximum number of bytes that can be
- * randomly generated per call.
- * @param {number}
- * [options.maxNumDigits=512] The maximum number of BigInteger digits
- * that can be randomly generated per call.
- */
- function SecureRandomGenerator(prng, options) {
- options = options || {};
- var maxNumBytes_ =
- options.maxNumBytes || constants.SECURE_RANDOM_MAX_NUM_BYTES;
- var maxNumDigits_ =
- options.maxNumDigits || constants.SECURE_RANDOM_MAX_NUM_DIGITS;
- /**
- * Generates some random bytes.
- *
- * @function nextBytes
- * @memberof SecureRandomGenerator
- * @param {number}
- * numBytes The number of bytes to generate.
- * @return {Uint8Array} The random bytes.
- * @throws {Error}
- * If the input data validation fails.
- */
- this.nextBytes = function(numBytes) {
- checkData(numBytes, maxNumBytes_, 'Number of bytes to randomly generate');
- return prng.nextBytes(numBytes);
- };
- /**
- * Generates a random positive BigInteger object, with a specified maximum
- * number of bits.
- *
- * @function nextBigInteger
- * @memberof SecureRandomGenerator
- * @param {number}
- * maxNumBits The maximum number of bits in the BigInteger
- * object.
- * @returns {BigInteger} The random BigInteger object.
- * @throws {Error}
- * If the input data validation fails.
- */
- this.nextBigInteger = function(maxNumBits) {
- validator.checkIsPositiveNumber(
- maxNumBits,
- 'Maximum number of bits in BigInteger to randomly generate');
- // Find minimum number of bytes needed for maximum number of bits.
- var numBytes = Math.ceil(maxNumBits / 8);
- var numExcessBits = 8 - (maxNumBits % 8);
- var randomBytes = prng.nextBytes(numBytes);
- var randomByteArray = Array.apply([], randomBytes);
- randomByteArray.unshift(0);
- var generatedBigInteger = codec.bytesToBigInteger(randomBytes);
- return generatedBigInteger.shiftRight(numExcessBits);
- };
- /**
- * Generates a random positive BigInteger object, with a specified maximum
- * number of digits.
- *
- * @function nextBigIntegerByDigits
- * @memberof SecureRandomGenerator
- * @param {number}
- * numDigits The maximum number of digits in the BigInteger
- * object value.
- * @returns {BigInteger} The random BigInteger object.
- * @throws {Error}
- * If the input data validation fails.
- */
- this.nextBigIntegerByDigits = function(numDigits) {
- checkData(
- numDigits, maxNumDigits_,
- 'Number of digits in BigInteger to randomly generate');
- // Variable n is largest possible number for given number of digits. For
- // instance, for 3 digits, n would be 999.
- var n = ((new BigInteger('10')).pow(numDigits)).subtract(BigInteger.ONE);
- // Get number of bits needed to represent n.
- var numBits = n.bitLength();
- // Get minimum number of bytes needed to represent n.
- var numBytes = Math.ceil(numBits / 8);
- // Continuously generate numbers until number is found that is smaller than
- // n. Note: This will take just one round if number of bits is a multiple
- // of 8.
- var generatedBigInteger;
- do {
- var randomBytes = prng.nextBytes(numBytes);
- var randomByteArray = Array.apply([], randomBytes);
- randomByteArray.unshift(0);
- generatedBigInteger = codec.bytesToBigInteger(randomBytes);
- } while ((generatedBigInteger.compareTo(BigInteger.ZERO) <= 0) ||
- (generatedBigInteger.compareTo(n) > 0));
- return generatedBigInteger;
- };
- /**
- * Implementation of the method <code>getBytesSync</code> so that this random
- * generator can be used directly by Forge.
- *
- * @function getBytesSync
- * @memberof SecureRandomGenerator
- * @private
- * @param {number}
- * numBytes The number of bytes to generate.
- * @returns {string} The random bytes, in binary encoded format.
- */
- this.getBytesSync = function(numBytes) {
- return codec.binaryEncode(this.nextBytes(numBytes));
- };
- function checkData(num, max, label) {
- validator.checkIsPositiveNumber(num, label);
- if (num > max) {
- throw new Error(
- 'Expected ' + label + ' to be less than or equal to ' + max +
- ' ; Found: ' + num);
- }
- }
- }
|