github#300 further reduction of SecureRandom constructor death spiral...
package org.bouncycastle.jcajce.provider.drbg;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.SecureRandomSpi;
+import java.security.Security;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -121,10 +125,19 @@ private static SecureRandom createCoreSecureRandom()
return new CoreSecureRandom();
}
else
+ {
+ try
+ {
+ String source = Security.getProperty("securerandom.source");
+
+ return new URLSeededSecureRandom(new URL(source));
+ }
+ catch (Exception e)
{
return new SecureRandom(); // we're desperate, it's worth a try.
}
}
+ }
private static EntropySourceProvider createEntropySource()
{
@@ -261,6 +274,83 @@ protected HybridRandomProvider()
}
}
+ private static class URLSeededSecureRandom
+ extends SecureRandom
+ {
+ private final InputStream seedStream;
+
+ URLSeededSecureRandom(final URL url)
+ {
+ super(null, new HybridRandomProvider());
+
+ this.seedStream = AccessController.doPrivileged(new PrivilegedAction<InputStream>()
+ {
+ public InputStream run()
+ {
+ try
+ {
+ return url.openStream();
+ }
+ catch (IOException e)
+ {
+ throw new InternalError("unable to open random source");
+ }
+ }
+ });
+ }
+
+ public void setSeed(byte[] seed)
+ {
+ // ignore
+ }
+
+ public void setSeed(long seed)
+ {
+ // ignore
+ }
+
+ public byte[] generateSeed(int numBytes)
+ {
+ synchronized (this)
+ {
+ byte[] data = new byte[numBytes];
+
+ int off = 0;
+ int len;
+
+ while (off != data.length && (len = privilegedRead(data, off, data.length - off)) > -1)
+ {
+ off += len;
+ }
+
+ if (off != data.length)
+ {
+ throw new InternalError("unable to fully read random source");
+ }
+
+ return data;
+ }
+ }
+
+ private int privilegedRead(final byte[] data, final int off, final int len)
+ {
+ return AccessController.doPrivileged(new PrivilegedAction<Integer>()
+ {
+ public Integer run()
+ {
+ try
+ {
+ return seedStream.read(data, off, len);
+ }
+ catch (IOException e)
+ {
+ throw new InternalError("unable to read random source");
+ }
+ }
+ });
+ }
+ }
+
private static class HybridSecureRandom
extends SecureRandom
{
