提交 ee5be2bd 编写于 作者: W wetmore

6425477: Better support for generation of high entropy random numbers

Reviewed-by: xuelei, weijun, mullan
上级 7647b4bc
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
package java.security; package java.security;
import java.util.*; import java.util.*;
import java.util.regex.*;
import java.security.Provider.Service; import java.security.Provider.Service;
...@@ -79,7 +80,7 @@ import sun.security.jca.GetInstance.Instance; ...@@ -79,7 +80,7 @@ import sun.security.jca.GetInstance.Instance;
* *
* Note: Depending on the implementation, the <code>generateSeed</code> and * Note: Depending on the implementation, the <code>generateSeed</code> and
* <code>nextBytes</code> methods may block as entropy is being gathered, * <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. * operating systems.
* *
* @see java.security.SecureRandomSpi * @see java.security.SecureRandomSpi
...@@ -428,6 +429,7 @@ public class SecureRandom extends java.util.Random { ...@@ -428,6 +429,7 @@ public class SecureRandom extends java.util.Random {
* *
* @see #getSeed * @see #getSeed
*/ */
@Override
public void setSeed(long seed) { public void setSeed(long seed) {
/* /*
* Ignore call from super constructor (as well as any other calls * Ignore call from super constructor (as well as any other calls
...@@ -450,7 +452,7 @@ public class SecureRandom extends java.util.Random { ...@@ -450,7 +452,7 @@ public class SecureRandom extends java.util.Random {
* *
* @param bytes the array to be filled in with random bytes. * @param bytes the array to be filled in with random bytes.
*/ */
@Override
synchronized public void nextBytes(byte[] bytes) { synchronized public void nextBytes(byte[] bytes) {
secureRandomSpi.engineNextBytes(bytes); secureRandomSpi.engineNextBytes(bytes);
} }
...@@ -469,14 +471,16 @@ public class SecureRandom extends java.util.Random { ...@@ -469,14 +471,16 @@ public class SecureRandom extends java.util.Random {
* @return an <code>int</code> containing the user-specified number * @return an <code>int</code> containing the user-specified number
* of pseudo-random bits (right justified, with leading zeros). * of pseudo-random bits (right justified, with leading zeros).
*/ */
@Override
final protected int next(int numBits) { final protected int next(int numBits) {
int numBytes = (numBits+7)/8; int numBytes = (numBits+7)/8;
byte b[] = new byte[numBytes]; byte b[] = new byte[numBytes];
int next = 0; int next = 0;
nextBytes(b); nextBytes(b);
for (int i = 0; i < numBytes; i++) for (int i = 0; i < numBytes; i++) {
next = (next << 8) + (b[i] & 0xFF); next = (next << 8) + (b[i] & 0xFF);
}
return next >>> (numBytes*8 - numBits); return next >>> (numBytes*8 - numBits);
} }
...@@ -499,8 +503,9 @@ public class SecureRandom extends java.util.Random { ...@@ -499,8 +503,9 @@ public class SecureRandom extends java.util.Random {
* @see #setSeed * @see #setSeed
*/ */
public static byte[] getSeed(int numBytes) { public static byte[] getSeed(int numBytes) {
if (seedGenerator == null) if (seedGenerator == null) {
seedGenerator = new SecureRandom(); seedGenerator = new SecureRandom();
}
return seedGenerator.generateSeed(numBytes); return seedGenerator.generateSeed(numBytes);
} }
...@@ -549,6 +554,104 @@ public class SecureRandom extends java.util.Random { ...@@ -549,6 +554,104 @@ public class SecureRandom extends java.util.Random {
return null; 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 // Declare serialVersionUID to be compatible with JDK1.1
static final long serialVersionUID = 4940670005562187L; static final long serialVersionUID = 4940670005562187L;
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,12 +25,9 @@ ...@@ -25,12 +25,9 @@
package sun.security.pkcs11; package sun.security.pkcs11;
import java.util.*;
import java.io.*; import java.io.*;
import java.security.*; import java.security.*;
import sun.security.pkcs11.wrapper.*; import sun.security.pkcs11.wrapper.*;
import sun.security.pkcs11.wrapper.PKCS11Constants.*;
/** /**
* SecureRandom implementation class. Some tokens support only * SecureRandom implementation class. Some tokens support only
...@@ -88,6 +85,7 @@ final class P11SecureRandom extends SecureRandomSpi { ...@@ -88,6 +85,7 @@ final class P11SecureRandom extends SecureRandomSpi {
} }
// see JCA spec // see JCA spec
@Override
protected synchronized void engineSetSeed(byte[] seed) { protected synchronized void engineSetSeed(byte[] seed) {
if (seed == null) { if (seed == null) {
throw new NullPointerException("seed must not be null"); throw new NullPointerException("seed must not be null");
...@@ -119,6 +117,7 @@ final class P11SecureRandom extends SecureRandomSpi { ...@@ -119,6 +117,7 @@ final class P11SecureRandom extends SecureRandomSpi {
} }
// see JCA spec // see JCA spec
@Override
protected void engineNextBytes(byte[] bytes) { protected void engineNextBytes(byte[] bytes) {
if ((bytes == null) || (bytes.length == 0)) { if ((bytes == null) || (bytes.length == 0)) {
return; return;
...@@ -149,6 +148,7 @@ final class P11SecureRandom extends SecureRandomSpi { ...@@ -149,6 +148,7 @@ final class P11SecureRandom extends SecureRandomSpi {
} }
// see JCA spec // see JCA spec
@Override
protected byte[] engineGenerateSeed(int numBytes) { protected byte[] engineGenerateSeed(int numBytes) {
byte[] b = new byte[numBytes]; byte[] b = new byte[numBytes];
engineNextBytes(b); engineNextBytes(b);
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -79,7 +79,7 @@ implements java.io.Serializable { ...@@ -79,7 +79,7 @@ implements java.io.Serializable {
} }
/** /**
* 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. * with a given seed from the SeedGenerator.
* *
* @param seed the seed. * @param seed the seed.
...@@ -94,7 +94,7 @@ implements java.io.Serializable { ...@@ -94,7 +94,7 @@ implements java.io.Serializable {
*/ */
private void init(byte[] seed) { private void init(byte[] seed) {
try { try {
digest = MessageDigest.getInstance ("SHA"); digest = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
throw new InternalError("internal error: SHA-1 not available.", e); throw new InternalError("internal error: SHA-1 not available.", e);
} }
...@@ -120,7 +120,10 @@ implements java.io.Serializable { ...@@ -120,7 +120,10 @@ implements java.io.Serializable {
* *
* @return the seed bytes. * @return the seed bytes.
*/ */
@Override
public byte[] engineGenerateSeed(int numBytes) { public byte[] engineGenerateSeed(int numBytes) {
// Neither of the SeedGenerator implementations require
// locking, so no sync needed here.
byte[] b = new byte[numBytes]; byte[] b = new byte[numBytes];
SeedGenerator.generateSeed(b); SeedGenerator.generateSeed(b);
return b; return b;
...@@ -133,19 +136,21 @@ implements java.io.Serializable { ...@@ -133,19 +136,21 @@ implements java.io.Serializable {
* *
* @param seed the seed. * @param seed the seed.
*/ */
@Override
synchronized public void engineSetSeed(byte[] seed) { synchronized public void engineSetSeed(byte[] seed) {
if (state != null) { if (state != null) {
digest.update(state); digest.update(state);
for (int i = 0; i < state.length; i++) for (int i = 0; i < state.length; i++) {
state[i] = 0; state[i] = 0;
}
} }
state = digest.digest(seed); state = digest.digest(seed);
} }
private static void updateState(byte[] state, byte[] output) { private static void updateState(byte[] state, byte[] output) {
int last = 1; int last = 1;
int v = 0; int v;
byte t = 0; byte t;
boolean zf = false; boolean zf = false;
// state(n + 1) = (state(n) + output(n) + 1) % 2^160; // state(n + 1) = (state(n) + output(n) + 1) % 2^160;
...@@ -162,8 +167,9 @@ implements java.io.Serializable { ...@@ -162,8 +167,9 @@ implements java.io.Serializable {
} }
// Make sure at least one bit changes! // Make sure at least one bit changes!
if (!zf) if (!zf) {
state[0]++; state[0]++;
}
} }
/** /**
...@@ -193,6 +199,7 @@ implements java.io.Serializable { ...@@ -193,6 +199,7 @@ implements java.io.Serializable {
* *
* @param bytes the array to be filled in with random bytes. * @param bytes the array to be filled in with random bytes.
*/ */
@Override
public synchronized void engineNextBytes(byte[] result) { public synchronized void engineNextBytes(byte[] result) {
int index = 0; int index = 0;
int todo; int todo;
...@@ -258,7 +265,7 @@ implements java.io.Serializable { ...@@ -258,7 +265,7 @@ implements java.io.Serializable {
s.defaultReadObject (); s.defaultReadObject ();
try { try {
digest = MessageDigest.getInstance ("SHA"); digest = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
throw new InternalError("internal error: SHA-1 not available.", e); throw new InternalError("internal error: SHA-1 not available.", e);
} }
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -26,11 +26,13 @@ ...@@ -26,11 +26,13 @@
package sun.security.provider; package sun.security.provider;
/** /**
* <P> This class generates seeds for the cryptographically strong random * This class generates seeds for the SHA1PRNG cryptographically strong
* number generator. * random number generator.
* <P> The seed is produced using one of two techniques, via a computation * <p>
* The seed is produced using one of two techniques, via a computation
* of current system activity or from an entropy gathering device. * 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 * number of times the VM manages to loop in a given period. This number
* roughly reflects the machine load at that point in time. * roughly reflects the machine load at that point in time.
* The samples are translated using a permutation (s-box) * The samples are translated using a permutation (s-box)
...@@ -41,23 +43,24 @@ package sun.security.provider; ...@@ -41,23 +43,24 @@ package sun.security.provider;
* We also create a number of sleeper threads which add entropy * We also create a number of sleeper threads which add entropy
* to the system by keeping the scheduler busy. * to the system by keeping the scheduler busy.
* Twenty such samples should give us roughly 160 bits of randomness. * 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 * thus allowing the system to continue performing it's different
* activites, which in turn add entropy to the random seed. * 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 * machine dependent, some not. This information is then hashed together
* with the 20 seed bytes. * 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 * from an entropy gathering device, such as /dev/random. This can be
* accomplished by setting the value of the "securerandom.source" * accomplished by setting the value of the {@code securerandom.source}
* security property (in the Java security properties file) to a URL * Security property to a URL specifying the location of the entropy
* specifying the location of the entropy gathering device. * gathering device, or by setting the {@code java.security.egd} System
* property.
* <p>
* In the event the specified URL cannot be accessed the default * In the event the specified URL cannot be accessed the default
* mechanism is used. * threading 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.
* *
* @author Joshua Bloch * @author Joshua Bloch
* @author Gadi Guy * @author Gadi Guy
...@@ -81,27 +84,28 @@ abstract class SeedGenerator { ...@@ -81,27 +84,28 @@ abstract class SeedGenerator {
private static final Debug debug = Debug.getInstance("provider"); 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 initializer to hook in selected or best performing generator
static { static {
String egdSource = SunEntries.getSeedSource(); String egdSource = SunEntries.getSeedSource();
// Try the URL specifying the source /*
// e.g. file:/dev/random * 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 URLs "file:/dev/random" or "file:/dev/urandom" are used to
// the SeedGenerator using OS support, if available. * indicate the SeedGenerator should use OS support, if available.
// On Windows, the causes MS CryptoAPI to be used. *
// On Solaris and Linux, this is the identical to using * On Windows, this causes the MS CryptoAPI seeder to be used.
// URLSeedGenerator to read from /dev/random *
* On Solaris/Linux/MacOS, this is identical to using
if (egdSource.equals(URL_DEV_RANDOM) || egdSource.equals(URL_DEV_URANDOM)) { * URLSeedGenerator to read from /dev/[u]random
*/
if (egdSource.equals(SunEntries.URL_DEV_RANDOM) ||
egdSource.equals(SunEntries.URL_DEV_URANDOM)) {
try { try {
instance = new NativeSeedGenerator(); instance = new NativeSeedGenerator(egdSource);
if (debug != null) { if (debug != null) {
debug.println("Using operating system seed generator"); debug.println(
"Using operating system seed generator" + egdSource);
} }
} catch (IOException e) { } catch (IOException e) {
if (debug != null) { if (debug != null) {
...@@ -117,9 +121,10 @@ abstract class SeedGenerator { ...@@ -117,9 +121,10 @@ abstract class SeedGenerator {
+ egdSource); + egdSource);
} }
} catch (IOException e) { } catch (IOException e) {
if (debug != null) if (debug != null) {
debug.println("Failed to create seed generator with " debug.println("Failed to create seed generator with "
+ egdSource + ": " + e.toString()); + egdSource + ": " + e.toString());
}
} }
} }
...@@ -161,8 +166,8 @@ abstract class SeedGenerator { ...@@ -161,8 +166,8 @@ abstract class SeedGenerator {
java.security.AccessController.doPrivileged java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction<Void>() { (new java.security.PrivilegedAction<Void>() {
@Override
public Void run() { public Void run() {
try { try {
// System properties can change from machine to machine // System properties can change from machine to machine
String s; String s;
...@@ -180,7 +185,9 @@ abstract class SeedGenerator { ...@@ -180,7 +185,9 @@ abstract class SeedGenerator {
// The temporary dir // The temporary dir
File f = new File(p.getProperty("java.io.tmpdir")); File f = new File(p.getProperty("java.io.tmpdir"));
int count = 0; 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 // We use a Random object to choose what file names
// should be used. Otherwise on a machine with too // should be used. Otherwise on a machine with too
// many files, the same first 1024 files always get // many files, the same first 1024 files always get
...@@ -189,7 +196,8 @@ abstract class SeedGenerator { ...@@ -189,7 +196,8 @@ abstract class SeedGenerator {
Random r = new Random(); Random r = new Random();
for (Path entry: stream) { for (Path entry: stream) {
if (count < 512 || r.nextBoolean()) { if (count < 512 || r.nextBoolean()) {
md.update(entry.getFileName().toString().getBytes()); md.update(entry.getFileName()
.toString().getBytes());
} }
if (count++ > 1024) { if (count++ > 1024) {
break; break;
...@@ -236,7 +244,8 @@ abstract class SeedGenerator { ...@@ -236,7 +244,8 @@ abstract class SeedGenerator {
*/ */
private static class ThreadedSeedGenerator extends SeedGenerator implements Runnable { private static class ThreadedSeedGenerator extends SeedGenerator
implements Runnable {
// Queue is used to collect seed bytes // Queue is used to collect seed bytes
private byte[] pool; private byte[] pool;
private int start, end, count; private int start, end, count;
...@@ -245,11 +254,10 @@ abstract class SeedGenerator { ...@@ -245,11 +254,10 @@ abstract class SeedGenerator {
ThreadGroup seedGroup; ThreadGroup seedGroup;
/** /**
* The constructor is only called once to construct the one * The constructor is only called once to construct the one
* instance we actually use. It instantiates the message digest * instance we actually use. It instantiates the message digest
* and starts the thread going. * and starts the thread going.
*/ */
ThreadedSeedGenerator() { ThreadedSeedGenerator() {
pool = new byte[20]; pool = new byte[20];
start = end = 0; start = end = 0;
...@@ -266,16 +274,18 @@ abstract class SeedGenerator { ...@@ -266,16 +274,18 @@ abstract class SeedGenerator {
final ThreadGroup[] finalsg = new ThreadGroup[1]; final ThreadGroup[] finalsg = new ThreadGroup[1];
Thread t = java.security.AccessController.doPrivileged Thread t = java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction<Thread>() { (new java.security.PrivilegedAction<Thread>() {
@Override
public Thread run() { public Thread run() {
ThreadGroup parent, group = ThreadGroup parent, group =
Thread.currentThread().getThreadGroup(); Thread.currentThread().getThreadGroup();
while ((parent = group.getParent()) != null) while ((parent = group.getParent()) != null) {
group = parent; group = parent;
}
finalsg[0] = new ThreadGroup finalsg[0] = new ThreadGroup
(group, "SeedGenerator ThreadGroup"); (group, "SeedGenerator ThreadGroup");
Thread newT = new Thread(finalsg[0], Thread newT = new Thread(finalsg[0],
ThreadedSeedGenerator.this, ThreadedSeedGenerator.this,
"SeedGenerator Thread"); "SeedGenerator Thread");
newT.setPriority(Thread.MIN_PRIORITY); newT.setPriority(Thread.MIN_PRIORITY);
newT.setDaemon(true); newT.setDaemon(true);
return newT; return newT;
...@@ -289,21 +299,23 @@ abstract class SeedGenerator { ...@@ -289,21 +299,23 @@ abstract class SeedGenerator {
* This method does the actual work. It collects random bytes and * This method does the actual work. It collects random bytes and
* pushes them into the queue. * pushes them into the queue.
*/ */
@Override
final public void run() { final public void run() {
try { try {
while (true) { while (true) {
// Queue full? Wait till there's room. // Queue full? Wait till there's room.
synchronized(this) { synchronized(this) {
while (count >= pool.length) while (count >= pool.length) {
wait(); wait();
}
} }
int counter, quanta; int counter, quanta;
byte v = 0; byte v = 0;
// Spin count must not be under 64000 // Spin count must not be under 64000
for (counter = quanta = 0; (counter < 64000) && (quanta < 6); for (counter = quanta = 0;
quanta++) { (counter < 64000) && (quanta < 6); quanta++) {
// Start some noisy threads // Start some noisy threads
try { try {
...@@ -313,14 +325,12 @@ abstract class SeedGenerator { ...@@ -313,14 +325,12 @@ abstract class SeedGenerator {
t.start(); t.start();
} catch (Exception e) { } catch (Exception e) {
throw new InternalError("internal error: " + throw new InternalError("internal error: " +
"SeedGenerator thread creation error." "SeedGenerator thread creation error.", e);
, e);
} }
// We wait 250milli quanta, so the minimum wait time // We wait 250milli quanta, so the minimum wait time
// cannot be under 250milli. // cannot be under 250milli.
int latch = 0; int latch = 0;
latch = 0;
long l = System.currentTimeMillis() + 250; long l = System.currentTimeMillis() + 250;
while (System.currentTimeMillis() < l) { while (System.currentTimeMillis() < l) {
synchronized(this){}; synchronized(this){};
...@@ -339,16 +349,16 @@ abstract class SeedGenerator { ...@@ -339,16 +349,16 @@ abstract class SeedGenerator {
pool[end] = v; pool[end] = v;
end++; end++;
count++; count++;
if (end >= pool.length) if (end >= pool.length) {
end = 0; end = 0;
}
notifyAll(); notifyAll();
} }
} }
} catch (Exception e) { } catch (Exception e) {
throw new InternalError("internal error: " + throw new InternalError("internal error: " +
"SeedGenerator thread generated an exception." "SeedGenerator thread generated an exception.", e);
, e);
} }
} }
...@@ -360,19 +370,20 @@ abstract class SeedGenerator { ...@@ -360,19 +370,20 @@ abstract class SeedGenerator {
} }
byte getSeedByte() { byte getSeedByte() {
byte b = 0; byte b;
try { try {
// Wait for it... // Wait for it...
synchronized(this) { synchronized(this) {
while (count <= 0) while (count <= 0) {
wait(); wait();
}
} }
} catch (Exception e) { } catch (Exception e) {
if (count <= 0) if (count <= 0) {
throw new InternalError("internal error: " + throw new InternalError("internal error: " +
"SeedGenerator thread generated an exception." "SeedGenerator thread generated an exception.", e);
,e); }
} }
synchronized(this) { synchronized(this) {
...@@ -381,8 +392,9 @@ abstract class SeedGenerator { ...@@ -381,8 +392,9 @@ abstract class SeedGenerator {
pool[start] = 0; pool[start] = 0;
start++; start++;
count--; count--;
if (start == pool.length) if (start == pool.length) {
start = 0; start = 0;
}
// Notify the daemon thread, just in case it is // Notify the daemon thread, just in case it is
// waiting for us to make room in the queue. // waiting for us to make room in the queue.
...@@ -430,12 +442,13 @@ abstract class SeedGenerator { ...@@ -430,12 +442,13 @@ abstract class SeedGenerator {
* thus adding entropy to the system load. * thus adding entropy to the system load.
* At least one instance of this class is generated for every seed byte. * At least one instance of this class is generated for every seed byte.
*/ */
private static class BogusThread implements Runnable { private static class BogusThread implements Runnable {
@Override
final public void run() { final public void run() {
try { try {
for(int i = 0; i < 5; i++) for (int i = 0; i < 5; i++) {
Thread.sleep(50); Thread.sleep(50);
}
// System.gc(); // System.gc();
} catch (Exception e) { } catch (Exception e) {
} }
...@@ -446,7 +459,7 @@ abstract class SeedGenerator { ...@@ -446,7 +459,7 @@ abstract class SeedGenerator {
static class URLSeedGenerator extends SeedGenerator { static class URLSeedGenerator extends SeedGenerator {
private String deviceName; private String deviceName;
private InputStream devRandom; private InputStream seedStream;
/** /**
* The constructor is only called once to construct the one * The constructor is only called once to construct the one
...@@ -462,15 +475,12 @@ abstract class SeedGenerator { ...@@ -462,15 +475,12 @@ abstract class SeedGenerator {
init(); init();
} }
URLSeedGenerator() throws IOException {
this(SeedGenerator.URL_DEV_RANDOM);
}
private void init() throws IOException { private void init() throws IOException {
final URL device = new URL(deviceName); final URL device = new URL(deviceName);
try { try {
devRandom = java.security.AccessController.doPrivileged seedStream = java.security.AccessController.doPrivileged
(new java.security.PrivilegedExceptionAction<InputStream>() { (new java.security.PrivilegedExceptionAction<InputStream>() {
@Override
public InputStream run() throws IOException { public InputStream run() throws IOException {
/* /*
* return a FileInputStream for file URLs and * return a FileInputStream for file URLs and
...@@ -481,7 +491,8 @@ abstract class SeedGenerator { ...@@ -481,7 +491,8 @@ abstract class SeedGenerator {
* can be slow to replenish. * can be slow to replenish.
*/ */
if (device.getProtocol().equalsIgnoreCase("file")) { if (device.getProtocol().equalsIgnoreCase("file")) {
File deviceFile = getDeviceFile(device); File deviceFile =
SunEntries.getDeviceFile(device);
return new FileInputStream(deviceFile); return new FileInputStream(deviceFile);
} else { } else {
return device.openStream(); return device.openStream();
...@@ -489,36 +500,8 @@ abstract class SeedGenerator { ...@@ -489,36 +500,8 @@ abstract class SeedGenerator {
} }
}); });
} catch (Exception e) { } catch (Exception e) {
throw new IOException("Failed to open " + deviceName, e.getCause()); 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());
} }
} }
...@@ -528,19 +511,19 @@ abstract class SeedGenerator { ...@@ -528,19 +511,19 @@ abstract class SeedGenerator {
int read = 0; int read = 0;
try { try {
while (read < len) { 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 // /dev/random blocks - should never have EOF
if (count < 0) if (count < 0) {
throw new InternalError("URLSeedGenerator " + deviceName + throw new InternalError(
" reached end of file"); "URLSeedGenerator " + deviceName +
" reached end of file");
}
read += count; read += count;
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new InternalError("URLSeedGenerator " + deviceName + throw new InternalError("URLSeedGenerator " + deviceName +
" generated exception: " + " generated exception: " + ioe.getMessage(), ioe);
ioe.getMessage(), ioe);
} }
} }
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
package sun.security.provider; package sun.security.provider;
import java.io.*;
import java.net.*;
import java.util.Map; import java.util.Map;
import java.security.*; import java.security.*;
...@@ -92,26 +94,41 @@ final class SunEntries { ...@@ -92,26 +94,41 @@ final class SunEntries {
// if user selected /dev/urandom, we put it before SHA1PRNG, // if user selected /dev/urandom, we put it before SHA1PRNG,
// otherwise after it // otherwise after it
boolean nativeAvailable = NativePRNG.isAvailable(); boolean nativeAvailable = NativePRNG.isAvailable();
boolean useUrandom = seedSource.equals(URL_DEV_URANDOM); boolean useNativePRNG = seedSource.equals(URL_DEV_URANDOM) ||
if (nativeAvailable && useUrandom) { seedSource.equals(URL_DEV_RANDOM);
if (nativeAvailable && useNativePRNG) {
map.put("SecureRandom.NativePRNG", map.put("SecureRandom.NativePRNG",
"sun.security.provider.NativePRNG"); "sun.security.provider.NativePRNG");
} }
map.put("SecureRandom.SHA1PRNG", map.put("SecureRandom.SHA1PRNG",
"sun.security.provider.SecureRandom"); "sun.security.provider.SecureRandom");
if (nativeAvailable && !useUrandom) { if (nativeAvailable && !useNativePRNG) {
map.put("SecureRandom.NativePRNG", map.put("SecureRandom.NativePRNG",
"sun.security.provider.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 * 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("Signature.NONEwithDSA", "sun.security.provider.DSA$RawDSA");
map.put("Alg.Alias.Signature.RawDSA", "NONEwithDSA"); map.put("Alg.Alias.Signature.RawDSA", "NONEwithDSA");
map.put("Signature.SHA224withDSA", "sun.security.provider.DSA$SHA224withDSA"); map.put("Signature.SHA224withDSA",
map.put("Signature.SHA256withDSA", "sun.security.provider.DSA$SHA256withDSA"); "sun.security.provider.DSA$SHA224withDSA");
map.put("Signature.SHA256withDSA",
"sun.security.provider.DSA$SHA256withDSA");
String dsaKeyClasses = "java.security.interfaces.DSAPublicKey" + String dsaKeyClasses = "java.security.interfaces.DSAPublicKey" +
"|java.security.interfaces.DSAPrivateKey"; "|java.security.interfaces.DSAPrivateKey";
...@@ -128,13 +145,15 @@ final class SunEntries { ...@@ -128,13 +145,15 @@ final class SunEntries {
map.put("Alg.Alias.Signature.SHAwithDSA", "SHA1withDSA"); map.put("Alg.Alias.Signature.SHAwithDSA", "SHA1withDSA");
map.put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA"); map.put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
map.put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", 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.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.13", "SHA1withDSA");
map.put("Alg.Alias.Signature.1.3.14.3.2.27", "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.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"); map.put("Alg.Alias.Signature.2.16.840.1.101.3.4.3.2", "SHA256withDSA");
/* /*
...@@ -160,17 +179,21 @@ final class SunEntries { ...@@ -160,17 +179,21 @@ final class SunEntries {
map.put("MessageDigest.SHA-224", "sun.security.provider.SHA2$SHA224"); 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.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("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.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("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.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("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.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 * Algorithm Parameter Generator engines
...@@ -296,6 +319,7 @@ final class SunEntries { ...@@ -296,6 +319,7 @@ final class SunEntries {
seedSource = AccessController.doPrivileged( seedSource = AccessController.doPrivileged(
new PrivilegedAction<String>() { new PrivilegedAction<String>() {
@Override
public String run() { public String run() {
String egdSource = System.getProperty(PROP_EGD, ""); String egdSource = System.getProperty(PROP_EGD, "");
if (egdSource.length() != 0) { if (egdSource.length() != 0) {
...@@ -314,4 +338,36 @@ final class SunEntries { ...@@ -314,4 +338,36 @@ final class SunEntries {
return seedSource; 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());
}
}
} }
...@@ -76,26 +76,57 @@ security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI ...@@ -76,26 +76,57 @@ security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC security.provider.9=sun.security.smartcardio.SunPCSC
# #
# Select the source of seed data for SecureRandom. By default an # Sun Provider SecureRandom seed source.
# attempt is made to use the entropy gathering device specified by #
# the securerandom.source property. If an exception occurs when # Select the primary source of seed data for the "SHA1PRNG" and
# accessing the URL then the traditional system/thread activity # "NativePRNG" SecureRandom implementations in the "Sun" provider.
# algorithm is used. # (Other SecureRandom implementations might also use this property.)
# #
# On Solaris and Linux systems, if file:/dev/urandom is specified and it # On Unix-like systems (for example, Solaris/Linux/MacOS), the
# exists, a special SecureRandom implementation is activated by default. # "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
# This "NativePRNG" reads random bytes directly from /dev/urandom. # special device files such as file:/dev/random.
# #
# On Windows systems, the URLs file:/dev/random and file:/dev/urandom # On Windows systems, specifying the URLs "file:/dev/random" or
# enables use of the Microsoft CryptoAPI seed functionality. # "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
# # mechanism for SHA1PRNG.
securerandom.source=file:/dev/urandom #
# # By default, an attempt is made to use the entropy gathering device
# The entropy gathering device is described as a URL and can also # specified by the "securerandom.source" Security property. If an
# be specified with the system property "java.security.egd". For example, # exception occurs while accessing the specified URL:
# -Djava.security.egd=file:/dev/urandom #
# Specifying this system property will override the securerandom.source # SHA1PRNG:
# setting. # 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 # Class to instantiate as the javax.security.auth.login.Configuration
...@@ -159,9 +190,9 @@ package.access=sun.,\ ...@@ -159,9 +190,9 @@ package.access=sun.,\
com.sun.org.glassfish.gmbal.,\ com.sun.org.glassfish.gmbal.,\
com.oracle.xmlns.internal.,\ com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\ com.oracle.webservices.internal.,\
jdk.internal.,\ jdk.internal.,\
jdk.nashorn.internal.,\ jdk.nashorn.internal.,\
jdk.nashorn.tools. jdk.nashorn.tools.
# #
# List of comma-separated packages that start with or equal this string # List of comma-separated packages that start with or equal this string
...@@ -187,9 +218,9 @@ package.definition=sun.,\ ...@@ -187,9 +218,9 @@ package.definition=sun.,\
com.sun.org.glassfish.gmbal.,\ com.sun.org.glassfish.gmbal.,\
com.oracle.xmlns.internal.,\ com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\ com.oracle.webservices.internal.,\
jdk.internal.,\ jdk.internal.,\
jdk.nashorn.internal.,\ jdk.nashorn.internal.,\
jdk.nashorn.tools. jdk.nashorn.tools.
# #
# Determines whether this properties file can be appended to # Determines whether this properties file can be appended to
......
...@@ -77,26 +77,57 @@ security.provider.9=sun.security.smartcardio.SunPCSC ...@@ -77,26 +77,57 @@ security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=apple.security.AppleProvider security.provider.10=apple.security.AppleProvider
# #
# Select the source of seed data for SecureRandom. By default an # Sun Provider SecureRandom seed source.
# attempt is made to use the entropy gathering device specified by #
# the securerandom.source property. If an exception occurs when # Select the primary source of seed data for the "SHA1PRNG" and
# accessing the URL then the traditional system/thread activity # "NativePRNG" SecureRandom implementations in the "Sun" provider.
# algorithm is used. # (Other SecureRandom implementations might also use this property.)
# #
# On Solaris and Linux systems, if file:/dev/urandom is specified and it # On Unix-like systems (for example, Solaris/Linux/MacOS), the
# exists, a special SecureRandom implementation is activated by default. # "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
# This "NativePRNG" reads random bytes directly from /dev/urandom. # special device files such as file:/dev/random.
# #
# On Windows systems, the URLs file:/dev/random and file:/dev/urandom # On Windows systems, specifying the URLs "file:/dev/random" or
# enables use of the Microsoft CryptoAPI seed functionality. # "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
# # mechanism for SHA1PRNG.
securerandom.source=file:/dev/urandom #
# # By default, an attempt is made to use the entropy gathering device
# The entropy gathering device is described as a URL and can also # specified by the "securerandom.source" Security property. If an
# be specified with the system property "java.security.egd". For example, # exception occurs while accessing the specified URL:
# -Djava.security.egd=file:/dev/urandom #
# Specifying this system property will override the securerandom.source # SHA1PRNG:
# setting. # 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 # Class to instantiate as the javax.security.auth.login.Configuration
...@@ -160,9 +191,9 @@ package.access=sun.,\ ...@@ -160,9 +191,9 @@ package.access=sun.,\
com.sun.org.glassfish.gmbal.,\ com.sun.org.glassfish.gmbal.,\
com.oracle.xmlns.internal.,\ com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\ com.oracle.webservices.internal.,\
jdk.internal.,\ jdk.internal.,\
jdk.nashorn.internal.,\ jdk.nashorn.internal.,\
jdk.nashorn.tools.,\ jdk.nashorn.tools.,\
apple. apple.
# #
...@@ -189,9 +220,9 @@ package.definition=sun.,\ ...@@ -189,9 +220,9 @@ package.definition=sun.,\
com.sun.org.glassfish.gmbal.,\ com.sun.org.glassfish.gmbal.,\
com.oracle.xmlns.internal.,\ com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\ com.oracle.webservices.internal.,\
jdk.internal.,\ jdk.internal.,\
jdk.nashorn.internal.,\ jdk.nashorn.internal.,\
jdk.nashorn.tools.,\ jdk.nashorn.tools.,\
apple. apple.
# #
......
...@@ -78,26 +78,57 @@ security.provider.10=org.jcp.xml.dsig.internal.dom.XMLDSigRI ...@@ -78,26 +78,57 @@ security.provider.10=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.11=sun.security.smartcardio.SunPCSC security.provider.11=sun.security.smartcardio.SunPCSC
# #
# Select the source of seed data for SecureRandom. By default an # Sun Provider SecureRandom seed source.
# attempt is made to use the entropy gathering device specified by #
# the securerandom.source property. If an exception occurs when # Select the primary source of seed data for the "SHA1PRNG" and
# accessing the URL then the traditional system/thread activity # "NativePRNG" SecureRandom implementations in the "Sun" provider.
# algorithm is used. # (Other SecureRandom implementations might also use this property.)
# #
# On Solaris and Linux systems, if file:/dev/urandom is specified and it # On Unix-like systems (for example, Solaris/Linux/MacOS), the
# exists, a special SecureRandom implementation is activated by default. # "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
# This "NativePRNG" reads random bytes directly from /dev/urandom. # special device files such as file:/dev/random.
# #
# On Windows systems, the URLs file:/dev/random and file:/dev/urandom # On Windows systems, specifying the URLs "file:/dev/random" or
# enables use of the Microsoft CryptoAPI seed functionality. # "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
# # mechanism for SHA1PRNG.
securerandom.source=file:/dev/urandom #
# # By default, an attempt is made to use the entropy gathering device
# The entropy gathering device is described as a URL and can also # specified by the "securerandom.source" Security property. If an
# be specified with the system property "java.security.egd". For example, # exception occurs while accessing the specified URL:
# -Djava.security.egd=file:/dev/urandom #
# Specifying this system property will override the securerandom.source # SHA1PRNG:
# setting. # 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 # Class to instantiate as the javax.security.auth.login.Configuration
...@@ -161,9 +192,9 @@ package.access=sun.,\ ...@@ -161,9 +192,9 @@ package.access=sun.,\
com.sun.org.glassfish.gmbal.,\ com.sun.org.glassfish.gmbal.,\
com.oracle.xmlns.internal.,\ com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\ com.oracle.webservices.internal.,\
jdk.internal.,\ jdk.internal.,\
jdk.nashorn.internal.,\ jdk.nashorn.internal.,\
jdk.nashorn.tools. jdk.nashorn.tools.
# #
# List of comma-separated packages that start with or equal this string # List of comma-separated packages that start with or equal this string
...@@ -189,9 +220,9 @@ package.definition=sun.,\ ...@@ -189,9 +220,9 @@ package.definition=sun.,\
com.sun.org.glassfish.gmbal.,\ com.sun.org.glassfish.gmbal.,\
com.oracle.xmlns.internal.,\ com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\ com.oracle.webservices.internal.,\
jdk.internal.,\ jdk.internal.,\
jdk.nashorn.internal.,\ jdk.nashorn.internal.,\
jdk.nashorn.tools. jdk.nashorn.tools.
# #
# Determines whether this properties file can be appended to # Determines whether this properties file can be appended to
...@@ -429,4 +460,4 @@ jdk.certpath.disabledAlgorithms=MD2, RSA keySize < 1024 ...@@ -429,4 +460,4 @@ jdk.certpath.disabledAlgorithms=MD2, RSA keySize < 1024
# #
# Example: # Example:
# jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 # jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048
i
...@@ -77,26 +77,57 @@ security.provider.9=sun.security.smartcardio.SunPCSC ...@@ -77,26 +77,57 @@ security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=sun.security.mscapi.SunMSCAPI security.provider.10=sun.security.mscapi.SunMSCAPI
# #
# Select the source of seed data for SecureRandom. By default an # Sun Provider SecureRandom seed source.
# attempt is made to use the entropy gathering device specified by #
# the securerandom.source property. If an exception occurs when # Select the primary source of seed data for the "SHA1PRNG" and
# accessing the URL then the traditional system/thread activity # "NativePRNG" SecureRandom implementations in the "Sun" provider.
# algorithm is used. # (Other SecureRandom implementations might also use this property.)
# #
# On Solaris and Linux systems, if file:/dev/urandom is specified and it # On Unix-like systems (for example, Solaris/Linux/MacOS), the
# exists, a special SecureRandom implementation is activated by default. # "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
# This "NativePRNG" reads random bytes directly from /dev/urandom. # special device files such as file:/dev/random.
# #
# On Windows systems, the URLs file:/dev/random and file:/dev/urandom # On Windows systems, specifying the URLs "file:/dev/random" or
# enables use of the Microsoft CryptoAPI seed functionality. # "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
# # mechanism for SHA1PRNG.
securerandom.source=file:/dev/urandom #
# # By default, an attempt is made to use the entropy gathering device
# The entropy gathering device is described as a URL and can also # specified by the "securerandom.source" Security property. If an
# be specified with the system property "java.security.egd". For example, # exception occurs while accessing the specified URL:
# -Djava.security.egd=file:/dev/urandom #
# Specifying this system property will override the securerandom.source # SHA1PRNG:
# setting. # 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 # Class to instantiate as the javax.security.auth.login.Configuration
...@@ -160,9 +191,9 @@ package.access=sun.,\ ...@@ -160,9 +191,9 @@ package.access=sun.,\
com.sun.org.glassfish.gmbal.,\ com.sun.org.glassfish.gmbal.,\
com.oracle.xmlns.internal.,\ com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\ com.oracle.webservices.internal.,\
jdk.internal.,\ jdk.internal.,\
jdk.nashorn.internal.,\ jdk.nashorn.internal.,\
jdk.nashorn.tools. jdk.nashorn.tools.
# #
# List of comma-separated packages that start with or equal this string # List of comma-separated packages that start with or equal this string
...@@ -188,9 +219,9 @@ package.definition=sun.,\ ...@@ -188,9 +219,9 @@ package.definition=sun.,\
com.sun.org.glassfish.gmbal.,\ com.sun.org.glassfish.gmbal.,\
com.oracle.xmlns.internal.,\ com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\ com.oracle.webservices.internal.,\
jdk.internal.,\ jdk.internal.,\
jdk.nashorn.internal.,\ jdk.nashorn.internal.,\
jdk.nashorn.tools. jdk.nashorn.tools.
# #
# Determines whether this properties file can be appended to # Determines whether this properties file can be appended to
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -26,34 +26,47 @@ ...@@ -26,34 +26,47 @@
package sun.security.provider; package sun.security.provider;
import java.io.*; import java.io.*;
import java.net.*;
import java.security.*; import java.security.*;
import java.security.SecureRandom; import sun.security.util.Debug;
/** /**
* Native PRNG implementation for Solaris/Linux. It interacts with * Native PRNG implementation for Solaris/Linux/MacOS.
* /dev/random and /dev/urandom, so it is only available if those * <p>
* files are present. Otherwise, SHA1PRNG is used instead of this class. * It obtains seed and random numbers by reading system files such as
* * the special device files /dev/random and /dev/urandom. This
* getSeed() and setSeed() directly read/write /dev/random. However, * implementation respects the {@code securerandom.source} Security
* /dev/random is only writable by root in many configurations. Because * property and {@code java.security.egd} System property for obtaining
* we cannot just ignore bytes specified via setSeed(), we keep a * seed material. If the file specified by the properties does not
* SHA1PRNG around in parallel. * exist, /dev/random is the default seed source. /dev/urandom is
* * the default source of random numbers.
* nextBytes() reads the bytes directly from /dev/urandom (and then * <p>
* mixes them with bytes from the SHA1PRNG for the reasons explained * On some Unix platforms, /dev/random may block until enough entropy is
* above). Reading bytes from /dev/urandom means that constantly get * available, but that may negatively impact the perceived startup
* new entropy the operating system has collected. This is a notable * time. By selecting these sources, this implementation tries to
* advantage over the SHA1PRNG model, which acquires entropy only * strike a balance between performance and security.
* initially during startup although the VM may be running for months. * <p>
* * generateSeed() and setSeed() attempt to directly read/write to the seed
* Also note that we do not need any initial pure random seed from * source. However, this file may only be writable by root in many
* /dev/random. This is an advantage because on some versions of Linux * configurations. Because we cannot just ignore bytes specified via
* it can be exhausted very quickly and could thus impact startup time. * 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) * Finally, note that we use a singleton for the actual work (RandomIO)
* to avoid having to open and close /dev/[u]random constantly. However, * 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 * @since 1.5
* @author Andreas Sterbenz * @author Andreas Sterbenz
...@@ -62,32 +75,121 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -62,32 +75,121 @@ public final class NativePRNG extends SecureRandomSpi {
private static final long serialVersionUID = -6599091113397072932L; private static final long serialVersionUID = -6599091113397072932L;
private static final Debug debug = Debug.getInstance("provider");
// name of the pure random file (also used for setSeed()) // name of the pure random file (also used for setSeed())
private static final String NAME_RANDOM = "/dev/random"; private static final String NAME_RANDOM = "/dev/random";
// name of the pseudo random file // name of the pseudo random file
private static final String NAME_URANDOM = "/dev/urandom"; 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 // 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( return AccessController.doPrivileged(
new PrivilegedAction<RandomIO>() { new PrivilegedAction<RandomIO>() {
@Override
public RandomIO run() { public RandomIO run() {
File randomFile = new File(NAME_RANDOM);
if (randomFile.exists() == false) { File seedFile;
return null; File nextFile;
}
File urandomFile = new File(NAME_URANDOM); switch(v) {
if (urandomFile.exists() == false) { case MIXED:
return null; URL egdUrl;
} File egdFile = null;
try {
return new RandomIO(randomFile, urandomFile); if ((egdUrl = getEgdUrl()) != null) {
} catch (Exception e) { try {
return null; 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;
}
} }
}
}); });
} }
...@@ -105,67 +207,173 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -105,67 +207,173 @@ public final class NativePRNG extends SecureRandomSpi {
} }
// set the seed // set the seed
@Override
protected void engineSetSeed(byte[] seed) { protected void engineSetSeed(byte[] seed) {
INSTANCE.implSetSeed(seed); INSTANCE.implSetSeed(seed);
} }
// get pseudo random bytes // get pseudo random bytes
@Override
protected void engineNextBytes(byte[] bytes) { protected void engineNextBytes(byte[] bytes) {
INSTANCE.implNextBytes(bytes); INSTANCE.implNextBytes(bytes);
} }
// get true random bytes // get true random bytes
@Override
protected byte[] engineGenerateSeed(int numBytes) { protected byte[] engineGenerateSeed(int numBytes) {
return INSTANCE.implGenerateSeed(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. * Nested class doing the actual work. Singleton, see INSTANCE above.
*/ */
private static class RandomIO { 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 // but we limit the lifetime to avoid using stale bits
// lifetime in ms, currently 100 ms (0.1 s) // lifetime in ms, currently 100 ms (0.1 s)
private final static long MAX_BUFFER_TIME = 100; 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; private final static int BUFFER_SIZE = 32;
// In/OutputStream for /dev/random and /dev/urandom // Holder for the seedFile. Used if we ever add seed material.
private final InputStream randomIn, urandomIn; File seedFile;
private OutputStream randomOut;
// In/OutputStream for "seed" and "next"
private final InputStream seedIn, nextIn;
private OutputStream seedOut;
// flag indicating if we have tried to open randomOut yet // flag indicating if we have tried to open seedOut yet
private boolean randomOutInitialized; private boolean seedOutInitialized;
// SHA1PRNG instance for mixing // SHA1PRNG instance for mixing
// initialized lazily on demand to avoid problems during startup // initialized lazily on demand to avoid problems during startup
private volatile sun.security.provider.SecureRandom mixRandom; private volatile sun.security.provider.SecureRandom mixRandom;
// buffer for /dev/urandom bits // buffer for next bits
private final byte[] urandomBuffer; private final byte[] nextBuffer;
// number of bytes left in urandomBuffer // number of bytes left in nextBuffer
private int buffered; private int buffered;
// time we read the data into the urandomBuffer // time we read the data into the nextBuffer
private long lastRead; private long lastRead;
// mutex lock for nextBytes() // mutex lock for nextBytes()
private final Object LOCK_GET_BYTES = new Object(); private final Object LOCK_GET_BYTES = new Object();
// mutex lock for getSeed() // mutex lock for generateSeed()
private final Object LOCK_GET_SEED = new Object(); private final Object LOCK_GET_SEED = new Object();
// mutex lock for setSeed() // mutex lock for setSeed()
private final Object LOCK_SET_SEED = new Object(); private final Object LOCK_SET_SEED = new Object();
// constructor, called only once from initIO() // constructor, called only once from initIO()
private RandomIO(File randomFile, File urandomFile) throws IOException { private RandomIO(File seedFile, File nextFile) throws IOException {
randomIn = new FileInputStream(randomFile); this.seedFile = seedFile;
urandomIn = new FileInputStream(urandomFile); seedIn = new FileInputStream(seedFile);
urandomBuffer = new byte[BUFFER_SIZE]; nextIn = new FileInputStream(nextFile);
nextBuffer = new byte[BUFFER_SIZE];
} }
// get the SHA1PRNG for mixing // get the SHA1PRNG for mixing
...@@ -179,7 +387,7 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -179,7 +387,7 @@ public final class NativePRNG extends SecureRandomSpi {
r = new sun.security.provider.SecureRandom(); r = new sun.security.provider.SecureRandom();
try { try {
byte[] b = new byte[20]; byte[] b = new byte[20];
readFully(urandomIn, b); readFully(nextIn, b);
r.engineSetSeed(b); r.engineSetSeed(b);
} catch (IOException e) { } catch (IOException e) {
throw new ProviderException("init failed", e); throw new ProviderException("init failed", e);
...@@ -192,7 +400,7 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -192,7 +400,7 @@ public final class NativePRNG extends SecureRandomSpi {
} }
// read data.length bytes from in // 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 // just keep trying as long as we are making progress
private static void readFully(InputStream in, byte[] data) private static void readFully(InputStream in, byte[] data)
throws IOException { throws IOException {
...@@ -201,22 +409,22 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -201,22 +409,22 @@ public final class NativePRNG extends SecureRandomSpi {
while (len > 0) { while (len > 0) {
int k = in.read(data, ofs, len); int k = in.read(data, ofs, len);
if (k <= 0) { if (k <= 0) {
throw new EOFException("/dev/[u]random closed?"); throw new EOFException("File(s) closed?");
} }
ofs += k; ofs += k;
len -= k; len -= k;
} }
if (len > 0) { 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) { private byte[] implGenerateSeed(int numBytes) {
synchronized (LOCK_GET_SEED) { synchronized (LOCK_GET_SEED) {
try { try {
byte[] b = new byte[numBytes]; byte[] b = new byte[numBytes];
readFully(randomIn, b); readFully(seedIn, b);
return b; return b;
} catch (IOException e) { } catch (IOException e) {
throw new ProviderException("generateSeed() failed", e); throw new ProviderException("generateSeed() failed", e);
...@@ -225,26 +433,27 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -225,26 +433,27 @@ public final class NativePRNG extends SecureRandomSpi {
} }
// supply random bytes to the OS // 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 // always add the seed to our mixing random
private void implSetSeed(byte[] seed) { private void implSetSeed(byte[] seed) {
synchronized (LOCK_SET_SEED) { synchronized (LOCK_SET_SEED) {
if (randomOutInitialized == false) { if (seedOutInitialized == false) {
randomOutInitialized = true; seedOutInitialized = true;
randomOut = AccessController.doPrivileged( seedOut = AccessController.doPrivileged(
new PrivilegedAction<OutputStream>() { new PrivilegedAction<OutputStream>() {
@Override
public OutputStream run() { public OutputStream run() {
try { try {
return new FileOutputStream(NAME_RANDOM, true); return new FileOutputStream(seedFile, true);
} catch (Exception e) { } catch (Exception e) {
return null; return null;
} }
} }
}); });
} }
if (randomOut != null) { if (seedOut != null) {
try { try {
randomOut.write(seed); seedOut.write(seed);
} catch (IOException e) { } catch (IOException e) {
throw new ProviderException("setSeed() failed", e); throw new ProviderException("setSeed() failed", e);
} }
...@@ -261,12 +470,12 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -261,12 +470,12 @@ public final class NativePRNG extends SecureRandomSpi {
return; return;
} }
lastRead = time; lastRead = time;
readFully(urandomIn, urandomBuffer); readFully(nextIn, nextBuffer);
buffered = urandomBuffer.length; buffered = nextBuffer.length;
} }
// get pseudo random bytes // 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 // mixing SHA1PRNG
private void implNextBytes(byte[] data) { private void implNextBytes(byte[] data) {
synchronized (LOCK_GET_BYTES) { synchronized (LOCK_GET_BYTES) {
...@@ -276,9 +485,9 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -276,9 +485,9 @@ public final class NativePRNG extends SecureRandomSpi {
int ofs = 0; int ofs = 0;
while (len > 0) { while (len > 0) {
ensureBufferValid(); ensureBufferValid();
int bufferOfs = urandomBuffer.length - buffered; int bufferOfs = nextBuffer.length - buffered;
while ((len > 0) && (buffered > 0)) { while ((len > 0) && (buffered > 0)) {
data[ofs++] ^= urandomBuffer[bufferOfs++]; data[ofs++] ^= nextBuffer[bufferOfs++];
len--; len--;
buffered--; buffered--;
} }
...@@ -288,7 +497,5 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -288,7 +497,5 @@ public final class NativePRNG extends SecureRandomSpi {
} }
} }
} }
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -34,8 +34,8 @@ import java.io.IOException; ...@@ -34,8 +34,8 @@ import java.io.IOException;
*/ */
class NativeSeedGenerator extends SeedGenerator.URLSeedGenerator { class NativeSeedGenerator extends SeedGenerator.URLSeedGenerator {
NativeSeedGenerator() throws IOException { NativeSeedGenerator(String seedFile) throws IOException {
super(); super(seedFile);
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -58,6 +58,7 @@ public final class PRNG extends SecureRandomSpi ...@@ -58,6 +58,7 @@ public final class PRNG extends SecureRandomSpi
* *
* @param seed the seed. * @param seed the seed.
*/ */
@Override
protected void engineSetSeed(byte[] seed) { protected void engineSetSeed(byte[] seed) {
if (seed != null) { if (seed != null) {
generateSeed(-1, seed); generateSeed(-1, seed);
...@@ -69,6 +70,7 @@ public final class PRNG extends SecureRandomSpi ...@@ -69,6 +70,7 @@ public final class PRNG extends SecureRandomSpi
* *
* @param bytes the array to be filled in with random bytes. * @param bytes the array to be filled in with random bytes.
*/ */
@Override
protected void engineNextBytes(byte[] bytes) { protected void engineNextBytes(byte[] bytes) {
if (bytes != null) { if (bytes != null) {
if (generateSeed(0, bytes) == null) { if (generateSeed(0, bytes) == null) {
...@@ -85,6 +87,7 @@ public final class PRNG extends SecureRandomSpi ...@@ -85,6 +87,7 @@ public final class PRNG extends SecureRandomSpi
* *
* @return the seed bytes. * @return the seed bytes.
*/ */
@Override
protected byte[] engineGenerateSeed(int numBytes) { protected byte[] engineGenerateSeed(int numBytes) {
byte[] seed = generateSeed(numBytes, null); byte[] seed = generateSeed(numBytes, null);
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -39,4 +39,15 @@ public final class NativePRNG { ...@@ -39,4 +39,15 @@ public final class NativePRNG {
return false; return false;
} }
public static final class NonBlocking {
static boolean isAvailable() {
return false;
}
}
public static final class Blocking {
static boolean isAvailable() {
return false;
}
}
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -39,7 +39,8 @@ class NativeSeedGenerator extends SeedGenerator { ...@@ -39,7 +39,8 @@ class NativeSeedGenerator extends SeedGenerator {
* @exception IOException if CryptoAPI seeds are not available * @exception IOException if CryptoAPI seeds are not available
* on this platform. * on this platform.
*/ */
NativeSeedGenerator() throws IOException { NativeSeedGenerator(String seedFile) throws IOException {
// seedFile is ignored.
super(); super();
// try generating two random bytes to see if CAPI is available // try generating two random bytes to see if CAPI is available
if (!nativeGenerateSeed(new byte[2])) { if (!nativeGenerateSeed(new byte[2])) {
......
/*
* 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();
}
}
/*
* 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");
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册