/* * 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 SecureRandomGenerator = require('./generator'); var PrivateKeyCollector = require('./entropy/collectors/privatekey'); var EntropyManager = require('./entropy/manager'); var Prng = require('./prng'); var constants = require('./constants'); module.exports = SecureRandomService; /** * @class SecureRandomService * @classdesc The secure random service API. To instantiate this object, use the * method {@link newService}. * @hideconstructor * @param {Object} * [options] An object containing optional arguments. * @param {Uint8Array} * [options.prngSeed=Internally generated] The seed to initialize the * PRNG. * @param {number} * [options.maxEntropyCounter=256] The amount of entropy to * accumulate before stopping collectors. It must be a positive * number. * @param {number} * [options.hashUpdaterInterval=1000] The interval (in milliseconds) * at which entropy data is to be hashed. It must be a positive * number. * @param {Object} * [options.windowObject=Built-in window object] The * window object provided to the collectors. * @param {Object} * [options.cryptoApi=Built-in cryptographic library] The * cryptographic library supplied to the WebKit collector (if the * latter is being used). * @param {Object} * [options.privateKeyData=Not used] The private key collector data. * @param {string} * options.privateKeyData.privateKey The private key, in PEM format. * @param {number} * options.privateKeyData.pinEntropy The PIN entropy of the private * key. It must be a positive number. * @param {boolean} * [options.noDefaultCollectors=false] If true, no * default entropy collectors are to be used. */ function SecureRandomService(options) { ////////////////////////////////// PRIVATE ////////////////////////////////// var prng_; var entropyManager_; function init(options) { options = options || {}; if (options.prngSeed) { prng_ = new Prng(options.prngSeed); } entropyManager_ = new EntropyManager(options); if (options.privateKeyData) { var privateKey = options.privateKeyData.privateKey; var pinEntropy = options.privateKeyData.pinEntropy; entropyManager_.addCollector(new PrivateKeyCollector( entropyManager_.collectEntropy, privateKey, pinEntropy)); } entropyManager_.startCollectors(); entropyManager_.stopCollectors(); } function getPrng() { if (!prng_) { prng_ = new Prng(entropyManager_.getEntropyHash()); } return prng_; } /////////////////////////////////// PUBLIC /////////////////////////////////// /** * Creates a new SecureRandomGenerator object, that uses the PRNG of this * service. This object can be used for all supported types of random * generation. * * @function newRandomGenerator * @memberof SecureRandomService * @param {Object} * [options] An object containing optional arguments. * @param {number} * [options.maxNumBytes=512] The maximum number of bytes that can * randomly generated per method call. * @param {number} * [options.maxNumDigits=512] The maximum number of BigInteger * digits that can randomly generated per method call. * @returns {SecureRandomGenerator} The new SecureRandomGenerator object. */ this.newRandomGenerator = function(options) { return new SecureRandomGenerator(getPrng(), options); }; /** * Generates a random seed that can be used to initialize the PRNG of a new * SecureRandomService object. * * @function nextSeed * @memberof SecureRandomService * @param {number} * [numBytes=32] The number of bytes in the seed. * @returns {Uint8Array} The random seed. */ this.nextSeed = function(numBytes) { numBytes = numBytes || constants.SECURE_RANDOM_DEFAULT_NUM_SEED_BYTES; return getPrng().nextBytes(numBytes); }; /** * Manually starts the entropy collection. This method has no effect if * entropy is already being collected. * * @function startEntropyCollection * @memberof SecureRandomService * @param {Function} * [callback=No callback] A callback function that will be * executed if the maximum amount of entropy required is * collected. */ this.startEntropyCollection = function(callback) { entropyManager_.startCollectors(callback); }; /** * Manually stops the entropy collection and resets the PRNG with the * collected entropy. * * @function stopEntropyCollection * @memberof SecureRandomService * @returns {boolean} true if the maximum amount of entropy * required has been collected, false otherwise. */ this.stopEntropyCollection = function() { var maxEntropyCollected = entropyManager_.stopCollectors(); prng_ = new Prng(entropyManager_.getEntropyHash()); return maxEntropyCollected; }; /** * Retrieves the amount of entropy collected, as a percentage of the maximum * amount of entropy required. * * @function getEntropyPercentage * @memberof SecureRandomService * @returns {number} The percentage of entropy collected. */ this.getEntropyPercentage = function() { return entropyManager_.getEntropyPercentage(); }; //////////////////////////////// CONSTRUCTOR //////////////////////////////// // Initialize the object. init(options); }