changeset 6960:0f93bd5cc8d7

6425477: Better support for generation of high entropy random numbers Reviewed-by: xuelei, weijun, mullan
author wetmore
date Thu, 11 Apr 2013 21:03:24 -0700
parents ea7976ed9bc6
children 5435f112e5ea
files src/share/classes/java/security/SecureRandom.java src/share/classes/sun/security/pkcs11/P11SecureRandom.java src/share/classes/sun/security/provider/SecureRandom.java src/share/classes/sun/security/provider/SeedGenerator.java src/share/classes/sun/security/provider/SunEntries.java src/share/lib/security/java.security-linux src/share/lib/security/java.security-macosx src/share/lib/security/java.security-solaris src/share/lib/security/java.security-windows src/solaris/classes/sun/security/provider/NativePRNG.java src/solaris/classes/sun/security/provider/NativeSeedGenerator.java src/windows/classes/sun/security/mscapi/PRNG.java src/windows/classes/sun/security/provider/NativePRNG.java src/windows/classes/sun/security/provider/NativeSeedGenerator.java test/sun/security/provider/SecureRandom/StrongSecureRandom.java test/sun/security/provider/SecureRandom/StrongSeedReader.java
diffstat 16 files changed, 1115 insertions(+), 307 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/security/SecureRandom.java	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/share/classes/java/security/SecureRandom.java	Thu Apr 11 21:03:24 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package java.security;
 
 import java.util.*;
+import java.util.regex.*;
 
 import java.security.Provider.Service;
 
@@ -79,7 +80,7 @@
  *
  * Note: Depending on the implementation, the <code>generateSeed</code> and
  * <code>nextBytes</code> methods may block as entropy is being gathered,
- * for example, if they need to read from /dev/random on various unix-like
+ * for example, if they need to read from /dev/random on various Unix-like
  * operating systems.
  *
  * @see java.security.SecureRandomSpi
@@ -428,6 +429,7 @@
      *
      * @see #getSeed
      */
+    @Override
     public void setSeed(long seed) {
         /*
          * Ignore call from super constructor (as well as any other calls
@@ -450,7 +452,7 @@
      *
      * @param bytes the array to be filled in with random bytes.
      */
-
+    @Override
     synchronized public void nextBytes(byte[] bytes) {
         secureRandomSpi.engineNextBytes(bytes);
     }
@@ -469,14 +471,16 @@
      * @return an <code>int</code> containing the user-specified number
      * of pseudo-random bits (right justified, with leading zeros).
      */
+    @Override
     final protected int next(int numBits) {
         int numBytes = (numBits+7)/8;
         byte b[] = new byte[numBytes];
         int next = 0;
 
         nextBytes(b);
-        for (int i = 0; i < numBytes; i++)
+        for (int i = 0; i < numBytes; i++) {
             next = (next << 8) + (b[i] & 0xFF);
+        }
 
         return next >>> (numBytes*8 - numBits);
     }
@@ -499,8 +503,9 @@
      * @see #setSeed
      */
     public static byte[] getSeed(int numBytes) {
-        if (seedGenerator == null)
+        if (seedGenerator == null) {
             seedGenerator = new SecureRandom();
+        }
         return seedGenerator.generateSeed(numBytes);
     }
 
@@ -549,6 +554,104 @@
         return null;
     }
 
+    /*
+     * Lazily initialize since Pattern.compile() is heavy.
+     * Effective Java (2nd Edition), Item 71.
+     */
+    private static final class StrongPatternHolder {
+        /*
+         * Entries are alg:prov separated by ,
+         * Allow for prepended/appended whitespace between entries.
+         *
+         * Capture groups:
+         *     1 - alg
+         *     2 - :prov (optional)
+         *     3 - prov (optional)
+         *     4 - ,nextEntry (optional)
+         *     5 - nextEntry (optional)
+         */
+        private static Pattern pattern =
+            Pattern.compile(
+                "\\s*([\\S&&[^:,]]*)(\\:([\\S&&[^,]]*))?\\s*(\\,(.*))?");
+    }
+
+    /**
+     * Returns a {@code SecureRandom} object that was selected by using
+     * the algorithms/providers specified in the {@code
+     * securerandom.strongAlgorithms} Security property.
+     * <p>
+     * Some situations require strong random values, such as when
+     * creating high-value/long-lived secrets like RSA public/private
+     * keys.  To help guide applications in selecting a suitable strong
+     * {@code SecureRandom} implementation, Java distributions should
+     * include a list of known strong {@code SecureRandom}
+     * implementations in the {@code securerandom.strongAlgorithms}
+     * Security property.
+     *
+     * <pre>
+     *     SecureRandom sr = SecureRandom.getStrongSecureRandom();
+     *
+     *     if (sr == null) {
+     *         // Decide if this is a problem, and whether to recover.
+     *         sr = new SecureRandom();
+     *         if (!goodEnough(sr)) {
+     *             return;
+     *         }
+     *     }
+     *
+     *     keyPairGenerator.initialize(2048, sr);
+     * </pre>
+     *
+     * @return a strong {@code SecureRandom} implementation as indicated
+     * by the {@code securerandom.strongAlgorithms} Security property, or
+     * null if none are available.
+     *
+     * @see Security#getProperty(String)
+     *
+     * @since 1.8
+     */
+    public static SecureRandom getStrongSecureRandom() {
+
+        String property = AccessController.doPrivileged(
+            new PrivilegedAction<String>() {
+                @Override
+                public String run() {
+                    return Security.getProperty(
+                        "securerandom.strongAlgorithms");
+                }
+            });
+
+        if ((property == null) || (property.length() == 0)) {
+            return null;
+        }
+
+        String remainder = property;
+        while (remainder != null) {
+            Matcher m;
+            if ((m = StrongPatternHolder.pattern.matcher(
+                    remainder)).matches()) {
+
+                String alg = m.group(1);
+                String prov = m.group(3);
+
+                try {
+                    if (prov == null) {
+                        return SecureRandom.getInstance(alg);
+                    } else {
+                        return SecureRandom.getInstance(alg, prov);
+                    }
+                } catch (NoSuchAlgorithmException |
+                        NoSuchProviderException e) {
+                }
+                remainder = m.group(5);
+            } else {
+                remainder = null;
+            }
+        }
+
+        return null;
+    }
+
     // Declare serialVersionUID to be compatible with JDK1.1
     static final long serialVersionUID = 4940670005562187L;
 
--- a/src/share/classes/sun/security/pkcs11/P11SecureRandom.java	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/share/classes/sun/security/pkcs11/P11SecureRandom.java	Thu Apr 11 21:03:24 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,12 +25,9 @@
 
 package sun.security.pkcs11;
 
-import java.util.*;
 import java.io.*;
 import java.security.*;
-
 import sun.security.pkcs11.wrapper.*;
