home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1998 July & August
/
Pcwk78a98.iso
/
Internet
/
Javadraw
/
DATA.Z
/
SeedGenerator.java
< prev
next >
Wrap
Text File
|
1997-08-30
|
5KB
|
143 lines
/*
* @(#)SeedGenerator.java 1.3 96/11/23
*
* Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
* CopyrightVersion 1.1_beta
*
*/
package java.security;
/**
* This class exports a single static method (genSeed) that generates
* a seed for a cryptographically strong random number generator. The
* goal is to provide a seed whose least significant byte is "truly random."
* The seed is produced by creating a "sleeper thread" that sleeps for a
* designated time period, and spinning on Thread.yield() while waiting
* for the sleeper thread to terminate. The parent thread keeps track of
* the number of times that it yields, and returns this "spin count"
* as a seed. Remarkably, the low order bits of this seed seem to be
* quite random.
*
* @version 1.3, 97/08/30
* @author Josh Bloch
*/
class SeedGenerator {
private static int sleepTime;
static {
setSleepTime();
}
private static final int TARGET_SPIN_COUNT = 55000;
private static final int MIN_SPIN_COUNT = (6*TARGET_SPIN_COUNT)/10;
private static final int MAX_SPIN_COUNT = 2*TARGET_SPIN_COUNT;
/**
* This method calculates a sleep time that results in ~55000 thread
* yields. Experimentally, this seems sufficient to generate one random
* byte. Note that this method (which "performs an experiment")requires
* approximately one second to execute. It is called once when the class
* is loaded, and again if the computed sleep time "stops doing its job."
* (This will happen if the load on the machine changes drastically.)
*/
private static void setSleepTime() {
sleepTime = (1000*TARGET_SPIN_COUNT)/genSeed(1000);
Security.debug("Resetting sleep time for seed generation: "
+ sleepTime + " ms.");
}
/**
* genSeed() - The sole exported method from this class; generates a
* random seed, an integer whose last byte is intended to be "truly
* random". (Higher order bits may have some randomness as well.)
* This method is synchronized for two reasons: 1) it has the side effect
* of maintaining sleepTime, which is a static variable, and 2) having
* multiple threads generate seeds concurrently would likely result in
* unnecessary (and inefficent) increases in sleepTime.
*/
public synchronized static int genSeed() {
int candidate = genSeed(sleepTime);
/*
* If candidate is way too low, recalculate sleep time until it
* isn't. This is necessary to thwart an attack where our adversary
* loads down the machine in order to reduce the quality of the
* seed generation.
*/
while (candidate < MIN_SPIN_COUNT) {
Security.debug("Candidate seed too low: "+ candidate +" ms.");
setSleepTime();
candidate = genSeed(sleepTime);
}
/*
* If candidate is way too high, recalculate sleep time, but DO use
* the candidate (which is of HIGHER quality than necessary). This
* step merely reduces the cost to calculate subsequent seed bytes.
* It isn't necessarily a win, as the recalculation is time consuming,
* but it prevents seed calculation time from unnecessarily
* "ratcheting up" over time.
*/
if (candidate > MAX_SPIN_COUNT) {
Security.debug("Candidate seed too high: "+ candidate +" ms.");
setSleepTime();
}
return candidate;
}
/**
* Generate a random seed by spinning on thread yield while waiting for
* a child thread that sleeps for the designated period of time, in
* milliseconds. The returned seed is the number of times we yield
* whilst waiting for the child.
*/
private static int genSeed(int sleepTime) {
int counter = 0;
Thread sleeper = new Sleeper(sleepTime);
sleeper.start();
while (sleeper.isAlive()) {
counter++;
Thread.yield();
}
return counter;
}
}
/**
* This helper class exports a "sleeper thread" that sleeps for a designated
* period (in milliseconds) and terminates.
*/
class Sleeper extends Thread {
private int sleepTime;
Sleeper(int sleepTime) {
this.sleepTime = sleepTime;
}
final public void run() {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
}