/*
* 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);
}