8024253: ThreadLocal random can use SecureRandom for the initial seed

Co-authored-by: Peter Levart <peter.levart@gmail.com>
Co-authored-by: Guy Steele <guy.steele@oracle.com>
Reviewed-by: psandoz, chegar, alanb
This commit is contained in:
Doug Lea 2013-09-20 11:07:06 -07:00 committed by Paul Sandoz
parent fdef74ade2
commit 851fd0447e
3 changed files with 77 additions and 9 deletions

View File

@ -25,8 +25,7 @@
package java.util;
import java.security.SecureRandom;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.IntConsumer;
import java.util.function.LongConsumer;
@ -242,12 +241,34 @@ public final class SplittableRandom {
s = (s << 8) | ((long)(seedBytes[i]) & 0xffL);
return s;
}
int hh = 0; // hashed host address
long h = 0L;
try {
hh = InetAddress.getLocalHost().hashCode();
Enumeration<NetworkInterface> ifcs =
NetworkInterface.getNetworkInterfaces();
boolean retry = false; // retry once if getHardwareAddress is null
while (ifcs.hasMoreElements()) {
NetworkInterface ifc = ifcs.nextElement();
if (!ifc.isVirtual()) { // skip fake addresses
byte[] bs = ifc.getHardwareAddress();
if (bs != null) {
int n = bs.length;
int m = Math.min(n >>> 1, 4);
for (int i = 0; i < m; ++i)
h = (h << 16) ^ (bs[i] << 8) ^ bs[n-1-i];
if (m < 4)
h = (h << 8) ^ bs[n-1-m];
h = mix64(h);
break;
}
else if (!retry)
retry = true;
else
break;
}
}
} catch (Exception ignore) {
}
return (mix64((((long)hh) << 32) ^ System.currentTimeMillis()) ^
return (h ^ mix64(System.currentTimeMillis()) ^
mix64(System.nanoTime()));
}

View File

@ -36,6 +36,8 @@
package java.util.concurrent;
import java.io.ObjectStreamField;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.Random;
import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicInteger;
@ -71,7 +73,10 @@ import java.util.stream.StreamSupport;
*
* <p>Instances of {@code ThreadLocalRandom} are not cryptographically
* secure. Consider instead using {@link java.security.SecureRandom}
* in security-sensitive applications.
* in security-sensitive applications. Additionally,
* default-constructed instances do not use a cryptographically random
* seed unless the {@linkplain System#getProperty system property}
* {@code java.util.secureRandomSeed} is set to {@code true}.
*
* @since 1.7
* @author Doug Lea
@ -129,9 +134,49 @@ public class ThreadLocalRandom extends Random {
/**
* The next seed for default constructors.
*/
private static final AtomicLong seeder =
new AtomicLong(mix64(System.currentTimeMillis()) ^
mix64(System.nanoTime()));
private static final AtomicLong seeder = new AtomicLong(initialSeed());
private static long initialSeed() {
String pp = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
"java.util.secureRandomSeed"));
if (pp != null && pp.equalsIgnoreCase("true")) {
byte[] seedBytes = java.security.SecureRandom.getSeed(8);
long s = (long)(seedBytes[0]) & 0xffL;
for (int i = 1; i < 8; ++i)
s = (s << 8) | ((long)(seedBytes[i]) & 0xffL);
return s;
}
long h = 0L;
try {
Enumeration<NetworkInterface> ifcs =
NetworkInterface.getNetworkInterfaces();
boolean retry = false; // retry once if getHardwareAddress is null
while (ifcs.hasMoreElements()) {
NetworkInterface ifc = ifcs.nextElement();
if (!ifc.isVirtual()) { // skip fake addresses
byte[] bs = ifc.getHardwareAddress();
if (bs != null) {
int n = bs.length;
int m = Math.min(n >>> 1, 4);
for (int i = 0; i < m; ++i)
h = (h << 16) ^ (bs[i] << 8) ^ bs[n-1-i];
if (m < 4)
h = (h << 8) ^ bs[n-1-m];
h = mix64(h);
break;
}
else if (!retry)
retry = true;
else
break;
}
}
} catch (Exception ignore) {
}
return (h ^ mix64(System.currentTimeMillis()) ^
mix64(System.nanoTime()));
}
/**
* The seed increment

View File

@ -33,7 +33,9 @@ import static org.testng.Assert.*;
/**
* @test
* @bug 8024253
* @run testng ThreadLocalRandomTest
* @run testng/othervm -Djava.util.secureRandomSeed=true ThreadLocalRandomTest
* @summary test methods on ThreadLocalRandom
*/
@Test