提交 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.
*
* 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 @@ import sun.security.jca.GetInstance.Instance;
*
* 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 @@ public class SecureRandom extends java.util.Random {
*
* @see #getSeed
*/
@Override
public void setSeed(long seed) {
/*
* Ignore call from super constructor (as well as any other calls
......@@ -450,7 +452,7 @@ public class SecureRandom extends java.util.Random {
*
* @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 @@ public class SecureRandom extends java.util.Random {
* @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 @@ public class SecureRandom extends java.util.Random {
* @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 @@ public class SecureRandom extends java.util.Random {
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;
......
/*
* 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 @@ final class P11SecureRandom extends SecureRandomSpi {
}
// 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 @@ final class P11SecureRandom extends SecureRandomSpi {
}
// see JCA spec
@Override
protected void engineNextBytes(byte[] bytes) {
if ((bytes == null) || (bytes.length == 0)) {
return;
......@@ -149,6 +148,7 @@ final class P11SecureRandom extends SecureRandomSpi {
}
// see JCA spec
@Override
protected byte[] engineGenerateSeed(int numBytes) {
byte[] b = new byte[numBytes];
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -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.
*
* @param seed the seed.
......@@ -94,7 +94,7 @@ implements java.io.Serializable {
*/
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 @@ implements java.io.Serializable {
*
* @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 @@ implements java.io.Serializable {
*
* @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 @@ implements java.io.Serializable {
}
// Make sure at least one bit changes!
if (!zf)
if (!zf) {
state[0]++;
}
}
/**
......@@ -193,6 +199,7 @@ implements java.io.Serializable {
*
* @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 @@ implements java.io.Serializable {
s.defaultReadObject ();
try {
digest = MessageDigest.getInstance ("SHA");
digest = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException 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.
*
* 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 @@ package sun.security.provider;
* We also create a number of sleeper threads which add entropy
* to the system by keeping the scheduler busy.
* Twenty such samples should give us roughly 160 bits of randomness.
* <P> These values are gathered in the background by a daemon thread
* <p>
* These values are gathered in the background by a daemon thread
* thus allowing the system to continue performing it's different
* activites, which in turn add entropy to the random seed.
* <p> The class also gathers miscellaneous system information, some
* <p>
* The class also gathers miscellaneous system information, some
* machine dependent, some not. This information is then hashed together
* with the 20 seed bytes.
* <P> The alternative to the above approach is to acquire seed material
* <p>
* The alternative to the above approach is to acquire seed material
* from an entropy gathering device, such as /dev/random. This can be
* accomplished by setting the value of the "securerandom.source"
* security property (in the Java security properties file) to a URL
* specifying the location of the entropy gathering device.
* accomplished by setting the value of the {@code securerandom.source}
* Security property to a URL specifying the location of the entropy
* gathering device, or by setting the {@code java.security.egd} System
* property.
* <p>
* In the event the specified URL cannot be accessed the default
* mechanism is used.
* The Java security properties file is located in the file named
* &lt;JAVA_HOME&gt;/lib/security/java.security.
* &lt;JAVA_HOME&gt; refers to the value of the java.home system property,
* and specifies the directory where the JRE is installed.
* threading mechanism is used.
*
* @author Joshua Bloch
* @author Gadi Guy
......@@ -81,27 +84,28 @@ abstract class SeedGenerator {
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 @@ abstract class SeedGenerator {
+ 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 @@ abstract class SeedGenerator {
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 @@ abstract class SeedGenerator {
// 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 @@ abstract class SeedGenerator {
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 @@ 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
private byte[] pool;
private int start, end, count;
......@@ -245,11 +254,10 @@ abstract class SeedGenerator {
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 @@ abstract class SeedGenerator {
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 @@ abstract class SeedGenerator {
* 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 @@ abstract class SeedGenerator {
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 @@ abstract class SeedGenerator {
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 @@ abstract class SeedGenerator {
}
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 @@ abstract class SeedGenerator {
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 @@ abstract class SeedGenerator {
* 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 @@ abstract class SeedGenerator {
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 @@ abstract class SeedGenerator {
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 @@ abstract class SeedGenerator {
* 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 @@ abstract class SeedGenerator {
}
});
} 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 @@ abstract class SeedGenerator {
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);
}
}
}
}
/*
* 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 @@ final class SunEntries {
// 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 @@ final class SunEntries {
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 @@ final class SunEntries {
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 @@ final class SunEntries {
seedSource = AccessController.doPrivileged(
new PrivilegedAction<String>() {
@Override
public String run() {
String egdSource = System.getProperty(PROP_EGD, "");
if (egdSource.length() != 0) {
......@@ -314,4 +338,36 @@ final class SunEntries {
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
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.
#
# 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, the URLs file:/dev/random and file:/dev/urandom
# enables use of the Microsoft CryptoAPI seed functionality.
#
securerandom.source=file:/dev/urandom
#
# 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.
# 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 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.
#
# The entropy gathering device can also be specified with the System
# property "java.security.egd". For example:
#
# % java -Djava.security.egd=file:/dev/random MainClass
#
# Specifying this System property will override the
# "securerandom.source" Security property.
#
# In addition, if "file:/dev/random" or "file:/dev/urandom" is
# specified, the "NativePRNG" implementation will be more preferred than
# SHA1PRNG in the Sun provider.
#
securerandom.source=file:/dev/random
#
# A list of known strong SecureRandom implementations.
#
# To help guide applications in selecting a suitable strong
# java.security.SecureRandom implementation, Java distributions should
# indicate a list of known strong implementations using the property.
#
# This is a comma-separated list of algorithm and/or algorithm:provider
# entries.
#
securerandom.strongAlgorithms=NativePRNGBlocking:SUN
#
# Class to instantiate as the javax.security.auth.login.Configuration
......@@ -159,9 +190,9 @@ package.access=sun.,\
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 @@ package.definition=sun.,\
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
......
......@@ -77,26 +77,57 @@ security.provider.9=sun.security.smartcardio.SunPCSC
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.
#
# 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, the URLs file:/dev/random and file:/dev/urandom
# enables use of the Microsoft CryptoAPI seed functionality.
#
securerandom.source=file:/dev/urandom
#
# 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.
# 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 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.
#
# The entropy gathering device can also be specified with the System
# property "java.security.egd". For example:
#
# % java -Djava.security.egd=file:/dev/random MainClass
#
# Specifying this System property will override the
# "securerandom.source" Security property.
#
# In addition, if "file:/dev/random" or "file:/dev/urandom" is
# specified, the "NativePRNG" implementation will be more preferred than
# SHA1PRNG in the Sun provider.
#
securerandom.source=file:/dev/random
#
# A list of known strong SecureRandom implementations.
#
# To help guide applications in selecting a suitable strong
# java.security.SecureRandom implementation, Java distributions should
# indicate a list of known strong implementations using the property.
#
# This is a comma-separated list of algorithm and/or algorithm:provider
# entries.
#
securerandom.strongAlgorithms=NativePRNGBlocking:SUN
#
# Class to instantiate as the javax.security.auth.login.Configuration
......@@ -160,9 +191,9 @@ package.access=sun.,\
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 @@ package.definition=sun.,\
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.
#
......
......@@ -78,26 +78,57 @@ security.provider.10=org.jcp.xml.dsig.internal.dom.XMLDSigRI
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.
#
# 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, the URLs file:/dev/random and file:/dev/urandom
# enables use of the Microsoft CryptoAPI seed functionality.
#
securerandom.source=file:/dev/urandom
#
# 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.
# 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 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.
#
# The entropy gathering device can also be specified with the System
# property "java.security.egd". For example:
#
# % java -Djava.security.egd=file:/dev/random MainClass
#
# Specifying this System property will override the
# "securerandom.source" Security property.
#
# In addition, if "file:/dev/random" or "file:/dev/urandom" is
# specified, the "NativePRNG" implementation will be more preferred than
# SHA1PRNG in the Sun provider.
#
securerandom.source=file:/dev/random
#
# A list of known strong SecureRandom implementations.
#
# To help guide applications in selecting a suitable strong
# java.security.SecureRandom implementation, Java distributions should
# indicate a list of known strong implementations using the property.
#
# This is a comma-separated list of algorithm and/or algorithm:provider
# entries.
#
securerandom.strongAlgorithms=NativePRNGBlocking:SUN
#
# Class to instantiate as the javax.security.auth.login.Configuration
......@@ -161,9 +192,9 @@ package.access=sun.,\
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 @@ package.definition=sun.,\
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 @@ jdk.certpath.disabledAlgorithms=MD2, RSA keySize < 1024
#
# Example:
# jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048
i
......@@ -77,26 +77,57 @@ security.provider.9=sun.security.smartcardio.SunPCSC
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.
#
# 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, the URLs file:/dev/random and file:/dev/urandom
# enables use of the Microsoft CryptoAPI seed functionality.
#
securerandom.source=file:/dev/urandom
#
# 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.
# 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 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.
#
# The entropy gathering device can also be specified with the System
# property "java.security.egd". For example:
#
# % java -Djava.security.egd=file:/dev/random MainClass
#
# Specifying this System property will override the
# "securerandom.source" Security property.
#
# In addition, if "file:/dev/random" or "file:/dev/urandom" is
# specified, the "NativePRNG" implementation will be more preferred than
# SHA1PRNG in the Sun provider.
#
securerandom.source=file:/dev/random
#
# A list of known strong SecureRandom implementations.
#
# To help guide applications in selecting a suitable strong
# java.security.SecureRandom implementation, Java distributions should
# indicate a list of known strong implementations using the property.
#
# This is a comma-separated list of algorithm and/or algorithm:provider
# entries.
#
securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI
#
# Class to instantiate as the javax.security.auth.login.Configuration
......@@ -160,9 +191,9 @@ package.access=sun.,\
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 @@ package.definition=sun.,\
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
......
/*
* 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 @@ public final class NativePRNG extends SecureRandomSpi {
private static final long serialVersionUID = -6599091113397072932L;
private static final Debug debug = Debug.getInstance("provider");
// name of the pure random file (also used for setSeed())
private static final String NAME_RANDOM = "/dev/random";
// name of the pseudo random file
private static final String NAME_URANDOM = "/dev/urandom";
// which kind of RandomIO object are we creating?
private enum Variant {
MIXED, BLOCKING, NONBLOCKING
}
// singleton instance or null if not available
private static final RandomIO INSTANCE = initIO();
private static final RandomIO INSTANCE = initIO(Variant.MIXED);
private static RandomIO initIO() {
/**
* Get the System egd source (if defined). We only allow "file:"
* URLs for now. If there is a egd value, parse it.
*
* @return the URL or null if not available.
*/
private static URL getEgdUrl() {
// This will return "" if nothing was set.
String egdSource = SunEntries.getSeedSource();
URL egdUrl;
if (egdSource.length() != 0) {
if (debug != null) {
debug.println("NativePRNG egdUrl: " + egdSource);
}
try {
egdUrl = new URL(egdSource);
if (!egdUrl.getProtocol().equalsIgnoreCase("file")) {
return null;
}
} catch (MalformedURLException e) {
return null;
}
} else {
egdUrl = null;
}
return egdUrl;
}
/**
* Create a RandomIO object for all I/O of this Variant type.
*/
private static RandomIO initIO(final Variant v) {
return AccessController.doPrivileged(
new PrivilegedAction<RandomIO>() {
@Override
public RandomIO run() {
File randomFile = new File(NAME_RANDOM);
if (randomFile.exists() == false) {
return null;
}
File urandomFile = new File(NAME_URANDOM);
if (urandomFile.exists() == false) {
return null;
}
try {
return new RandomIO(randomFile, urandomFile);
} catch (Exception e) {
return null;
File seedFile;
File nextFile;
switch(v) {
case MIXED:
URL egdUrl;
File egdFile = null;
if ((egdUrl = getEgdUrl()) != null) {
try {
egdFile = SunEntries.getDeviceFile(egdUrl);
} catch (IOException e) {
// Swallow, seedFile is still null
}
}
// Try egd first.
if ((egdFile != null) && egdFile.canRead()) {
seedFile = egdFile;
} else {
// fall back to /dev/random.
seedFile = new File(NAME_RANDOM);
}
nextFile = new File(NAME_URANDOM);
break;
case BLOCKING:
seedFile = new File(NAME_RANDOM);
nextFile = new File(NAME_RANDOM);
break;
case NONBLOCKING:
seedFile = new File(NAME_URANDOM);
nextFile = new File(NAME_URANDOM);
break;
default:
// Shouldn't happen!
return null;
}
if (debug != null) {
debug.println("NativePRNG." + v +
" seedFile: " + seedFile +
" nextFile: " + nextFile);
}
if (!seedFile.canRead() || !nextFile.canRead()) {
if (debug != null) {
debug.println("NativePRNG." + v +
" Couldn't read Files.");
}
return null;
}
try {
return new RandomIO(seedFile, nextFile);
} catch (Exception e) {
return null;
}
}
}
});
}
......@@ -105,67 +207,173 @@ public final class NativePRNG extends SecureRandomSpi {
}
// 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;
// In/OutputStream for "seed" and "next"
private final InputStream seedIn, nextIn;
private OutputStream seedOut;
// flag indicating if we have tried to open randomOut yet
private boolean randomOutInitialized;
// 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 @@ public final class NativePRNG extends SecureRandomSpi {
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 @@ public final class NativePRNG extends SecureRandomSpi {
}
// 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 @@ public final class NativePRNG extends SecureRandomSpi {
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 @@ public final class NativePRNG extends SecureRandomSpi {
}
// 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 @@ public final class NativePRNG extends SecureRandomSpi {
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 @@ public final class NativePRNG extends SecureRandomSpi {
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 @@ 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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -34,8 +34,8 @@ import java.io.IOException;
*/
class NativeSeedGenerator extends SeedGenerator.URLSeedGenerator {
NativeSeedGenerator() throws IOException {
super();
NativeSeedGenerator(String seedFile) throws IOException {
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -58,6 +58,7 @@ public final class PRNG extends SecureRandomSpi
*
* @param seed the seed.
*/
@Override
protected void engineSetSeed(byte[] seed) {
if (seed != null) {
generateSeed(-1, seed);
......@@ -69,6 +70,7 @@ public final class PRNG extends SecureRandomSpi
*
* @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 @@ public final class PRNG extends SecureRandomSpi
*
* @return the seed bytes.
*/
@Override
protected byte[] engineGenerateSeed(int numBytes) {
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -39,4 +39,15 @@ public final class NativePRNG {
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -39,7 +39,8 @@ class NativeSeedGenerator extends SeedGenerator {
* @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])) {
......
/*
* 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.
先完成此消息的编辑!
想要评论请 注册