/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
/**
* files are present. Otherwise, SHA1PRNG is used instead of this class.
*
* we cannot just ignore bytes specified via setSeed(), we keep a
* SHA1PRNG around in parallel.
*
* mixes them with bytes from the SHA1PRNG for the reasons explained
* 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
* it can be exhausted very quickly and could thus impact startup time.
*
* 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.
*
* @since 1.5
* @author Andreas Sterbenz
*/
// name of the pure random file (also used for setSeed())
// name of the pseudo random file
// singleton instance or null if not available
return AccessController.doPrivileged(
new PrivilegedAction<RandomIO>() {
if (randomFile.exists() == false) {
return null;
}
if (urandomFile.exists() == false) {
return null;
}
try {
} catch (Exception e) {
return null;
}
}
});
}
// return whether the NativePRNG is available
static boolean isAvailable() {
}
// constructor, called by the JCA framework
public NativePRNG() {
super();
throw new AssertionError("NativePRNG not available");
}
}
// set the seed
}
// get pseudo random bytes
}
// get true random bytes
}
/**
* Nested class doing the actual work. Singleton, see INSTANCE above.
*/
private static class RandomIO {
// but we limit the lifetime to avoid using stale bits
// lifetime in ms, currently 100 ms (0.1 s)
// flag indicating if we have tried to open randomOut yet
private boolean randomOutInitialized;
// SHA1PRNG instance for mixing
// initialized lazily on demand to avoid problems during startup
private final byte[] urandomBuffer;
// number of bytes left in urandomBuffer
private int buffered;
// time we read the data into the urandomBuffer
private long lastRead;
// mutex lock for nextBytes()
// mutex lock for getSeed()
// mutex lock for setSeed()
// constructor, called only once from initIO()
urandomBuffer = new byte[BUFFER_SIZE];
}
// get the SHA1PRNG for mixing
// initialize if not yet created
if (r == null) {
synchronized (LOCK_GET_BYTES) {
r = mixRandom;
if (r == null) {
try {
byte[] b = new byte[20];
r.engineSetSeed(b);
} catch (IOException e) {
throw new ProviderException("init failed", e);
}
mixRandom = r;
}
}
}
return r;
}
// read data.length bytes from in
// /dev/[u]random are not normal files, so we need to loop the read.
// just keep trying as long as we are making progress
throws IOException {
int ofs = 0;
while (len > 0) {
if (k <= 0) {
throw new EOFException("/dev/[u]random closed?");
}
ofs += k;
len -= k;
}
if (len > 0) {
throw new IOException("Could not read from /dev/[u]random");
}
}
synchronized (LOCK_GET_SEED) {
try {
byte[] b = new byte[numBytes];
return b;
} catch (IOException e) {
throw new ProviderException("generateSeed() failed", e);
}
}
}
// supply random bytes to the OS
// always add the seed to our mixing random
synchronized (LOCK_SET_SEED) {
if (randomOutInitialized == false) {
randomOutInitialized = true;
new PrivilegedAction<OutputStream>() {
public OutputStream run() {
try {
return new FileOutputStream(NAME_RANDOM, true);
} catch (Exception e) {
return null;
}
}
});
}
try {
} catch (IOException e) {
throw new ProviderException("setSeed() failed", e);
}
}
}
}
// ensure that there is at least one valid byte in the buffer
// if not, read new bytes
return;
}
}
// get pseudo random bytes
// mixing SHA1PRNG
synchronized (LOCK_GET_BYTES) {
try {
int ofs = 0;
while (len > 0) {
len--;
buffered--;
}
}
} catch (IOException e) {
throw new ProviderException("nextBytes() failed", e);
}
}
}
}
}