home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / SeedGenerator.java < prev    next >
Text File  |  1998-01-23  |  5KB  |  143 lines

  1. /*
  2.  * @(#)SeedGenerator.java    1.3 96/11/23
  3.  * 
  4.  * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  * CopyrightVersion 1.1_beta
  20.  * 
  21.  */
  22.  
  23. package java.security;
  24.  
  25. /**
  26.  * This class exports a single static method (genSeed) that generates
  27.  * a seed for a cryptographically strong random number generator.  The
  28.  * goal is to provide a seed whose least significant byte is "truly random."
  29.  * The seed is produced by creating a "sleeper thread" that sleeps for a
  30.  * designated time period, and spinning on Thread.yield() while waiting
  31.  * for the sleeper thread to terminate.  The parent thread keeps track of
  32.  * the number of times that it yields, and returns this "spin count"
  33.  * as a seed.  Remarkably, the low order bits of this seed seem to be
  34.  * quite random.
  35.  *
  36.  * @version 1.3, 97/11/25
  37.  * @author Josh Bloch
  38.  */
  39.  
  40. class SeedGenerator {
  41.     private static int sleepTime;
  42.     static {
  43.     setSleepTime();
  44.     }
  45.  
  46.     private static final int TARGET_SPIN_COUNT = 55000;
  47.     private static final int MIN_SPIN_COUNT = (6*TARGET_SPIN_COUNT)/10;
  48.     private static final int MAX_SPIN_COUNT = 2*TARGET_SPIN_COUNT;
  49.  
  50.     /**
  51.      * This method calculates a sleep time that results in ~55000 thread
  52.      * yields.  Experimentally, this seems sufficient to generate one random
  53.      * byte.  Note that this  method (which "performs an experiment")requires
  54.      * approximately one second to execute.  It is called once when the class
  55.      * is loaded, and again if the computed sleep time "stops doing its job."
  56.      * (This will happen if the load on the machine changes drastically.)
  57.      */
  58.     private static void setSleepTime() {
  59.     sleepTime = (1000*TARGET_SPIN_COUNT)/genSeed(1000);
  60.     Security.debug("Resetting sleep time for seed generation: "
  61.                + sleepTime + " ms.");
  62.      }
  63.  
  64.     /**
  65.      * genSeed() - The sole exported method from this class; generates a
  66.      * random seed, an integer whose last byte is intended to be "truly
  67.      * random".  (Higher order bits may have some randomness as well.)
  68.      * This method is synchronized for two reasons: 1) it has the side effect
  69.      * of maintaining sleepTime, which is a static variable, and 2) having
  70.      * multiple threads generate seeds concurrently would likely result in
  71.      * unnecessary (and inefficent) increases in sleepTime.
  72.      */
  73.     public synchronized static int genSeed() {
  74.     int candidate = genSeed(sleepTime);
  75.  
  76.     /*
  77.      * If candidate is way too low, recalculate sleep time until it
  78.      * isn't.  This is necessary to thwart an attack where our adversary
  79.      * loads down the machine in order to reduce the quality of the
  80.      * seed generation.
  81.      */
  82.     while (candidate < MIN_SPIN_COUNT) {
  83.         Security.debug("Candidate seed too low: "+ candidate +" ms.");
  84.         setSleepTime();
  85.         candidate = genSeed(sleepTime);
  86.     }
  87.  
  88.     /*
  89.      * If candidate is way too high, recalculate sleep time, but DO use
  90.      * the candidate (which is of HIGHER quality than necessary).  This
  91.      * step merely reduces the cost to calculate subsequent seed bytes.
  92.      * It isn't necessarily a win, as the recalculation is time consuming,
  93.      * but it prevents seed calculation time from unnecessarily
  94.      * "ratcheting up" over time.
  95.      */
  96.     if (candidate > MAX_SPIN_COUNT) {
  97.         Security.debug("Candidate seed too high: "+ candidate +" ms.");
  98.         setSleepTime();
  99.     }
  100.  
  101.     return candidate;
  102.     }
  103.  
  104.     /**
  105.      * Generate a random seed by spinning on thread yield while waiting for
  106.      * a child thread that sleeps for the designated period of time, in
  107.      * milliseconds.  The returned seed is the number of times we yield
  108.      * whilst waiting for the child.
  109.      */
  110.     private static int genSeed(int sleepTime) {
  111.     int counter = 0;
  112.  
  113.     Thread sleeper = new Sleeper(sleepTime);
  114.     sleeper.start();
  115.  
  116.     while (sleeper.isAlive()) {
  117.         counter++;
  118.         Thread.yield();
  119.     }
  120.  
  121.     return counter;
  122.     }
  123. }
  124.  
  125. /**
  126.  * This helper class exports a "sleeper thread" that sleeps for a designated
  127.  * period (in milliseconds) and terminates.
  128.  */
  129. class Sleeper extends Thread {
  130.     private int sleepTime;
  131.  
  132.     Sleeper(int sleepTime) {
  133.     this.sleepTime = sleepTime;
  134.     }
  135.  
  136.     final public void run() {
  137.     try {
  138.         Thread.sleep(sleepTime);
  139.     } catch (InterruptedException e) {
  140.     }
  141.     }
  142. }
  143.