OpenJDK / amber / amber
changeset 20188:564bad4af0a8
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>
author | psandoz |
---|---|
date | Fri, 20 Sep 2013 11:07:06 -0700 |
parents | e360435c2d8e |
children | 1e618f2a82d9 |
files | jdk/src/share/classes/java/util/SplittableRandom.java jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java jdk/test/java/util/concurrent/ThreadLocalRandom/ThreadLocalRandomTest.java |
diffstat | 3 files changed, 77 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- 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