package com.samhg.authentication.key;

import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.util.concurrent.TimeUnit;

public final class ReseedingSecureRandom {

	/**
	 * A {@link SecureRandom} for PRNG.
	 */
	private SecureRandom random;
	
	/**
	 * The amount of times {@link #random} has been used.
	 */
	private int callCount;
	
	/**
	 * The time at which {@link #random} was previously updated.
	 */
	private long lastUpdate;
	
	/**
	 * Maximum amount of calls before {@link #random} should be re-seeded.
	 */
	private static final int MAXIMUM_CALLS = 1_000_000;
	
	/**
	 * Maximum amount of time before re-seeding is required.
	 */
	private static final long MAXIMUM_TIME_DELTA = TimeUnit.MINUTES.toMillis(10);

	/**
	 * Algorithm name and provider used by {@link #random} for PRNG.
	 */
	private static final String ALGORITHM = "SHA1PRNG", PROVIDER = "SUN";
	
	/**
	 * Checks if random needs to be re-instantiated {@link #random} in order to
	 * re-seed and does so if needs be.
	 * 
	 * This method should be called before any use of {@link #random} to assure that
	 * it is re-seeded periodically.
	 */
	private void updateRandom() {
		if (random == null || callCount++ >= MAXIMUM_CALLS || System.nanoTime() - lastUpdate >= MAXIMUM_TIME_DELTA) {
			try {
				random = SecureRandom.getInstance(ALGORITHM, PROVIDER);
				lastUpdate = System.nanoTime();
			} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
				// Shouldn't ever really happen.
				throw new RuntimeException("Failed getting SecureRandom instance.", e);
			}
		}
	}
	
	/**
	 * Gets the next bytes from {@link #random} and stores them in an array.
	 * 
	 * @param size the size of the array.
	 * @return an array of random bytes.
	 */
	public byte[] getNextBytes(int size) {
		updateRandom();
		byte[] bytes = new byte[size];
		random.nextBytes(bytes);
		return bytes;
	}
	
	/**
	 * Gets {@link #random} and calls {@link #updateRandom}
	 * 
	 * @return
	 */
	public SecureRandom getSecureRandom() {
		updateRandom();
		
		return random;
	}
	
}
@@ -59,70 +59,23 @@
 ity.
-NoSuchAlgorithmException;%0D%0Aimport java.security.NoSuchProvider
+GeneralSecurity
 Exce
@@ -264,16 +264,22 @@
 private 
+final 
 SecureRa
@@ -285,24 +285,40 @@
 andom random
+ = getInstance()
 ;%0D%0A%09%0D%0A%09/**%0D%0A
@@ -992,100 +992,171 @@
 dom 
-needs to be re-instantiated %7B@link #random%7D in order to%0D%0A%09 * re-seed and does so if needs be
+requires reseeding. This is the case when there have been either %7B@link #MAXIMUM_CALLS%7D or%0D%0A%09 * %7B@link #MAXIMUM_TIME_DELTA%7D has elapsed between calls to the random
 .%0D%0A%09
@@ -1326,26 +1326,8 @@
 if (
-random == null %7C%7C 
 call
@@ -1418,78 +1418,44 @@
 %0A%09%09%09
-try %7B%0D%0A%09%09%09%09random = SecureRandom.getInstance(ALGORITHM, PROVIDER
+return;%0D%0A%09%09%7D%0D%0A%0D%0A%09%09random.reseed(
 );%0D%0A
-%09%09
 %09%09la
@@ -1490,118 +1490,382 @@
 ;%0D%0A%09
-%09%09%7D catch (NoSuchAlgorithmException %7C NoSuchProviderException e) %7B%0D%0A%09%09%09%09// Shouldn't ever really happen.
+%7D%0D%0A%0D%0A%09/**%0D%0A%09 * Gets an instance of %7B@link SecureRandom%7D using %7B@link #ALGORITHM%7D and %7B@link #PROVIDER%7D as the%0D%0A%09 * algorithm and provider parameters respectively.%0D%0A%09 *%0D%0A%09 * @return a %7B@link SecureRandom%7D instance.%0D%0A%09 */%0D%0A%09private SecureRandom getInstance() %7B%0D%0A%09%09try %7B%0D%0A%09%09%09return SecureRandom.getInstance(ALGORITHM, PROVIDER);%0D%0A%0D%0A%09%09%7D catch (GeneralSecurityException e) %7B
 %0D%0A%09%09%09
-%09
 thro
@@ -1899,15 +1899,14 @@
 led 
+to 
 get
-ting
  Sec
@@ -1929,19 +1929,10 @@
 ce.%22
-, e);%0D%0A%09%09%09%7D
+);
 %0D%0A%09%09
@@ -1934,25 +1934,24 @@
 ;%0D%0A%09%09%7D%0D%0A%09%7D%0D%0A
-%09
 %0D%0A%09/**%0D%0A%09 * 
@@ -2172,16 +2172,18 @@
 dom();%0D%0A
+%0D%0A
 %09%09byte%5B%5D
@@ -2236,16 +2236,18 @@
 ytes);%0D%0A
+%0D%0A
 %09%09return

Refactor ReseedingSecureRandom class so that the SecureRandom field is not reinstantiated it is, instead, reseeded.