package java.security; import java.util.Random; import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.prng.RandomGenerator; import org.bouncycastle.crypto.prng.DigestRandomGenerator; /** * An implementation of SecureRandom specifically for the light-weight API, JDK * 1.0, and the J2ME. Random generation is based on the traditional SHA1 with * counter. Calling setSeed will always increase the entropy of the hash. * <p> * <b>Do not use this class without calling setSeed at least once</b>! There * are some example seed generators in the org.bouncycastle.prng package. */ public class SecureRandom extends java.util.Random { // Note: all objects of this class should be deriving their random data from // a single generator appropriate to the digest being used. private static final RandomGenerator sha1Generator = new DigestRandomGenerator(new SHA1Digest()); private static final RandomGenerator sha256Generator = new DigestRandomGenerator(new SHA256Digest()); protected RandomGenerator generator; // public constructors public SecureRandom() { this(sha1Generator); setSeed(System.currentTimeMillis()); } public SecureRandom(byte[] inSeed) { this(sha1Generator); setSeed(inSeed); } protected SecureRandom( RandomGenerator generator) { super(0); this.generator = generator; } // protected constructors // protected SecureRandom(SecureRandomSpi srs, Provider provider); // public class methods public static SecureRandom getInstance(String algorithm) { if (algorithm.equals("SHA1PRNG")) { return new SecureRandom(sha1Generator); } if (algorithm.equals("SHA256PRNG")) { return new SecureRandom(sha256Generator); } return new SecureRandom(); // follow old behaviour } public static SecureRandom getInstance(String algorithm, String provider) { return getInstance(algorithm); } public static byte[] getSeed(int numBytes) { byte[] rv = new byte[numBytes]; sha1Generator.addSeedMaterial(System.currentTimeMillis()); sha1Generator.nextBytes(rv); return rv; } // public instance methods public byte[] generateSeed(int numBytes) { byte[] rv = new byte[numBytes]; nextBytes(rv); return rv; } // public final Provider getProvider(); public void setSeed(byte[] inSeed) { generator.addSeedMaterial(inSeed); } // public methods overriding random public void nextBytes(byte[] bytes) { generator.nextBytes(bytes); } public void setSeed(long rSeed) { if (rSeed != 0) // to avoid problems with Random calling setSeed in construction { generator.addSeedMaterial(rSeed); } } public int nextInt() { byte[] intBytes = new byte[4]; nextBytes(intBytes); int result = 0; for (int i = 0; i < 4; i++) { result = (result << 8) + (intBytes[i] & 0xff); } return result; } protected final int next(int numBits) { int size = (numBits + 7) / 8; byte[] bytes = new byte[size]; nextBytes(bytes); int result = 0; for (int i = 0; i < size; i++) { result = (result << 8) + (bytes[i] & 0xff); } return result & ((1 << numBits) - 1); } }