-import sun.security.pkcs11.wrapper.PKCS11Constants.*;
 
 /**
  * SecureRandom implementation class. Some tokens support only
@@ -88,6 +85,7 @@
     }
 
     // see JCA spec
+    @Override
     protected synchronized void engineSetSeed(byte[] seed) {
         if (seed == null) {
             throw new NullPointerException("seed must not be null");
@@ -119,6 +117,7 @@
     }
 
     // see JCA spec
+    @Override
     protected void engineNextBytes(byte[] bytes) {
         if ((bytes == null) || (bytes.length == 0)) {
             return;
@@ -149,6 +148,7 @@
     }
 
     // see JCA spec
+    @Override
     protected byte[] engineGenerateSeed(int numBytes) {
         byte[] b = new byte[numBytes];
         engineNextBytes(b);
--- a/src/share/classes/sun/security/provider/SecureRandom.java	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/share/classes/sun/security/provider/SecureRandom.java	Thu Apr 11 21:03:24 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -79,7 +79,7 @@
     }
 
     /**
-     * This constructor is used to instatiate the private seeder object
+     * This constructor is used to instantiate the private seeder object
      * with a given seed from the SeedGenerator.
      *
      * @param seed the seed.
@@ -94,7 +94,7 @@
      */
     private void init(byte[] seed) {
         try {
-            digest = MessageDigest.getInstance ("SHA");
+            digest = MessageDigest.getInstance("SHA");
         } catch (NoSuchAlgorithmException e) {
             throw new InternalError("internal error: SHA-1 not available.", e);
         }
@@ -120,7 +120,10 @@
      *
      * @return the seed bytes.
      */
+    @Override
     public byte[] engineGenerateSeed(int numBytes) {
+        // Neither of the SeedGenerator implementations require
+        // locking, so no sync needed here.
         byte[] b = new byte[numBytes];
         SeedGenerator.generateSeed(b);
         return b;
@@ -133,19 +136,21 @@
      *
      * @param seed the seed.
      */
+    @Override
     synchronized public void engineSetSeed(byte[] seed) {
         if (state != null) {
             digest.update(state);
-            for (int i = 0; i < state.length; i++)
+            for (int i = 0; i < state.length; i++) {
                 state[i] = 0;
+            }
         }
         state = digest.digest(seed);
     }
 
     private static void updateState(byte[] state, byte[] output) {
         int last = 1;
-        int v = 0;
-        byte t = 0;
+        int v;
+        byte t;
         boolean zf = false;
 
         // state(n + 1) = (state(n) + output(n) + 1) % 2^160;
@@ -162,8 +167,9 @@
         }
 
         // Make sure at least one bit changes!
-        if (!zf)
+        if (!zf) {
            state[0]++;
+        }
     }
 
     /**
@@ -193,6 +199,7 @@
      *
      * @param bytes the array to be filled in with random bytes.
      */
+    @Override
     public synchronized void engineNextBytes(byte[] result) {
         int index = 0;
         int todo;
@@ -258,7 +265,7 @@
         s.defaultReadObject ();
 
         try {
-            digest = MessageDigest.getInstance ("SHA");
+            digest = MessageDigest.getInstance("SHA");
         } catch (NoSuchAlgorithmException e) {
             throw new InternalError("internal error: SHA-1 not available.", e);
         }
--- a/src/share/classes/sun/security/provider/SeedGenerator.java	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/share/classes/sun/security/provider/SeedGenerator.java	Thu Apr 11 21:03:24 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,11 +26,13 @@
 package sun.security.provider;
 
 /**
- * <P> This class generates seeds for the cryptographically strong random
- * number generator.
- * <P> The seed is produced using one of two techniques, via a computation
+ * This class generates seeds for the SHA1PRNG cryptographically strong
+ * random number generator.
+ * <p>
+ * The seed is produced using one of two techniques, via a computation
  * of current system activity or from an entropy gathering device.
- * <p> In the default technique the seed is  produced by counting the
+ * <p>
+ * In the default technique the seed is produced by counting the
  * number of times the VM manages to loop in a given period. This number
  * roughly reflects the machine load at that point in time.
  * The samples are translated using a permutation (s-box)
@@ -41,23 +43,24 @@
  * We also create a number of sleeper threads which add entropy
  * to the system by keeping the scheduler busy.
  * Twenty such samples should give us roughly 160 bits of randomness.
- * <P> These values are gathered in the background by a daemon thread
+ * <p>
+ * These values are gathered in the background by a daemon thread
  * thus allowing the system to continue performing it's different
  * activites, which in turn add entropy to the random seed.
- * <p> The class also gathers miscellaneous system information, some
+ * <p>
+ * The class also gathers miscellaneous system information, some
  * machine dependent, some not. This information is then hashed together
  * with the 20 seed bytes.
- * <P> The alternative to the above approach is to acquire seed material
+ * <p>
+ * The alternative to the above approach is to acquire seed material
  * from an entropy gathering device, such as /dev/random. This can be
- * accomplished by setting the value of the "securerandom.source"
- * security property (in the Java security properties file) to a URL
- * specifying the location of the entropy gathering device.
+ * accomplished by setting the value of the {@code securerandom.source}
+ * Security property to a URL specifying the location of the entropy
+ * gathering device, or by setting the {@code java.security.egd} System
+ * property.
+ * <p>
  * In the event the specified URL cannot be accessed the default
- * mechanism is used.
- * The Java security properties file is located in the file named
- * &lt;JAVA_HOME&gt;/lib/security/java.security.
- * &lt;JAVA_HOME&gt; refers to the value of the java.home system property,
- * and specifies the directory where the JRE is installed.
+ * threading mechanism is used.
  *
  * @author Joshua Bloch
  * @author Gadi Guy
@@ -81,27 +84,28 @@
 
     private static final Debug debug = Debug.getInstance("provider");
 
-    final static String URL_DEV_RANDOM = SunEntries.URL_DEV_RANDOM;
-    final static String URL_DEV_URANDOM = SunEntries.URL_DEV_URANDOM;
-
     // Static initializer to hook in selected or best performing generator
     static {
         String egdSource = SunEntries.getSeedSource();
 
-        // Try the URL specifying the source
-        // e.g. file:/dev/random
-        //
-        // The URL file:/dev/random or file:/dev/urandom is used to indicate
-        // the SeedGenerator using OS support, if available.
-        // On Windows, the causes MS CryptoAPI to be used.
-        // On Solaris and Linux, this is the identical to using
-        // URLSeedGenerator to read from /dev/random
-
-        if (egdSource.equals(URL_DEV_RANDOM) || egdSource.equals(URL_DEV_URANDOM)) {
+        /*
+         * Try the URL specifying the source (e.g. file:/dev/random)
+         *
+         * The URLs "file:/dev/random" or "file:/dev/urandom" are used to
+         * indicate the SeedGenerator should use OS support, if available.
+         *
+         * On Windows, this causes the MS CryptoAPI seeder to be used.
+         *
+         * On Solaris/Linux/MacOS, this is identical to using
+         * URLSeedGenerator to read from /dev/[u]random
+         */
+        if (egdSource.equals(SunEntries.URL_DEV_RANDOM) ||
+                egdSource.equals(SunEntries.URL_DEV_URANDOM)) {
             try {
-                instance = new NativeSeedGenerator();
+                instance = new NativeSeedGenerator(egdSource);
                 if (debug != null) {
-                    debug.println("Using operating system seed generator");
+                    debug.println(
+                        "Using operating system seed generator" + egdSource);
                 }
             } catch (IOException e) {
                 if (debug != null) {
@@ -117,9 +121,10 @@
                                   + egdSource);
                 }
             } catch (IOException e) {
-                if (debug != null)
+                if (debug != null) {
                     debug.println("Failed to create seed generator with "
                                   + egdSource + ": " + e.toString());
+                }
             }
         }
 
@@ -161,8 +166,8 @@
 
         java.security.AccessController.doPrivileged
             (new java.security.PrivilegedAction<Void>() {
+                @Override
                 public Void run() {
-
                     try {
                         // System properties can change from machine to machine
                         String s;
@@ -180,7 +185,9 @@
                         // The temporary dir
                         File f = new File(p.getProperty("java.io.tmpdir"));
                         int count = 0;
-                        try (DirectoryStream<Path> stream = Files.newDirectoryStream(f.toPath())) {
+                        try (
+                            DirectoryStream<Path> stream =
+                                Files.newDirectoryStream(f.toPath())) {
                             // We use a Random object to choose what file names
                             // should be used. Otherwise on a machine with too
                             // many files, the same first 1024 files always get
@@ -189,7 +196,8 @@
                             Random r = new Random();
                             for (Path entry: stream) {
                                 if (count < 512 || r.nextBoolean()) {
-                                    md.update(entry.getFileName().toString().getBytes());
+                                    md.update(entry.getFileName()
+                                        .toString().getBytes());
                                 }
                                 if (count++ > 1024) {
                                     break;
@@ -236,7 +244,8 @@
     */
 
 
-    private static class ThreadedSeedGenerator extends SeedGenerator implements Runnable {
+    private static class ThreadedSeedGenerator extends SeedGenerator
+            implements Runnable {
         // Queue is used to collect seed bytes
         private byte[] pool;
         private int start, end, count;
@@ -245,11 +254,10 @@
         ThreadGroup seedGroup;
 
         /**
-     * The constructor is only called once to construct the one
-     * instance we actually use. It instantiates the message digest
-     * and starts the thread going.
-     */
-
+         * The constructor is only called once to construct the one
+         * instance we actually use. It instantiates the message digest
+         * and starts the thread going.
+         */
         ThreadedSeedGenerator() {
             pool = new byte[20];
             start = end = 0;
@@ -266,16 +274,18 @@
             final ThreadGroup[] finalsg = new ThreadGroup[1];
             Thread t = java.security.AccessController.doPrivileged
                 (new java.security.PrivilegedAction<Thread>() {
+                        @Override
                         public Thread run() {
                             ThreadGroup parent, group =
                                 Thread.currentThread().getThreadGroup();
-                            while ((parent = group.getParent()) != null)
+                            while ((parent = group.getParent()) != null) {
                                 group = parent;
+                            }
                             finalsg[0] = new ThreadGroup
                                 (group, "SeedGenerator ThreadGroup");
                             Thread newT = new Thread(finalsg[0],
-                                                     ThreadedSeedGenerator.this,
-                                                     "SeedGenerator Thread");
+                                ThreadedSeedGenerator.this,
+                                "SeedGenerator Thread");
                             newT.setPriority(Thread.MIN_PRIORITY);
                             newT.setDaemon(true);
                             return newT;
@@ -289,21 +299,23 @@
          * This method does the actual work. It collects random bytes and
          * pushes them into the queue.
          */
+        @Override
         final public void run() {
             try {
                 while (true) {
                     // Queue full? Wait till there's room.
                     synchronized(this) {
-                        while (count >= pool.length)
+                        while (count >= pool.length) {
                             wait();
+                        }
                     }
 
                     int counter, quanta;
                     byte v = 0;
 
                     // Spin count must not be under 64000
-                    for (counter = quanta = 0; (counter < 64000) && (quanta < 6);
-                         quanta++) {
+                    for (counter = quanta = 0;
+                            (counter < 64000) && (quanta < 6); quanta++) {
 
                         // Start some noisy threads
                         try {
@@ -313,14 +325,12 @@
                             t.start();
                         } catch (Exception e) {
                             throw new InternalError("internal error: " +
-                                                    "SeedGenerator thread creation error."
-                                    , e);
+                                "SeedGenerator thread creation error.", e);
                         }
 
                         // We wait 250milli quanta, so the minimum wait time
                         // cannot be under 250milli.
                         int latch = 0;
-                        latch = 0;
                         long l = System.currentTimeMillis() + 250;
                         while (System.currentTimeMillis() < l) {
                             synchronized(this){};
@@ -339,16 +349,16 @@
                         pool[end] = v;
                         end++;
                         count++;
-                        if (end >= pool.length)
+                        if (end >= pool.length) {
                             end = 0;
+                        }
 
                         notifyAll();
                     }
                 }
             } catch (Exception e) {
                 throw new InternalError("internal error: " +
-                                        "SeedGenerator thread generated an exception."
-                        , e);
+                    "SeedGenerator thread generated an exception.", e);
             }
         }
 
@@ -360,19 +370,20 @@
         }
 
         byte getSeedByte() {
-            byte b = 0;
+            byte b;
 
             try {
                 // Wait for it...
                 synchronized(this) {
-                    while (count <= 0)
+                    while (count <= 0) {
                         wait();
+                    }
                 }
             } catch (Exception e) {
-                if (count <= 0)
+                if (count <= 0) {
                     throw new InternalError("internal error: " +
-                                            "SeedGenerator thread generated an exception."
-                            ,e);
+                        "SeedGenerator thread generated an exception.", e);
+                }
             }
 
             synchronized(this) {
@@ -381,8 +392,9 @@
                 pool[start] = 0;
                 start++;
                 count--;
-                if (start == pool.length)
+                if (start == pool.length) {
                     start = 0;
+                }
 
                 // Notify the daemon thread, just in case it is
                 // waiting for us to make room in the queue.
@@ -430,12 +442,13 @@
          * thus adding entropy to the system load.
          * At least one instance of this class is generated for every seed byte.
          */
-
         private static class BogusThread implements Runnable {
+            @Override
             final public void run() {
                 try {
-                    for(int i = 0; i < 5; i++)
+                    for (int i = 0; i < 5; i++) {
                         Thread.sleep(50);
+                    }
                     // System.gc();
                 } catch (Exception e) {
                 }
@@ -446,7 +459,7 @@
     static class URLSeedGenerator extends SeedGenerator {
 
         private String deviceName;
-        private InputStream devRandom;
+        private InputStream seedStream;
 
         /**
          * The constructor is only called once to construct the one
@@ -462,15 +475,12 @@
             init();
         }
 
-        URLSeedGenerator() throws IOException {
-            this(SeedGenerator.URL_DEV_RANDOM);
-        }
-
         private void init() throws IOException {
             final URL device = new URL(deviceName);
             try {
-                devRandom = java.security.AccessController.doPrivileged
+                seedStream = java.security.AccessController.doPrivileged
                     (new java.security.PrivilegedExceptionAction<InputStream>() {
+                        @Override
                         public InputStream run() throws IOException {
                             /*
                              * return a FileInputStream for file URLs and
@@ -481,7 +491,8 @@
                              * can be slow to replenish.
                              */
                             if (device.getProtocol().equalsIgnoreCase("file")) {
-                                File deviceFile = getDeviceFile(device);
+                                File deviceFile =
+                                    SunEntries.getDeviceFile(device);
                                 return new FileInputStream(deviceFile);
                             } else {
                                 return device.openStream();
@@ -489,36 +500,8 @@
                         }
                     });
             } catch (Exception e) {
-                throw new IOException("Failed to open " + deviceName, e.getCause());
-            }
-        }
-
-        /*
-         * Use a URI to access this File. Previous code used a URL
-         * which is less strict on syntax. If we encounter a
-         * URISyntaxException we make best efforts for backwards
-         * compatibility. e.g. space character in deviceName string.
-         *
-         * Method called within PrivilegedExceptionAction block.
-         */
-        private File getDeviceFile(URL device) throws IOException {
-            try {
-                URI deviceURI = device.toURI();
-                if(deviceURI.isOpaque()) {
-                    // File constructor does not accept opaque URI
-                    URI localDir = new File(System.getProperty("user.dir")).toURI();
-                    String uriPath = localDir.toString() +
-                                         deviceURI.toString().substring(5);
-                    return new File(URI.create(uriPath));
-                } else {
-                    return new File(deviceURI);
-                }
-            } catch (URISyntaxException use) {
-                /*
-                 * Make best effort to access this File.
-                 * We can try using the URL path.
-                 */
-                return new File(device.getPath());
+                throw new IOException(
+                    "Failed to open " + deviceName, e.getCause());
             }
         }
 
@@ -528,19 +511,19 @@
             int read = 0;
             try {
                 while (read < len) {
-                    int count = devRandom.read(result, read, len - read);
+                    int count = seedStream.read(result, read, len - read);
                     // /dev/random blocks - should never have EOF
-                    if (count < 0)
-                        throw new InternalError("URLSeedGenerator " + deviceName +
-                                        " reached end of file");
+                    if (count < 0) {
+                        throw new InternalError(
+                            "URLSeedGenerator " + deviceName +
+                            " reached end of file");
+                    }
                     read += count;
                 }
             } catch (IOException ioe) {
                 throw new InternalError("URLSeedGenerator " + deviceName +
-                                        " generated exception: " +
-                                        ioe.getMessage(), ioe);
+                    " generated exception: " + ioe.getMessage(), ioe);
             }
         }
-
     }
 }
--- a/src/share/classes/sun/security/provider/SunEntries.java	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/share/classes/sun/security/provider/SunEntries.java	Thu Apr 11 21:03:24 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 
 package sun.security.provider;
 
+import java.io.*;
+import java.net.*;
 import java.util.Map;
 import java.security.*;
 
@@ -92,26 +94,41 @@
         // if user selected /dev/urandom, we put it before SHA1PRNG,
         // otherwise after it
         boolean nativeAvailable = NativePRNG.isAvailable();
-        boolean useUrandom = seedSource.equals(URL_DEV_URANDOM);
-        if (nativeAvailable && useUrandom) {
+        boolean useNativePRNG = seedSource.equals(URL_DEV_URANDOM) ||
+            seedSource.equals(URL_DEV_RANDOM);
+
+        if (nativeAvailable && useNativePRNG) {
             map.put("SecureRandom.NativePRNG",
                 "sun.security.provider.NativePRNG");
         }
         map.put("SecureRandom.SHA1PRNG",
              "sun.security.provider.SecureRandom");
-        if (nativeAvailable && !useUrandom) {
+        if (nativeAvailable && !useNativePRNG) {
             map.put("SecureRandom.NativePRNG",
                 "sun.security.provider.NativePRNG");
         }
 
+        if (NativePRNG.Blocking.isAvailable()) {
+            map.put("SecureRandom.NativePRNGBlocking",
+                "sun.security.provider.NativePRNG$Blocking");
+        }
+
+        if (NativePRNG.NonBlocking.isAvailable()) {
+            map.put("SecureRandom.NativePRNGNonBlocking",
+                "sun.security.provider.NativePRNG$NonBlocking");
+        }
+
         /*
          * Signature engines
          */
-        map.put("Signature.SHA1withDSA", "sun.security.provider.DSA$SHA1withDSA");
+        map.put("Signature.SHA1withDSA",
+                "sun.security.provider.DSA$SHA1withDSA");
         map.put("Signature.NONEwithDSA", "sun.security.provider.DSA$RawDSA");
         map.put("Alg.Alias.Signature.RawDSA", "NONEwithDSA");
-        map.put("Signature.SHA224withDSA", "sun.security.provider.DSA$SHA224withDSA");
-        map.put("Signature.SHA256withDSA", "sun.security.provider.DSA$SHA256withDSA");
+        map.put("Signature.SHA224withDSA",
+                "sun.security.provider.DSA$SHA224withDSA");
+        map.put("Signature.SHA256withDSA",
+                "sun.security.provider.DSA$SHA256withDSA");
 
         String dsaKeyClasses = "java.security.interfaces.DSAPublicKey" +
                 "|java.security.interfaces.DSAPrivateKey";
@@ -128,13 +145,15 @@
         map.put("Alg.Alias.Signature.SHAwithDSA", "SHA1withDSA");
         map.put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
         map.put("Alg.Alias.Signature.OID.1.2.840.10040.4.3",
-            "SHA1withDSA");
+                "SHA1withDSA");
         map.put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA");
         map.put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA1withDSA");
         map.put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA1withDSA");
-        map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.1", "SHA224withDSA");
+        map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.1",
+                "SHA224withDSA");
         map.put("Alg.Alias.Signature.2.16.840.1.101.3.4.3.1", "SHA224withDSA");
-        map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.2", "SHA256withDSA");
+        map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.2",
+                "SHA256withDSA");
         map.put("Alg.Alias.Signature.2.16.840.1.101.3.4.3.2", "SHA256withDSA");
 
         /*
@@ -160,17 +179,21 @@
 
         map.put("MessageDigest.SHA-224", "sun.security.provider.SHA2$SHA224");
         map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.4", "SHA-224");
-        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.4", "SHA-224");
+        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.4",
+                "SHA-224");
 
         map.put("MessageDigest.SHA-256", "sun.security.provider.SHA2$SHA256");
         map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256");
-        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.1", "SHA-256");
+        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.1",
+                "SHA-256");
         map.put("MessageDigest.SHA-384", "sun.security.provider.SHA5$SHA384");
         map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384");
-        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.2", "SHA-384");
+        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.2",
+                "SHA-384");
         map.put("MessageDigest.SHA-512", "sun.security.provider.SHA5$SHA512");
         map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
-        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3", "SHA-512");
+        map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3",
+                "SHA-512");
 
         /*
          * Algorithm Parameter Generator engines
@@ -296,6 +319,7 @@
         seedSource = AccessController.doPrivileged(
                 new PrivilegedAction<String>() {
 
+            @Override
             public String run() {
                 String egdSource = System.getProperty(PROP_EGD, "");
                 if (egdSource.length() != 0) {
@@ -314,4 +338,36 @@
         return seedSource;
     }
 
+    /*
+     * Use a URI to access this File. Previous code used a URL
+     * which is less strict on syntax. If we encounter a
+     * URISyntaxException we make best efforts for backwards
+     * compatibility. e.g. space character in deviceName string.
+     *
+     * Method called within PrivilegedExceptionAction block.
+     *
+     * Moved from SeedGenerator to avoid initialization problems with
+     * signed providers.
+     */
+    static File getDeviceFile(URL device) throws IOException {
+        try {
+            URI deviceURI = device.toURI();
+            if(deviceURI.isOpaque()) {
+                // File constructor does not accept opaque URI
+                URI localDir = new File(
+                    System.getProperty("user.dir")).toURI();
+                String uriPath = localDir.toString() +
+                                     deviceURI.toString().substring(5);
+                return new File(URI.create(uriPath));
+            } else {
+                return new File(deviceURI);
+            }
+        } catch (URISyntaxException use) {
+            /*
+             * Make best effort to access this File.
+             * We can try using the URL path.
+             */
+            return new File(device.getPath());
+        }
+    }
 }
--- a/src/share/lib/security/java.security-linux	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/share/lib/security/java.security-linux	Thu Apr 11 21:03:24 2013 -0700
@@ -76,26 +76,57 @@
 security.provider.9=sun.security.smartcardio.SunPCSC
 
 #
-# Select the source of seed data for SecureRandom. By default an
-# attempt is made to use the entropy gathering device specified by
-# the securerandom.source property. If an exception occurs when
-# accessing the URL then the traditional system/thread activity
-# algorithm is used.
+# Sun Provider SecureRandom seed source.
 #
-# On Solaris and Linux systems, if file:/dev/urandom is specified and it
-# exists, a special SecureRandom implementation is activated by default.
-# This "NativePRNG" reads random bytes directly from /dev/urandom.
+# Select the primary source of seed data for the "SHA1PRNG" and
+# "NativePRNG" SecureRandom implementations in the "Sun" provider.
+# (Other SecureRandom implementations might also use this property.)
 #
-# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
-# enables use of the Microsoft CryptoAPI seed functionality.
+# On Unix-like systems (for example, Solaris/Linux/MacOS), the
+# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
+# special device files such as file:/dev/random.
 #
-securerandom.source=file:/dev/urandom
+# On Windows systems, specifying the URLs "file:/dev/random" or
+# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
+# mechanism for SHA1PRNG.
 #
-# The entropy gathering device is described as a URL and can also
-# be specified with the system property "java.security.egd". For example,
-#   -Djava.security.egd=file:/dev/urandom
-# Specifying this system property will override the securerandom.source
-# setting.
+# By default, an attempt is made to use the entropy gathering device
+# specified by the "securerandom.source" Security property.  If an
+# exception occurs while accessing the specified URL:
+#
+#     SHA1PRNG:
+#         the traditional system/thread activity algorithm will be used.
+#
+#     NativePRNG:
+#         a default value of /dev/random will be used.  If neither
+#         are available, the implementation will be disabled.
+#         "file" is the only currently supported protocol type.
+#
+# The entropy gathering device can also be specified with the System
+# property "java.security.egd". For example:
+#
+#   % java -Djava.security.egd=file:/dev/random MainClass
+#
+# Specifying this System property will override the
+# "securerandom.source" Security property.
+#
+# In addition, if "file:/dev/random" or "file:/dev/urandom" is
+# specified, the "NativePRNG" implementation will be more preferred than
+# SHA1PRNG in the Sun provider.
+#
+securerandom.source=file:/dev/random
+
+#
+# A list of known strong SecureRandom implementations.
+#
+# To help guide applications in selecting a suitable strong
+# java.security.SecureRandom implementation, Java distributions should
+# indicate a list of known strong implementations using the property.
+#
+# This is a comma-separated list of algorithm and/or algorithm:provider
+# entries.
+#
+securerandom.strongAlgorithms=NativePRNGBlocking:SUN
 
 #
 # Class to instantiate as the javax.security.auth.login.Configuration
@@ -159,9 +190,9 @@
                com.sun.org.glassfish.gmbal.,\
                com.oracle.xmlns.internal.,\
                com.oracle.webservices.internal.,\
-	       jdk.internal.,\
-	       jdk.nashorn.internal.,\
-	       jdk.nashorn.tools.
+               jdk.internal.,\
+               jdk.nashorn.internal.,\
+               jdk.nashorn.tools.
 
 #
 # List of comma-separated packages that start with or equal this string
@@ -187,9 +218,9 @@
                    com.sun.org.glassfish.gmbal.,\
                    com.oracle.xmlns.internal.,\
                    com.oracle.webservices.internal.,\
-		   jdk.internal.,\
-		   jdk.nashorn.internal.,\
-		   jdk.nashorn.tools.
+                   jdk.internal.,\
+                   jdk.nashorn.internal.,\
+                   jdk.nashorn.tools.
 
 #
 # Determines whether this properties file can be appended to
--- a/src/share/lib/security/java.security-macosx	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/share/lib/security/java.security-macosx	Thu Apr 11 21:03:24 2013 -0700
@@ -77,26 +77,57 @@
 security.provider.10=apple.security.AppleProvider
 
 #
-# Select the source of seed data for SecureRandom. By default an
-# attempt is made to use the entropy gathering device specified by
-# the securerandom.source property. If an exception occurs when
-# accessing the URL then the traditional system/thread activity
-# algorithm is used.
+# Sun Provider SecureRandom seed source.
 #
-# On Solaris and Linux systems, if file:/dev/urandom is specified and it
-# exists, a special SecureRandom implementation is activated by default.
-# This "NativePRNG" reads random bytes directly from /dev/urandom.
+# Select the primary source of seed data for the "SHA1PRNG" and
+# "NativePRNG" SecureRandom implementations in the "Sun" provider.
+# (Other SecureRandom implementations might also use this property.)
 #
-# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
-# enables use of the Microsoft CryptoAPI seed functionality.
+# On Unix-like systems (for example, Solaris/Linux/MacOS), the
+# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
+# special device files such as file:/dev/random.
 #
-securerandom.source=file:/dev/urandom
+# On Windows systems, specifying the URLs "file:/dev/random" or
+# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
+# mechanism for SHA1PRNG.
 #
-# The entropy gathering device is described as a URL and can also
-# be specified with the system property "java.security.egd". For example,
-#   -Djava.security.egd=file:/dev/urandom
-# Specifying this system property will override the securerandom.source
-# setting.
+# By default, an attempt is made to use the entropy gathering device
+# specified by the "securerandom.source" Security property.  If an
+# exception occurs while accessing the specified URL:
+#
+#     SHA1PRNG:
+#         the traditional system/thread activity algorithm will be used.
+#
+#     NativePRNG:
+#         a default value of /dev/random will be used.  If neither
+#         are available, the implementation will be disabled.
+#         "file" is the only currently supported protocol type.
+#
+# The entropy gathering device can also be specified with the System
+# property "java.security.egd". For example:
+#
+#   % java -Djava.security.egd=file:/dev/random MainClass
+#
+# Specifying this System property will override the
+# "securerandom.source" Security property.
+#
+# In addition, if "file:/dev/random" or "file:/dev/urandom" is
+# specified, the "NativePRNG" implementation will be more preferred than
+# SHA1PRNG in the Sun provider.
+#
+securerandom.source=file:/dev/random
+
+#
+# A list of known strong SecureRandom implementations.
+#
+# To help guide applications in selecting a suitable strong
+# java.security.SecureRandom implementation, Java distributions should
+# indicate a list of known strong implementations using the property.
+#
+# This is a comma-separated list of algorithm and/or algorithm:provider
+# entries.
+#
+securerandom.strongAlgorithms=NativePRNGBlocking:SUN
 
 #
 # Class to instantiate as the javax.security.auth.login.Configuration
@@ -160,9 +191,9 @@
                com.sun.org.glassfish.gmbal.,\
                com.oracle.xmlns.internal.,\
                com.oracle.webservices.internal.,\
-	       jdk.internal.,\
-	       jdk.nashorn.internal.,\
-	       jdk.nashorn.tools.,\
+               jdk.internal.,\
+               jdk.nashorn.internal.,\
+               jdk.nashorn.tools.,\
                apple.
 
 #
@@ -189,9 +220,9 @@
                    com.sun.org.glassfish.gmbal.,\
                    com.oracle.xmlns.internal.,\
                    com.oracle.webservices.internal.,\
-		   jdk.internal.,\
-		   jdk.nashorn.internal.,\
-		   jdk.nashorn.tools.,\
+                   jdk.internal.,\
+                   jdk.nashorn.internal.,\
+                   jdk.nashorn.tools.,\
                    apple.
 
 #
--- a/src/share/lib/security/java.security-solaris	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/share/lib/security/java.security-solaris	Thu Apr 11 21:03:24 2013 -0700
@@ -78,26 +78,57 @@
 security.provider.11=sun.security.smartcardio.SunPCSC
 
 #
-# Select the source of seed data for SecureRandom. By default an
-# attempt is made to use the entropy gathering device specified by
-# the securerandom.source property. If an exception occurs when
-# accessing the URL then the traditional system/thread activity
-# algorithm is used.
+# Sun Provider SecureRandom seed source.
 #
-# On Solaris and Linux systems, if file:/dev/urandom is specified and it
-# exists, a special SecureRandom implementation is activated by default.
-# This "NativePRNG" reads random bytes directly from /dev/urandom.
+# Select the primary source of seed data for the "SHA1PRNG" and
+# "NativePRNG" SecureRandom implementations in the "Sun" provider.
+# (Other SecureRandom implementations might also use this property.)
 #
-# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
-# enables use of the Microsoft CryptoAPI seed functionality.
+# On Unix-like systems (for example, Solaris/Linux/MacOS), the
+# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
+# special device files such as file:/dev/random.
 #
-securerandom.source=file:/dev/urandom
+# On Windows systems, specifying the URLs "file:/dev/random" or
+# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
+# mechanism for SHA1PRNG.
 #
-# The entropy gathering device is described as a URL and can also
-# be specified with the system property "java.security.egd". For example,
-#   -Djava.security.egd=file:/dev/urandom
-# Specifying this system property will override the securerandom.source
-# setting.
+# By default, an attempt is made to use the entropy gathering device
+# specified by the "securerandom.source" Security property.  If an
+# exception occurs while accessing the specified URL:
+#
+#     SHA1PRNG:
+#         the traditional system/thread activity algorithm will be used.
+#
+#     NativePRNG:
+#         a default value of /dev/random will be used.  If neither
+#         are available, the implementation will be disabled.
+#         "file" is the only currently supported protocol type.
+#
+# The entropy gathering device can also be specified with the System
+# property "java.security.egd". For example:
+#
+#   % java -Djava.security.egd=file:/dev/random MainClass
+#
+# Specifying this System property will override the
+# "securerandom.source" Security property.
+#
+# In addition, if "file:/dev/random" or "file:/dev/urandom" is
+# specified, the "NativePRNG" implementation will be more preferred than
+# SHA1PRNG in the Sun provider.
+#
+securerandom.source=file:/dev/random
+
+#
+# A list of known strong SecureRandom implementations.
+#
+# To help guide applications in selecting a suitable strong
+# java.security.SecureRandom implementation, Java distributions should
+# indicate a list of known strong implementations using the property.
+#
+# This is a comma-separated list of algorithm and/or algorithm:provider
+# entries.
+#
+securerandom.strongAlgorithms=NativePRNGBlocking:SUN
 
 #
 # Class to instantiate as the javax.security.auth.login.Configuration
@@ -161,9 +192,9 @@
                com.sun.org.glassfish.gmbal.,\
                com.oracle.xmlns.internal.,\
                com.oracle.webservices.internal.,\
-	       jdk.internal.,\
-	       jdk.nashorn.internal.,\
-	       jdk.nashorn.tools.
+               jdk.internal.,\
+               jdk.nashorn.internal.,\
+               jdk.nashorn.tools.
 
 #
 # List of comma-separated packages that start with or equal this string
@@ -189,9 +220,9 @@
                    com.sun.org.glassfish.gmbal.,\
                    com.oracle.xmlns.internal.,\
                    com.oracle.webservices.internal.,\
-		   jdk.internal.,\
-		   jdk.nashorn.internal.,\
-		   jdk.nashorn.tools.
+                   jdk.internal.,\
+                   jdk.nashorn.internal.,\
+                   jdk.nashorn.tools.
 
 #
 # Determines whether this properties file can be appended to
@@ -429,4 +460,4 @@
 #
 # Example:
 #   jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048
-i
+
--- a/src/share/lib/security/java.security-windows	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/share/lib/security/java.security-windows	Thu Apr 11 21:03:24 2013 -0700
@@ -77,26 +77,57 @@
 security.provider.10=sun.security.mscapi.SunMSCAPI
 
 #
-# Select the source of seed data for SecureRandom. By default an
-# attempt is made to use the entropy gathering device specified by
-# the securerandom.source property. If an exception occurs when
-# accessing the URL then the traditional system/thread activity
-# algorithm is used.
+# Sun Provider SecureRandom seed source.
 #
-# On Solaris and Linux systems, if file:/dev/urandom is specified and it
-# exists, a special SecureRandom implementation is activated by default.
-# This "NativePRNG" reads random bytes directly from /dev/urandom.
+# Select the primary source of seed data for the "SHA1PRNG" and
+# "NativePRNG" SecureRandom implementations in the "Sun" provider.
+# (Other SecureRandom implementations might also use this property.)
 #
-# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
-# enables use of the Microsoft CryptoAPI seed functionality.
+# On Unix-like systems (for example, Solaris/Linux/MacOS), the
+# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
+# special device files such as file:/dev/random.
 #
-securerandom.source=file:/dev/urandom
+# On Windows systems, specifying the URLs "file:/dev/random" or
+# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
+# mechanism for SHA1PRNG.
 #
-# The entropy gathering device is described as a URL and can also
-# be specified with the system property "java.security.egd". For example,
-#   -Djava.security.egd=file:/dev/urandom
-# Specifying this system property will override the securerandom.source
-# setting.
+# By default, an attempt is made to use the entropy gathering device
+# specified by the "securerandom.source" Security property.  If an
+# exception occurs while accessing the specified URL:
+#
+#     SHA1PRNG:
+#         the traditional system/thread activity algorithm will be used.
+#
+#     NativePRNG:
+#         a default value of /dev/random will be used.  If neither
+#         are available, the implementation will be disabled.
+#         "file" is the only currently supported protocol type.
+#
+# The entropy gathering device can also be specified with the System
+# property "java.security.egd". For example:
+#
+#   % java -Djava.security.egd=file:/dev/random MainClass
+#
+# Specifying this System property will override the
+# "securerandom.source" Security property.
+#
+# In addition, if "file:/dev/random" or "file:/dev/urandom" is
+# specified, the "NativePRNG" implementation will be more preferred than
+# SHA1PRNG in the Sun provider.
+#
+securerandom.source=file:/dev/random
+
+#
+# A list of known strong SecureRandom implementations.
+#
+# To help guide applications in selecting a suitable strong
+# java.security.SecureRandom implementation, Java distributions should
+# indicate a list of known strong implementations using the property.
+#
+# This is a comma-separated list of algorithm and/or algorithm:provider
+# entries.
+#
+securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI
 
 #
 # Class to instantiate as the javax.security.auth.login.Configuration
@@ -160,9 +191,9 @@
                com.sun.org.glassfish.gmbal.,\
                com.oracle.xmlns.internal.,\
                com.oracle.webservices.internal.,\
-	       jdk.internal.,\
-	       jdk.nashorn.internal.,\
-	       jdk.nashorn.tools.
+               jdk.internal.,\
+               jdk.nashorn.internal.,\
+               jdk.nashorn.tools.
 
 #
 # List of comma-separated packages that start with or equal this string
@@ -188,9 +219,9 @@
                    com.sun.org.glassfish.gmbal.,\
                    com.oracle.xmlns.internal.,\
                    com.oracle.webservices.internal.,\
-		   jdk.internal.,\
-		   jdk.nashorn.internal.,\
-		   jdk.nashorn.tools.
+                   jdk.internal.,\
+                   jdk.nashorn.internal.,\
+                   jdk.nashorn.tools.
 
 #
 # Determines whether this properties file can be appended to
--- a/src/solaris/classes/sun/security/provider/NativePRNG.java	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/solaris/classes/sun/security/provider/NativePRNG.java	Thu Apr 11 21:03:24 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,34 +26,47 @@
 package sun.security.provider;
 
 import java.io.*;
-
+import java.net.*;
 import java.security.*;
-import java.security.SecureRandom;
+import sun.security.util.Debug;
 
 /**
- * Native PRNG implementation for Solaris/Linux. It interacts with
- * /dev/random and /dev/urandom, so it is only available if those
- * files are present. Otherwise, SHA1PRNG is used instead of this class.
- *
- * getSeed() and setSeed() directly read/write /dev/random. However,
- * /dev/random is only writable by root in many configurations. Because
- * we cannot just ignore bytes specified via setSeed(), we keep a
- * SHA1PRNG around in parallel.
- *
- * nextBytes() reads the bytes directly from /dev/urandom (and then
- * mixes them with bytes from the SHA1PRNG for the reasons explained
- * above). Reading bytes from /dev/urandom means that constantly get
- * new entropy the operating system has collected. This is a notable
- * advantage over the SHA1PRNG model, which acquires entropy only
- * initially during startup although the VM may be running for months.
- *
- * Also note that we do not need any initial pure random seed from
- * /dev/random. This is an advantage because on some versions of Linux
- * it can be exhausted very quickly and could thus impact startup time.
- *
+ * Native PRNG implementation for Solaris/Linux/MacOS.
+ * <p>
+ * It obtains seed and random numbers by reading system files such as
+ * the special device files /dev/random and /dev/urandom.  This
+ * implementation respects the {@code securerandom.source} Security
+ * property and {@code java.security.egd} System property for obtaining
+ * seed material.  If the file specified by the properties does not
+ * exist, /dev/random is the default seed source.  /dev/urandom is
+ * the default source of random numbers.
+ * <p>
+ * On some Unix platforms, /dev/random may block until enough entropy is
+ * available, but that may negatively impact the perceived startup
+ * time.  By selecting these sources, this implementation tries to
+ * strike a balance between performance and security.
+ * <p>
+ * generateSeed() and setSeed() attempt to directly read/write to the seed
+ * source. However, this file may only be writable by root in many
+ * configurations. Because we cannot just ignore bytes specified via
+ * setSeed(), we keep a SHA1PRNG around in parallel.
+ * <p>
+ * nextBytes() reads the bytes directly from the source of random
+ * numbers (and then mixes them with bytes from the SHA1PRNG for the
+ * reasons explained above). Reading bytes from the random generator means
+ * that we are generally getting entropy from the operating system. This
+ * is a notable advantage over the SHA1PRNG model, which acquires
+ * entropy only initially during startup although the VM may be running
+ * for months.
+ * <p>
+ * Also note for nextBytes() that we do not need any initial pure random
+ * seed from /dev/random. This is an advantage because on some versions
+ * of Linux entropy can be exhausted very quickly and could thus impact
+ * startup time.
+ * <p>
  * Finally, note that we use a singleton for the actual work (RandomIO)
  * to avoid having to open and close /dev/[u]random constantly. However,
- * there may me many NativePRNG instances created by the JCA framework.
+ * there may be many NativePRNG instances created by the JCA framework.
  *
  * @since   1.5
  * @author  Andreas Sterbenz
@@ -62,32 +75,121 @@
 
     private static final long serialVersionUID = -6599091113397072932L;
 
+    private static final Debug debug = Debug.getInstance("provider");
+
     // name of the pure random file (also used for setSeed())
     private static final String NAME_RANDOM = "/dev/random";
     // name of the pseudo random file
     private static final String NAME_URANDOM = "/dev/urandom";
 
+    // which kind of RandomIO object are we creating?
+    private enum Variant {
+        MIXED, BLOCKING, NONBLOCKING
+    }
+
     // singleton instance or null if not available
-    private static final RandomIO INSTANCE = initIO();
+    private static final RandomIO INSTANCE = initIO(Variant.MIXED);
 
-    private static RandomIO initIO() {
+    /**
+     * Get the System egd source (if defined).  We only allow "file:"
+     * URLs for now. If there is a egd value, parse it.
+     *
+     * @return the URL or null if not available.
+     */
+    private static URL getEgdUrl() {
+        // This will return "" if nothing was set.
+        String egdSource = SunEntries.getSeedSource();
+        URL egdUrl;
+
+        if (egdSource.length() != 0) {
+            if (debug != null) {
+                debug.println("NativePRNG egdUrl: " + egdSource);
+            }
+            try {
+                egdUrl = new URL(egdSource);
+                if (!egdUrl.getProtocol().equalsIgnoreCase("file")) {
+                    return null;
+                }
+            } catch (MalformedURLException e) {
+                return null;
+            }
+        } else {
+            egdUrl = null;
+        }
+
+        return egdUrl;
+    }
+
+    /**
+     * Create a RandomIO object for all I/O of this Variant type.
+     */
+    private static RandomIO initIO(final Variant v) {
         return AccessController.doPrivileged(
             new PrivilegedAction<RandomIO>() {
+                @Override
                 public RandomIO run() {
-                File randomFile = new File(NAME_RANDOM);
-                if (randomFile.exists() == false) {
-                    return null;
+
+                    File seedFile;
+                    File nextFile;
+
+                    switch(v) {
+                    case MIXED:
+                        URL egdUrl;
+                        File egdFile = null;
+
+                        if ((egdUrl = getEgdUrl()) != null) {
+                            try {
+                                egdFile = SunEntries.getDeviceFile(egdUrl);
+                            } catch (IOException e) {
+                                // Swallow, seedFile is still null
+                            }
+                        }
+
+                        // Try egd first.
+                        if ((egdFile != null) && egdFile.canRead()) {
+                            seedFile = egdFile;
+                        } else {
+                            // fall back to /dev/random.
+                            seedFile = new File(NAME_RANDOM);
+                        }
+                        nextFile = new File(NAME_URANDOM);
+                        break;
+
+                    case BLOCKING:
+                        seedFile = new File(NAME_RANDOM);
+                        nextFile = new File(NAME_RANDOM);
+                        break;
+
+                    case NONBLOCKING:
+                        seedFile = new File(NAME_URANDOM);
+                        nextFile = new File(NAME_URANDOM);
+                        break;
+
+                    default:
+                        // Shouldn't happen!
+                        return null;
+                    }
+
+                    if (debug != null) {
+                        debug.println("NativePRNG." + v +
+                            " seedFile: " + seedFile +
+                            " nextFile: " + nextFile);
+                    }
+
+                    if (!seedFile.canRead() || !nextFile.canRead()) {
+                        if (debug != null) {
+                            debug.println("NativePRNG." + v +
+                                " Couldn't read Files.");
+                        }
+                        return null;
+                    }
+
+                    try {
+                        return new RandomIO(seedFile, nextFile);
+                    } catch (Exception e) {
+                        return null;
+                    }
                 }
-                File urandomFile = new File(NAME_URANDOM);
-                if (urandomFile.exists() == false) {
-                    return null;
-                }
-                try {
-                    return new RandomIO(randomFile, urandomFile);
-                } catch (Exception e) {
-                    return null;
-                }
-            }
         });
     }
 
@@ -105,67 +207,173 @@
     }
 
     // set the seed
+    @Override
     protected void engineSetSeed(byte[] seed) {
         INSTANCE.implSetSeed(seed);
     }
 
     // get pseudo random bytes
+    @Override
     protected void engineNextBytes(byte[] bytes) {
         INSTANCE.implNextBytes(bytes);
     }
 
     // get true random bytes
+    @Override
     protected byte[] engineGenerateSeed(int numBytes) {
         return INSTANCE.implGenerateSeed(numBytes);
     }
 
     /**
+     * A NativePRNG-like class that uses /dev/random for both
+     * seed and random material.
+     *
+     * Note that it does not respect the egd properties, since we have
+     * no way of knowing what those qualities are.
+     *
+     * This is very similar to the outer NativePRNG class, minimizing any
+     * breakage to the serialization of the existing implementation.
+     *
+     * @since   1.8
+     */
+    public static final class Blocking extends SecureRandomSpi {
+        private static final long serialVersionUID = -6396183145759983347L;
+
+        private static final RandomIO INSTANCE = initIO(Variant.BLOCKING);
+
+        // return whether this is available
+        static boolean isAvailable() {
+            return INSTANCE != null;
+        }
+
+        // constructor, called by the JCA framework
+        public Blocking() {
+            super();
+            if (INSTANCE == null) {
+                throw new AssertionError("NativePRNG$Blocking not available");
+            }
+        }
+
+        // set the seed
+        @Override
+        protected void engineSetSeed(byte[] seed) {
+            INSTANCE.implSetSeed(seed);
+        }
+
+        // get pseudo random bytes
+        @Override
+        protected void engineNextBytes(byte[] bytes) {
+            INSTANCE.implNextBytes(bytes);
+        }
+
+        // get true random bytes
+        @Override
+        protected byte[] engineGenerateSeed(int numBytes) {
+            return INSTANCE.implGenerateSeed(numBytes);
+        }
+    }
+
+    /**
+     * A NativePRNG-like class that uses /dev/urandom for both
+     * seed and random material.
+     *
+     * Note that it does not respect the egd properties, since we have
+     * no way of knowing what those qualities are.
+     *
+     * This is very similar to the outer NativePRNG class, minimizing any
+     * breakage to the serialization of the existing implementation.
+     *
+     * @since   1.8
+     */
+    public static final class NonBlocking extends SecureRandomSpi {
+        private static final long serialVersionUID = -1102062982994105487L;
+
+        private static final RandomIO INSTANCE = initIO(Variant.NONBLOCKING);
+
+        // return whether this is available
+        static boolean isAvailable() {
+            return INSTANCE != null;
+        }
+
+        // constructor, called by the JCA framework
+        public NonBlocking() {
+            super();
+            if (INSTANCE == null) {
+                throw new AssertionError(
+                    "NativePRNG$NonBlocking not available");
+            }
+        }
+
+        // set the seed
+        @Override
+        protected void engineSetSeed(byte[] seed) {
+            INSTANCE.implSetSeed(seed);
+        }
+
+        // get pseudo random bytes
+        @Override
+        protected void engineNextBytes(byte[] bytes) {
+            INSTANCE.implNextBytes(bytes);
+        }
+
+        // get true random bytes
+        @Override
+        protected byte[] engineGenerateSeed(int numBytes) {
+            return INSTANCE.implGenerateSeed(numBytes);
+        }
+    }
+
+    /**
      * Nested class doing the actual work. Singleton, see INSTANCE above.
      */
     private static class RandomIO {
 
-        // we buffer data we read from /dev/urandom for efficiency,
+        // we buffer data we read from the "next" file for efficiency,
         // but we limit the lifetime to avoid using stale bits
         // lifetime in ms, currently 100 ms (0.1 s)
         private final static long MAX_BUFFER_TIME = 100;
 
-        // size of the /dev/urandom buffer
+        // size of the "next" buffer
         private final static int BUFFER_SIZE = 32;
 
-        // In/OutputStream for /dev/random and /dev/urandom
-        private final InputStream randomIn, urandomIn;
-        private OutputStream randomOut;
+        // Holder for the seedFile.  Used if we ever add seed material.
+        File seedFile;
 
-        // flag indicating if we have tried to open randomOut yet
-        private boolean randomOutInitialized;
+        // In/OutputStream for "seed" and "next"
+        private final InputStream seedIn, nextIn;
+        private OutputStream seedOut;
+
+        // flag indicating if we have tried to open seedOut yet
+        private boolean seedOutInitialized;
 
         // SHA1PRNG instance for mixing
         // initialized lazily on demand to avoid problems during startup
         private volatile sun.security.provider.SecureRandom mixRandom;
 
-        // buffer for /dev/urandom bits
-        private final byte[] urandomBuffer;
+        // buffer for next bits
+        private final byte[] nextBuffer;
 
-        // number of bytes left in urandomBuffer
+        // number of bytes left in nextBuffer
         private int buffered;
 
-        // time we read the data into the urandomBuffer
+        // time we read the data into the nextBuffer
         private long lastRead;
 
         // mutex lock for nextBytes()
         private final Object LOCK_GET_BYTES = new Object();
 
-        // mutex lock for getSeed()
+        // mutex lock for generateSeed()
         private final Object LOCK_GET_SEED = new Object();
 
         // mutex lock for setSeed()
         private final Object LOCK_SET_SEED = new Object();
 
         // constructor, called only once from initIO()
-        private RandomIO(File randomFile, File urandomFile) throws IOException {
-            randomIn = new FileInputStream(randomFile);
-            urandomIn = new FileInputStream(urandomFile);
-            urandomBuffer = new byte[BUFFER_SIZE];
+        private RandomIO(File seedFile, File nextFile) throws IOException {
+            this.seedFile = seedFile;
+            seedIn = new FileInputStream(seedFile);
+            nextIn = new FileInputStream(nextFile);
+            nextBuffer = new byte[BUFFER_SIZE];
         }
 
         // get the SHA1PRNG for mixing
@@ -179,7 +387,7 @@
                         r = new sun.security.provider.SecureRandom();
                         try {
                             byte[] b = new byte[20];
-                            readFully(urandomIn, b);
+                            readFully(nextIn, b);
                             r.engineSetSeed(b);
                         } catch (IOException e) {
                             throw new ProviderException("init failed", e);
@@ -192,7 +400,7 @@
         }
 
         // read data.length bytes from in
-        // /dev/[u]random are not normal files, so we need to loop the read.
+        // These are not normal files, so we need to loop the read.
         // just keep trying as long as we are making progress
         private static void readFully(InputStream in, byte[] data)
                 throws IOException {
@@ -201,22 +409,22 @@
             while (len > 0) {
                 int k = in.read(data, ofs, len);
                 if (k <= 0) {
-                    throw new EOFException("/dev/[u]random closed?");
+                    throw new EOFException("File(s) closed?");
                 }
                 ofs += k;
                 len -= k;
             }
             if (len > 0) {
-                throw new IOException("Could not read from /dev/[u]random");
+                throw new IOException("Could not read from file(s)");
             }
         }
 
-        // get true random bytes, just read from /dev/random
+        // get true random bytes, just read from "seed"
         private byte[] implGenerateSeed(int numBytes) {
             synchronized (LOCK_GET_SEED) {
                 try {
                     byte[] b = new byte[numBytes];
-                    readFully(randomIn, b);
+                    readFully(seedIn, b);
                     return b;
                 } catch (IOException e) {
                     throw new ProviderException("generateSeed() failed", e);
@@ -225,26 +433,27 @@
         }
 
         // supply random bytes to the OS
-        // write to /dev/random if possible
+        // write to "seed" if possible
         // always add the seed to our mixing random
         private void implSetSeed(byte[] seed) {
             synchronized (LOCK_SET_SEED) {
-                if (randomOutInitialized == false) {
-                    randomOutInitialized = true;
-                    randomOut = AccessController.doPrivileged(
+                if (seedOutInitialized == false) {
+                    seedOutInitialized = true;
+                    seedOut = AccessController.doPrivileged(
                             new PrivilegedAction<OutputStream>() {
+                        @Override
                         public OutputStream run() {
                             try {
-                                return new FileOutputStream(NAME_RANDOM, true);
+                                return new FileOutputStream(seedFile, true);
                             } catch (Exception e) {
                                 return null;
                             }
                         }
                     });
                 }
-                if (randomOut != null) {
+                if (seedOut != null) {
                     try {
-                        randomOut.write(seed);
+                        seedOut.write(seed);
                     } catch (IOException e) {
                         throw new ProviderException("setSeed() failed", e);
                     }
@@ -261,12 +470,12 @@
                 return;
             }
             lastRead = time;
-            readFully(urandomIn, urandomBuffer);
-            buffered = urandomBuffer.length;
+            readFully(nextIn, nextBuffer);
+            buffered = nextBuffer.length;
         }
 
         // get pseudo random bytes
-        // read from /dev/urandom and XOR with bytes generated by the
+        // read from "next" and XOR with bytes generated by the
         // mixing SHA1PRNG
         private void implNextBytes(byte[] data) {
             synchronized (LOCK_GET_BYTES) {
@@ -276,9 +485,9 @@
                     int ofs = 0;
                     while (len > 0) {
                         ensureBufferValid();
-                        int bufferOfs = urandomBuffer.length - buffered;
+                        int bufferOfs = nextBuffer.length - buffered;
                         while ((len > 0) && (buffered > 0)) {
-                            data[ofs++] ^= urandomBuffer[bufferOfs++];
+                            data[ofs++] ^= nextBuffer[bufferOfs++];
                             len--;
                             buffered--;
                         }
@@ -288,7 +497,5 @@
                 }
             }
         }
-
     }
-
 }
--- a/src/solaris/classes/sun/security/provider/NativeSeedGenerator.java	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/solaris/classes/sun/security/provider/NativeSeedGenerator.java	Thu Apr 11 21:03:24 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,8 +34,8 @@
  */
 class NativeSeedGenerator extends SeedGenerator.URLSeedGenerator {
 
-    NativeSeedGenerator() throws IOException {
-        super();
+    NativeSeedGenerator(String seedFile) throws IOException {
+        super(seedFile);
     }
 
 }
--- a/src/windows/classes/sun/security/mscapi/PRNG.java	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/windows/classes/sun/security/mscapi/PRNG.java	Thu Apr 11 21:03:24 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,6 +58,7 @@
      *
      * @param seed the seed.
      */
+    @Override
     protected void engineSetSeed(byte[] seed) {
         if (seed != null) {
             generateSeed(-1, seed);
@@ -69,6 +70,7 @@
      *
      * @param bytes the array to be filled in with random bytes.
      */
+    @Override
     protected void engineNextBytes(byte[] bytes) {
         if (bytes != null) {
             if (generateSeed(0, bytes) == null) {
@@ -85,6 +87,7 @@
      *
      * @return the seed bytes.
      */
+    @Override
     protected byte[] engineGenerateSeed(int numBytes) {
         byte[] seed = generateSeed(numBytes, null);
 
--- a/src/windows/classes/sun/security/provider/NativePRNG.java	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/windows/classes/sun/security/provider/NativePRNG.java	Thu Apr 11 21:03:24 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,4 +39,15 @@
         return false;
     }
 
+    public static final class NonBlocking {
+        static boolean isAvailable() {
+            return false;
+        }
+    }
+
+    public static final class Blocking {
+        static boolean isAvailable() {
+            return false;
+        }
+    }
 }
--- a/src/windows/classes/sun/security/provider/NativeSeedGenerator.java	Thu Apr 11 19:36:52 2013 -0700
+++ b/src/windows/classes/sun/security/provider/NativeSeedGenerator.java	Thu Apr 11 21:03:24 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,8 @@
      * @exception IOException if CryptoAPI seeds are not available
      * on this platform.
      */
-    NativeSeedGenerator() throws IOException {
+    NativeSeedGenerator(String seedFile) throws IOException {
+        // seedFile is ignored.
         super();
         // try generating two random bytes to see if CAPI is available
         if (!nativeGenerateSeed(new byte[2])) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/provider/SecureRandom/StrongSecureRandom.java	Thu Apr 11 21:03:24 2013 -0700
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 6425477
+ * @summary Better support for generation of high entropy random numbers
+ * @run main/othervm StrongSecureRandom
+ */
+import java.security.*;
+import java.util.*;
+
+/**
+ * This test assumes that the standard Sun providers are installed.
+ */
+public class StrongSecureRandom {
+
+    private static String os = System.getProperty("os.name", "unknown");
+
+    private static void testDefaultEgd() throws Exception {
+        // No SecurityManager installed.
+        String s = Security.getProperty("securerandom.source");
+
+        System.out.println("Testing:  default EGD: " + s);
+        if (!s.equals("file:/dev/random")) {
+            throw new Exception("Default is not 'file:/dev/random'");
+        }
+    }
+
+    private static void testSHA1PRNGImpl() throws Exception {
+        SecureRandom sr;
+        byte[] ba;
+
+        String urandom = "file:/dev/urandom";
+
+        System.out.println("Testing new SeedGenerator and EGD");
+
+        Security.setProperty("securerandom.source", urandom);
+        if (!Security.getProperty("securerandom.source").equals(urandom)) {
+            throw new Exception("Couldn't set securerandom.source");
+        }
+
+        /*
+         * Take out a large number of bytes in hopes of blocking.
+         * Don't expect this to happen, unless something is broken on Linux
+         */
+        sr = SecureRandom.getInstance("SHA1PRNG");
+        if (!sr.getAlgorithm().equals("SHA1PRNG")) {
+            throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
+        }
+
+        ba = sr.generateSeed(4096);
+        sr.nextBytes(ba);
+        sr.setSeed(ba);
+    }
+
+    private static void testNativePRNGImpls() throws Exception {
+        SecureRandom sr;
+        byte[] ba;
+
+        System.out.println("Testing new NativePRNGImpls");
+
+        if (os.startsWith("Windows")) {
+            System.out.println("Skip windows testing.");
+            return;
+        }
+
+        System.out.println("    Testing regular");
+        sr = SecureRandom.getInstance("NativePRNG");
+        if (!sr.getAlgorithm().equals("NativePRNG")) {
+            throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
+        }
+        ba = sr.generateSeed(1);
+        sr.nextBytes(ba);
+        sr.setSeed(ba);
+
+        System.out.println("    Testing NonBlocking");
+        sr = SecureRandom.getInstance("NativePRNGNonBlocking");
+        if (!sr.getAlgorithm().equals("NativePRNGNonBlocking")) {
+            throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
+        }
+        ba = sr.generateSeed(1);
+        sr.nextBytes(ba);
+        sr.setSeed(ba);
+
+        if (os.equals("Linux")) {
+            System.out.println("Skip Linux blocking test.");
+            return;
+        }
+
+        System.out.println("    Testing Blocking");
+        sr = SecureRandom.getInstance("NativePRNGBlocking");
+        if (!sr.getAlgorithm().equals("NativePRNGBlocking")) {
+            throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
+        }
+        ba = sr.generateSeed(1);
+        sr.nextBytes(ba);
+        sr.setSeed(ba);
+    }
+
+    private static void testStrongInstance(boolean expected) throws Exception {
+
+        boolean result = (SecureRandom.getStrongSecureRandom() != null);
+
+        if (expected != result) {
+            throw new Exception("Received: " + result);
+        }
+    }
+
+    /*
+     * This test assumes that the standard providers are installed.
+     */
+    private static void testProperty(String property, boolean expected)
+            throws Exception {
+
+        System.out.println("Testing: '" + property + "' " + expected);
+
+        Security.setProperty("securerandom.strongAlgorithms", property);
+        testStrongInstance(expected);
+    }
+
+    private static void testProperties() throws Exception {
+        // Sets securerandom.strongAlgorithms, and then tests various combos.
+        testProperty("", false);
+
+        testProperty("SHA1PRNG", true);
+        testProperty(" SHA1PRNG", true);
+        testProperty("SHA1PRNG ", true);
+        testProperty(" SHA1PRNG ", true);
+
+        // Impls are case-insenstive, providers are sensitive.
+        testProperty("SHA1PRNG:SUN", true);
+        testProperty("Sha1PRNG:SUN", true);
+        testProperty("SHA1PRNG:Sun", false);
+
+        testProperty(" SHA1PRNG:SUN", true);
+        testProperty("SHA1PRNG:SUN ", true);
+        testProperty(" SHA1PRNG:SUN ", true);
+
+        testProperty(" SHA1PRNG:SUn", false);
+        testProperty("SHA1PRNG:SUn ", false);
+        testProperty(" SHA1PRNG:SUn ", false);
+
+        testProperty(",,,SHA1PRNG", true);
+        testProperty(",,, SHA1PRNG", true);
+        testProperty(" , , ,SHA1PRNG ", true);
+
+        testProperty(",,,, SHA1PRNG ,,,", true);
+        testProperty(",,,, SHA1PRNG:SUN ,,,", true);
+        testProperty(",,,, SHA1PRNG:SUn ,,,", false);
+
+        testProperty(",,,SHA1PRNG:Sun,, SHA1PRNG:SUN", true);
+        testProperty(",,,Sha1PRNG:Sun, SHA1PRNG:SUN", true);
+        testProperty(" SHA1PRNG:Sun, Sha1PRNG:Sun,,,,Sha1PRNG:SUN", true);
+
+        testProperty(",,,SHA1PRNG:Sun,, SHA1PRNG:SUn", false);
+        testProperty(",,,Sha1PRNG:Sun, SHA1PRNG:SUn", false);
+        testProperty(" SHA1PRNG:Sun, Sha1PRNG:Sun,,,,Sha1PRNG:SUn", false);
+
+        testProperty(
+                " @#%,%$#:!%^, NativePRNG:Sun, Sha1PRNG:Sun,,Sha1PRNG:SUN",
+                true);
+        testProperty(" @#%,%$#!%^, NativePRNG:Sun, Sha1PRNG:Sun,,Sha1PRNG:SUn",
+                false);
+    }
+
+    /*
+     * Linux tends to block, so ignore anything that reads /dev/random.
+     */
+    private static void handleLinuxRead(SecureRandom sr) throws Exception {
+        if (os.equals("Linux")) {
+            if (!sr.getAlgorithm().equalsIgnoreCase("NativePRNGBlocking")) {
+                sr.nextBytes(new byte[34]);
+            }
+        } else {
+            sr.nextBytes(new byte[34]);
+            sr.generateSeed(34);
+            sr.setSeed(new byte[34]);
+        }
+    }
+
+    /*
+     * This is duplicating stuff above, but just iterate over all impls
+     * just in case we missed something.
+     */
+    private static void testAllImpls() throws Exception {
+        System.out.print("Testing:  AllImpls:  ");
+
+        Iterator<String> i = Security.getAlgorithms("SecureRandom").iterator();
+
+        while (i.hasNext()) {
+            String s = i.next();
+            System.out.print("/" + s);
+            SecureRandom sr = SecureRandom.getInstance(s);
+
+            handleLinuxRead(sr);
+            handleLinuxRead(sr);
+        }
+        System.out.println("/");
+    }
+
+    public static void main(String args[]) throws Exception {
+        testDefaultEgd();
+        testSHA1PRNGImpl();
+        testNativePRNGImpls();
+        testAllImpls();
+
+        // test default.
+        testStrongInstance(true);
+        testProperties();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/provider/SecureRandom/StrongSeedReader.java	Thu Apr 11 21:03:24 2013 -0700
@@ -0,0 +1,81 @@
+ /*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 6425477
+ * @summary Better support for generation of high entropy random numbers
+ * @run main/othervm StrongSeedReader
+ */
+
+import java.io.*;
+import java.net.*;
+import java.security.SecureRandom;
+
+/**
+ * A simple test which takes into account knowledge about the underlying
+ * implementation. This may change if the implementations change.
+ *
+ * Create a new EGD file with known bytes, then set the EGD System property. The
+ * data read should be the same as what was written.
+ */
+public class StrongSeedReader {
+
+    public static void main(String[] args) throws Exception {
+        // Skip Windows, the SHA1PRNG uses CryptGenRandom.
+        if (System.getProperty("os.name", "unknown").startsWith("Windows")) {
+            return;
+        }
+
+        File file = null;
+        try {
+            file = new File(System.getProperty("java.io.tmpdir") +
+                    "StrongSeedReader.tmpdata");
+
+            // write a bunch of 0's to the file.
+            FileOutputStream fos = new FileOutputStream(file);
+            fos.write(new byte[2048]);
+
+            System.setProperty("java.security.egd", file.toURI().toString());
+            testSeed("NativePRNG");
+            testSeed("SHA1PRNG");
+        } finally {
+            if (file != null) {
+                file.delete();
+            }
+        }
+    }
+
+    private static void testSeed(String alg) throws Exception {
+        System.out.println("Testing: " + alg);
+        SecureRandom sr = SecureRandom.getInstance(alg);
+        byte[] ba = sr.generateSeed(20);
+
+        // We should get back a bunch of zeros from the file.
+        for (byte b : ba) {
+            if (b != 0) {
+                throw new Exception("Byte != 0");
+            }
+        }
+    }
+}