//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Apache License Version 2.0.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
package com.microsoft.uprove;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
/**
* Implementation for the SDK's source of randomness.
*
* @see com.microsoft.uprove.RandomSource
* @see java.security.SecureRandom
*/
final class RandomSourceImpl {
private static SecureRandom random; // = null;
/**
* Non instantiable class.
*/
private RandomSourceImpl() {
super();
}
/**
* Initializes the SecureRandom.
*/
private static synchronized void init() {
if (random == null) {
// get values from ConfigImpl
final String algo = ConfigImpl.secureRandomAlgorithm();
final String prov = ConfigImpl.secureRandomProvider();
try {
if (prov != null) {
// we specify a provider
random = SecureRandom.getInstance(algo, prov);
} else {
// we use the default provider
random = SecureRandom.getInstance(algo);
}
// Forces the SecureRandom to use Java's seed, that hopefully
// the caller will supplement with a call to seed()
// From the SecureRandom's getInstance() javadoc:
// Note that the returned instance of SecureRandom has not
// been seeded.
// [...] If a call is not made to setSeed, the first call to
// the nextBytes method will force the SecureRandom object
// to seed itself.
random.nextBytes(new byte[1]);
} catch (NoSuchAlgorithmException e) {
IllegalStateException ise =
new IllegalStateException(
"Cannot find SecureRandom algorithm named " + algo);
ise.initCause(e);
throw ise;
} catch (NoSuchProviderException e) {
IllegalStateException ise =
new IllegalStateException(
"Cannot find SecureRandom provider named " + prov);
ise.initCause(e);
throw ise;
}
}
}
/**
* Resets so that the source is reset from the configured algo/provider.
*/
static synchronized void reset() {
random = null;
}
/**
* Returns a random <code>BigInteger</code> of specified size,
* uniformly distributed over
* the range <tt>0</tt> to <tt>(2<sup>numBits</sup> - 1)</tt>, inclusive.
* The uniformity of the distribution is dependent on the quality
* of the underlying RNG.
* @param numBits number of bits of the requested <code>BigInteger</code>.
* @return a random <code>BigInteger</code>.
* @throws IllegalArgumentException if <code>numBits</code> is negative.
*/
public static java.math.BigInteger getRandomBigInteger(final int numBits) {
if (numBits < 0) {
throw new IllegalArgumentException();
}
init();
return new java.math.BigInteger(numBits, random);
}
/**
* Generates a random byte array of given <code>size</code>.
* @param size number of bytes to generate.
* @return random byte array.
* @throws IllegalArgumentException if <code>size</code> is negative.
*/
public static byte[] getRandomBytes(final int size) {
if (size < 0) {
throw new IllegalArgumentException();
}
init();
byte[] bytes = new byte[size];
random.nextBytes(bytes);
return bytes;
}
/**
* Seeds the random source with the provided <code>data</code>. This method
* can be called several times; the given seed supplements, rather than
* replaces, the existing seed.
* @param data random data that will be used to seed the underlying
* <code>SecureRandom</code> object.
*/
public static void seed(final byte[] data) {
if (data == null) {
throw new NullPointerException();
}
init();
random.setSeed(data);
}
}