8024253: ThreadLocal random can use SecureRandom for the initial seed
Reviewed-by: psandoz, chegar, alanb
Contributed-by: Doug Lea <dl@cs.oswego.edu>, Peter Levart <peter.levart@gmail.com>, Guy Steele <guy.steele@oracle.com>
--- a/jdk/src/share/classes/java/util/SplittableRandom.java Fri Sep 20 16:40:32 2013 +0200
+++ b/jdk/src/share/classes/java/util/SplittableRandom.java Fri Sep 20 11:07:06 2013 -0700
@@ -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 @@
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()));
}
--- a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java Fri Sep 20 16:40:32 2013 +0200
+++ b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java Fri Sep 20 11:07:06 2013 -0700
@@ -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 @@
*
* <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 @@
/**
* 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
--- a/jdk/test/java/util/concurrent/ThreadLocalRandom/ThreadLocalRandomTest.java Fri Sep 20 16:40:32 2013 +0200
+++ b/jdk/test/java/util/concurrent/ThreadLocalRandom/ThreadLocalRandomTest.java Fri Sep 20 11:07:06 2013 -0700
@@ -33,7 +33,9 @@
/**
* @test
+ * @bug 8024253
* @run testng ThreadLocalRandomTest
+ * @run testng/othervm -Djava.util.secureRandomSeed=true ThreadLocalRandomTest
* @summary test methods on ThreadLocalRandom
*/
@Test