123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- /*
- * 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, jasmine:true */
- 'use strict';
- var secureRandom = require('../lib/index');
- var constants = require('../lib/constants');
- var codec = require('scytl-codec');
- var forge = require('node-forge');
- var BigInteger = forge.jsbn.BigInteger;
- describe('The secure random module should be able to ...', function() {
- var TEST_SEED = new Uint8Array([18, 58, 188]);
- var PRIVATE_KEY_PEM =
- '-----BEGIN RSA PRIVATE KEY-----MIIEowIBAAKCAQEAglypZU45bnf2opnRI+Y51VqouBpvDT33xIB/OtbwKzwVpi+JrjBFtfk33tE9t/dSRs79CK94HRhCWcOiLa2qWPrjeZ9SBiEyScrhIvRZVBF41zBgwQNuRvJCsKmAqlZaFNJDZxEP4repmlBn1CfVFmfrXmOKqwP5F7l9ZtucveRzsfmF1yVPFkW8TMuB3YqMiyymyqHlS8ujCsu5I8tpgPbwuxdMOY94fNhSXrYkY8IuX1g1zdq/Z1jluOaR/UqK4UpnbuJaH/F0VgDNiWh6cTD0DFGEk0b70i5wU4Q3L/S6XZQRvSuADoCbhwBKuFL5pW5n865oLVb5S3wuVdWaGwIDAQABAoIBAC/tn34Wf3kE9BGeGc1oFLVDaqqdVVz5/oEpeR2J7q0GnzMFYUpAhzC7WvY52cYsUPyll1Q9Jx0TUTmteo/uvKWQQFfz4nVMeS+2PoXabolBDzuWlsv/1eiRo0FOYHa/3siu8YcQN9X0DpAkpbfTmT1uoZOHZ3EuucMmOFu7vGn38Grw8bSxpR0uvTtnb8ygC+aB51y38RMyhzQQanrM8FMeAfDAy6IB0Yo7b0c50Cxa6Ax4nqn9LXyGakr5WeAMkgTIOA/GId9SZD4e5eRpq+628pOeR4O9datFltgl6r1+A4ii2VrJsDqeatGtODlX6KRKqwFHoGIa2TjgSZLuorECgYEAxeSZDOOgFsI5mB7RkRzZaQ9znJ15sgdyZiAFZAOUah4hSGdAXNAnZTlrdacduXEu3EfkpuPToX7xZSv5FRYwfBwMwCLeytlGLPjQzWejZGbo4+KqgzWb9fECDYVtDPlJ/+yLih9nt67BHweJKxYydl18rVigdVyy22X86NijSykCgYEAqKPUrXZAo+TJvmTw4tgsibJgvXBYBhmsej8mGNQw+Nyp2gV28sgm61ifIeXKS8teq+MFwGA6cHQedbsCqhMHokdhESZmlbWxhSFLihQcewBxwvrBwbaxI23yXRzwMewznZFL032PpcbqrmwFmcSSEZ3nmbvTH6ShqLW+pzDNp6MCgYBQLzdgxJ7qedqSa/JohTMG4e7rh9d2rpPJE7J7ewPZF8pOpx+qO+Gqn2COdJ+Ts2vUcAETKn9nEaPIZc/wnmQY9dioxbhWo0FPGaaphBPtq9Ez/XUv4zoFppk5V1X/isdUPsmvttf00oeIBiqrXbwmv+yz5JRn2Z7TTXjz9Ev+OQKBgQCUuoCMRzl1EgcXIqEL/0kwW6BUEqufHa9u1Ri9Vw6lvL8T6DPipMEmWK9nzuid9gtVns/ovTVtDgv7GuabplLaPQePf4WDzY11c0rSyS/hDyBFrK+LL5uEOqhAlJAGB2HyOj1clWVF+GvrTpuV5LZKUS/79pmZU7G7QCaX/0Ow7wKBgC/kDH7cmWQnWvvJ5izrx/7PogQVPOLELeUIGLu/hjsSdDKiFCxCUZ948+9NuG+DnpXDWzw//r8mPBRRGGsqFws5Aipp7yjQ3kRDCCzGelPCVhHyfmKqA+8ewXPulKS3/wIyHIvaXmsuAtTfurHtpRyzjKmCBK1Y6WQ3trIXvo7s-----END RSA PRIVATE KEY-----';
- var PIN_ENTROPY = 100;
- var service_;
- var randomGenerator_;
- beforeEach(function() {
- service_ = secureRandom.newService();
- randomGenerator_ = service_.newRandomGenerator();
- });
- describe('create a secure random service that should be able to ..', function() {
- describe(
- 'create a secure random generator that should be able to', function() {
- it('generate 10 random bytes', function() {
- var numBytes = 10;
- var bytes = randomGenerator_.nextBytes(numBytes);
- expect(bytes).toBeDefined();
- expect(bytes.length).not.toBeGreaterThan(numBytes);
- });
- it('generate a specified number of random bytes', function() {
- var numBytes = 16;
- var bytes = randomGenerator_.nextBytes(numBytes);
- expect(bytes).toBeDefined();
- expect(bytes.numBytes).not.toBeGreaterThan(numBytes);
- });
- it('generate a random BigInteger of a specified maximum bit length',
- function() {
- for (var maxNumBits = 1; maxNumBits <= 20; maxNumBits++) {
- var randomBigInteger =
- randomGenerator_.nextBigInteger(maxNumBits);
- expect(randomBigInteger).not.toBeLessThan(0);
- expect(randomBigInteger.bitLength())
- .not.toBeGreaterThan(maxNumBits);
- }
- });
- it('generate a random BigInteger of a specified number of digits',
- function() {
- var maxValue;
- for (var numDigits = 1; numDigits <= 10; numDigits++) {
- maxValue = Math.pow(10, numDigits);
- var randomBigInteger =
- randomGenerator_.nextBigIntegerByDigits(numDigits);
- expect(randomBigInteger.compareTo(BigInteger.ZERO))
- .toBeGreaterThan(0);
- expect(randomBigInteger.compareTo(
- new BigInteger(maxValue.toString())))
- .toBeLessThan(0);
- }
- });
- it('be created by specifying a maximum allowed number of bytes',
- function() {
- var maxNumBytes = constants.SECURE_RANDOM_MAX_NUM_BYTES + 1;
- var randomGenerator_ =
- service_.newRandomGenerator({maxNumBytes: maxNumBytes});
- var randomBytes = randomGenerator_.nextBytes(maxNumBytes);
- expect(randomBytes).toBeDefined();
- expect(randomBytes.length).not.toBeGreaterThan(maxNumBytes);
- expect(function() {
- randomGenerator_.nextBytes(maxNumBytes + 1);
- }).toThrow();
- });
- it('be created by specifying maximum allowed number of digits',
- function() {
- var maxNumDigits = constants.SECURE_RANDOM_MAX_NUM_BYTES + 1;
- var randomGenerator_ =
- service_.newRandomGenerator({maxNumDigits: maxNumDigits});
- var randomBigInteger =
- randomGenerator_.nextBigIntegerByDigits(maxNumDigits);
- expect(randomBigInteger).toBeDefined();
- expect(randomBigInteger.compareTo(BigInteger.ZERO))
- .toBeGreaterThan(0);
- expect(randomBigInteger.compareTo(
- new BigInteger('10').pow(maxNumDigits)))
- .toBeLessThan(0);
- expect(function() {
- randomGenerator_.nextBigIntegerByDigits(maxNumDigits + 1);
- }).toThrow();
- });
- it('throw an exception when a negative input argument is passed',
- function() {
- expect(function() {
- randomGenerator_.nextBytes(-1);
- }).toThrow();
- expect(function() {
- randomGenerator_.nextBigInteger(-1);
- }).toThrow();
- expect(function() {
- randomGenerator_.nextBigIntegerByDigits(-1);
- }).toThrow();
- });
- it('throw an exception when a non-numeric input argument is passed',
- function() {
- expect(function() {
- randomGenerator_.nextBytes('abc');
- }).toThrow();
- expect(function() {
- randomGenerator_.nextBigInteger('abc');
- }).toThrow();
- expect(function() {
- randomGenerator_.nextBigIntegerByDigits('abc');
- }).toThrow();
- });
- it('throw an exception when a too-large input argument is passed',
- function() {
- expect(function() {
- randomGenerator_.nextBytes(
- constants.SECURE_RANDOM_MAX_NUM_BYTES + 1);
- }).toThrow();
- expect(function() {
- randomGenerator_.nextBigIntegerByDigits(
- constants.SECURE_RANDOM_MAX_NUM_DIGITS + 1);
- }).toThrow();
- });
- });
- it('initialize its PRNG from a provided seed', function() {
- var service = secureRandom.newService(
- {prngSeed: TEST_SEED, noDefaultCollectors: true});
- var randomGenerator = service.newRandomGenerator();
- expect(randomGenerator.nextBigIntegerByDigits(2).toString())
- .toEqual('21');
- expect(randomGenerator.nextBigIntegerByDigits(4).toString())
- .toEqual('2950');
- expect(randomGenerator.nextBigIntegerByDigits(16).toString())
- .toEqual('5574593524320719');
- });
- it('generate a random seed to instantiate other secure random services',
- function() {
- var seed = service_.nextSeed();
- expect(seed.length)
- .toBe(constants.SECURE_RANDOM_DEFAULT_NUM_SEED_BYTES);
- seed = service_.nextSeed(16);
- expect(seed.length).toBe(16);
- var service1 = secureRandom.newService(
- {prngSeed: seed, noDefaultCollectors: true});
- var randomGenerator1 = service1.newRandomGenerator();
- var randomInt1 = randomGenerator1.nextBigIntegerByDigits(2);
- var service2 = secureRandom.newService(
- {prngSeed: seed, noDefaultCollectors: true});
- var randomGenerator2 = service2.newRandomGenerator();
- var randomInt2 = randomGenerator2.nextBigIntegerByDigits(2);
- expect(randomInt1).toEqual(randomInt2);
- });
- it('create two different secure random generators that use the same PRNG',
- function() {
- var service = secureRandom.newService(
- {prngSeed: TEST_SEED, noDefaultCollectors: true});
- var randomGenerator1 = service.newRandomGenerator();
- var randomGenerator2 = service.newRandomGenerator();
- expect(randomGenerator1.nextBigIntegerByDigits(2).toString())
- .toEqual('21');
- expect(randomGenerator1.nextBigIntegerByDigits(4).toString())
- .toEqual('2950');
- expect(randomGenerator1.nextBigIntegerByDigits(16).toString())
- .toEqual('5574593524320719');
- expect(randomGenerator2.nextBigIntegerByDigits(2).toString())
- .toEqual('12');
- expect(randomGenerator2.nextBigIntegerByDigits(4).toString())
- .toEqual('6576');
- expect(randomGenerator2.nextBigIntegerByDigits(16).toString())
- .toEqual('2672997009079990');
- });
- it('start and stop the entropy collection manually', function() {
- var callbackCalled = false;
- var callback = function() {
- callbackCalled = true;
- };
- service_.startEntropyCollection(callback);
- var maxEntropyCollected = service_.stopEntropyCollection();
- expect(callbackCalled).toBeTruthy();
- expect(typeof maxEntropyCollected).toBe('boolean');
- });
- it('measure the entropy collected as a percentage of the maximum entropy required',
- function() {
- var service = secureRandom.newService({noDefaultCollectors: true});
- service.startEntropyCollection();
- service.stopEntropyCollection();
- expect(service.getEntropyPercentage()).toBe(0);
- service = secureRandom.newService();
- service.startEntropyCollection();
- service.stopEntropyCollection();
- expect(service.getEntropyPercentage()).toBeGreaterThan(0);
- expect(service.getEntropyPercentage()).toBeLessThan(101);
- });
- it('collect some entropy with the maximum entropy counter option set',
- function() {
- var service = secureRandom.newService({maxEntropyCounter: 150});
- expect(service.getEntropyPercentage()).toBeGreaterThan(0);
- expect(service.getEntropyPercentage()).toBeLessThan(101);
- });
- it('collect some entropy with the hash updater interval option set',
- function() {
- var service = secureRandom.newService({hashUpdaterInterval: 500});
- expect(service.getEntropyPercentage()).toBeGreaterThan(0);
- expect(service.getEntropyPercentage()).toBeLessThan(101);
- });
- it('collect some entropy using private key data', function() {
- var privateKeyData = {
- privateKey: PRIVATE_KEY_PEM,
- pinEntropy: PIN_ENTROPY
- };
- var service = secureRandom.newService(
- {noDefaultCollectors: true, privateKeyData: privateKeyData});
- expect(service.getEntropyPercentage()).toBeGreaterThan(0);
- expect(service.getEntropyPercentage()).toBeLessThan(101);
- });
- it('generate bytes with the Forge-compliant bytes generation method',
- function() {
- var service = secureRandom.newService(
- {prngSeed: TEST_SEED, noDefaultCollectors: true});
- var randomGenerator = service.newRandomGenerator();
- expect(codec.base64Encode(
- codec.binaryDecode(randomGenerator.getBytesSync(2))))
- .toEqual('k5U=');
- expect(codec.base64Encode(
- codec.binaryDecode(randomGenerator.getBytesSync(4))))
- .toEqual('FQJ+/Q==');
- expect(codec.base64Encode(
- codec.binaryDecode(randomGenerator.getBytesSync(6))))
- .toEqual('o9f6kc4U');
- });
- });
- });
|