home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-01-23 | 4.9 KB | 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/11/25
- * @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) {
- }
- }
- }
-