6425477: Better support for generation of high entropy random numbers
Reviewed-by: xuelei, weijun, mullan
--- a/jdk/src/share/classes/java/security/SecureRandom.java Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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/jdk/src/share/classes/sun/security/pkcs11/P11SecureRandom.java Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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/jdk/src/share/classes/sun/security/provider/SecureRandom.java Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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/jdk/src/share/classes/sun/security/provider/SeedGenerator.java Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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
- * <JAVA_HOME>/lib/security/java.security.
- * <JAVA_HOME> 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/jdk/src/share/classes/sun/security/provider/SunEntries.java Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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/jdk/src/share/lib/security/java.security-linux Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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.
+#
+# 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 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.
#
-# 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.
+# On Windows systems, specifying the URLs "file:/dev/random" or
+# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
+# mechanism for SHA1PRNG.
+#
+# 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.
#
-# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
-# enables use of the Microsoft CryptoAPI seed functionality.
+# 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
#
-securerandom.source=file:/dev/urandom
+# 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.
#
-# 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.
+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/jdk/src/share/lib/security/java.security-macosx Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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.
+#
+# 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 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.
#
-# 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.
+# On Windows systems, specifying the URLs "file:/dev/random" or
+# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
+# mechanism for SHA1PRNG.
+#
+# 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.
#
-# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
-# enables use of the Microsoft CryptoAPI seed functionality.
+# 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
#
-securerandom.source=file:/dev/urandom
+# 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.
#
-# 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.
+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/jdk/src/share/lib/security/java.security-solaris Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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.
+#
+# 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 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.
#
-# 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.
+# On Windows systems, specifying the URLs "file:/dev/random" or
+# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
+# mechanism for SHA1PRNG.
+#
+# 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.
#
-# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
-# enables use of the Microsoft CryptoAPI seed functionality.
+# 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
#
-securerandom.source=file:/dev/urandom
+# 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.
#
-# 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.
+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/jdk/src/share/lib/security/java.security-windows Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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.
+#
+# 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 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.
#
-# 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.
+# On Windows systems, specifying the URLs "file:/dev/random" or
+# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
+# mechanism for SHA1PRNG.
+#
+# 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.
#
-# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
-# enables use of the Microsoft CryptoAPI seed functionality.
+# 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
#
-securerandom.source=file:/dev/urandom
+# 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.
#
-# 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.
+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/jdk/src/solaris/classes/sun/security/provider/NativePRNG.java Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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() {
- return AccessController.doPrivileged(
- new PrivilegedAction<RandomIO>() {
- public RandomIO run() {
- File randomFile = new File(NAME_RANDOM);
- if (randomFile.exists() == false) {
+ /**
+ * 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;
}
- File urandomFile = new File(NAME_URANDOM);
- if (urandomFile.exists() == false) {
- 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 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;
+ }
}
- 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/jdk/src/solaris/classes/sun/security/provider/NativeSeedGenerator.java Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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/jdk/src/windows/classes/sun/security/mscapi/PRNG.java Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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/jdk/src/windows/classes/sun/security/provider/NativePRNG.java Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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/jdk/src/windows/classes/sun/security/provider/NativeSeedGenerator.java Thu Apr 11 19:36:52 2013 -0700
+++ b/jdk/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/jdk/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/jdk/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");
+ }
+ }
+ }
+}