home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / SecureRandom.java < prev    next >
Text File  |  1997-05-20  |  9KB  |  251 lines

  1. /*
  2.  * @(#)SecureRandom.java    1.16 97/01/30
  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. import java.util.*;
  26.  
  27. /**
  28.  * <p>This class provides a crytpographically strong pseudo-random number
  29.  * generator based on the SHA-1 hash algorithm.
  30.  *
  31.  * <p>The calls inherited from Random will be implemented in terms of the
  32.  * strengthened functionality.
  33.  *
  34.  * @see java.util.Random
  35.  * 
  36.  * @version 1.2 96/09/15
  37.  * @author Benjamin Renaud
  38.  * @author Josh Bloch 
  39.  */
  40.  
  41. public class SecureRandom extends Random {
  42.     private byte[] state;
  43.     private MessageDigest digest;
  44.  
  45.     /**
  46.      * Used by the empty constructor to seed the SecureRandom under construction.
  47.      */
  48.     private static SecureRandom generatorGenerator;
  49.  
  50.     /**
  51.      * This empty constructor automatically seeds the generator.  We attempt
  52.      * to provide sufficient seed bytes to completely randomize the internal
  53.      * state of the generator (20 bytes).  Note, however, that our seed
  54.      * generation algorithm has not been thoroughly studied or widely deployed.
  55.      * It relies on counting the number of times that the calling thread
  56.      * can yield while waiting for another thread to sleep for a specified
  57.      * interval. 
  58.      * 
  59.      * <p>The first time this constructor is called in a given Virtual Machine,
  60.      * it may take several seconds of CPU time to seed the generator, depending
  61.      * on the underlying hardware.  Successive calls run quickly because they
  62.      * rely on the same (internal) pseudo-random number generator for their
  63.      * seed bits.
  64.      *
  65.      * <p>The seeding procedure implemented by this constructor ensures that
  66.      * the sequence of pseudo-random bytes produced by each SecureRandom 
  67.      * instance yields no useful information about the byte-sequence produced
  68.      * by any other instance.  If however, the user wishes to produce multiple 
  69.      * instances with truly unrelated seeds, the following code yields
  70.      * the desired result (at substantial CPU cost per instance!):<p>
  71.      *
  72.      * <pre>
  73.      * SecureRandom rnd = new SecureRandom(SecureRandom.getSeed(20));
  74.      * </pre>
  75.      */
  76.     public SecureRandom() {
  77.     this(nextSeed());
  78.     }
  79.  
  80.     /**
  81.      * This call, used exclusively by the empty constructor, returns 20 seed
  82.      * bytes to seed the SecureRandom instance under construction.  The first
  83.      * time this method is called, creates a class-wide generator-generator.
  84.      * This involves generating 20 "real-random" bytes with getSeed, which is
  85.      * very time consuming!
  86.      */
  87.     private synchronized static byte[] nextSeed() {
  88.     if (generatorGenerator == null)
  89.         generatorGenerator = new SecureRandom(getSeed(20));
  90.  
  91.     byte seed[] = new byte[20];
  92.     generatorGenerator.nextBytes(seed);
  93.     return seed;
  94.     }
  95.  
  96.  
  97.     /**
  98.      * This constructor uses a user-provided seed in preference to the 
  99.      * self-seeding algorithm referred to in the empty constructor 
  100.      * description. It may be preferable to the empty constructor if the 
  101.      * caller has access to high-quality random bytes from some physical 
  102.      * device (for example, a radiation detector or a noisy diode).
  103.      * 
  104.      * @param seed the seed.
  105.      */
  106.     public SecureRandom(byte seed[]) {
  107.     /*
  108.      * This call to our superclass constructor will result in a call
  109.      * to our own setSeed method, which will return immediately when
  110.      * it is passed zero.
  111.      */
  112.     super(0);
  113.  
  114.     try {
  115.         digest = MessageDigest.getInstance("SHA");
  116.     } catch (NoSuchAlgorithmException e) {
  117.         throw new InternalError("internal error: SHA-1 not available.");
  118.     }
  119.  
  120.     setSeed(seed);
  121.     }
  122.  
  123.     /**
  124.      * Reseeds this random object. The given seed supplements, rather than
  125.      * replaces, the existing seed. Thus, repeated calls are guaranteed
  126.      * never to reduce randomness.
  127.      *
  128.      * @param seed the seed.
  129.      */
  130.     synchronized public void setSeed(byte[] seed) {
  131.     if (state != null)
  132.         digest.update(state);
  133.     state = digest.digest(seed);
  134.     }
  135.  
  136.     /**
  137.      * Reseeds this random object, using the eight bytes contained 
  138.      * in the given <code>long seed</code>. The given seed supplements, 
  139.      * rather than replaces, the existing seed. Thus, repeated calls 
  140.      * are guaranteed never to reduce randomness. 
  141.      * 
  142.      * <p>This method is defined for compatibility with 
  143.      * <code>java.util.Random</code>.
  144.      *
  145.      * @param seed the seed.
  146.      */
  147.     public void setSeed(long seed) {
  148.     /* 
  149.      * Ignore call from super constructor (as well as any other calls
  150.      * unfortunate enough to be passing 0).  It's critical that we
  151.      * ignore call from superclass constructor, as digest has not
  152.      * yet been initialized at that point.
  153.      */
  154.     if (seed != 0)
  155.         setSeed(longToByteArray(seed));
  156.     }
  157.  
  158.     private byte[] randomBytes = null;
  159.     private int randomBytesUsed = 0;
  160.     private long counter = 0;    /* # of times we've generated randomBytes */
  161.  
  162.     /**
  163.      * Generates a user-specified number of random bytes.  This method is
  164.      * used as the basis of all random entities returned by this class
  165.      * (except seed bytes).  Thus, it may be overridden to change the
  166.      * behavior of the class.
  167.      * 
  168.      * @param bytes the array to be filled in with random bytes.
  169.      */
  170.  
  171.     synchronized public void nextBytes(byte[] bytes) {
  172.     int numRequested = bytes.length;
  173.     int numGot = 0;
  174.  
  175.     while (numGot < numRequested) {
  176.         /* If no more random bytes, make some more */
  177.         if (randomBytes == null || randomBytesUsed == randomBytes.length) {
  178.         digest.update(state);
  179.         randomBytes = digest.digest(longToByteArray(counter++));
  180.         randomBytesUsed = 0;
  181.         }
  182.  
  183.         bytes[numGot++] = randomBytes[randomBytesUsed++];
  184.     }
  185.     }
  186.  
  187.     /**
  188.      * Generates an integer containing the user-specified number of
  189.      * pseudo-random bits (right justified, with leading zeros).  This
  190.      * method overrides a <code>java.util.Random</code> method, and serves 
  191.      * to provide a source of random bits to all of the methods inherited 
  192.      * from that class (for example, <code>nextInt</code>, 
  193.      * <code>nextLong</code>, and <code>nextFloat</code>).
  194.      *
  195.      * @param numBits number of pseudo-random bits to be generated, where 
  196.      * 0 <= <code>numBits</code> <= 32.
  197.      */
  198.     final protected int next(int numBits) {
  199.     int numBytes = (numBits+7)/8;
  200.     byte b[] = new byte[numBytes];
  201.         int next = 0;
  202.  
  203.     nextBytes(b);
  204.     for (int i=0; i<numBytes; i++)
  205.         next = (next << 8) + (b[i] & 0xFF);
  206.  
  207.         return next >>> (numBytes*8 - numBits);
  208.     }
  209.  
  210.     /**
  211.      * Returns the given number of seed bytes, computed using the seed
  212.      * generation algorithm that this class uses to seed itself.  This
  213.      * call may be used to seed other random number generators.  While
  214.      * we attempt to return a "truly random" sequence of bytes, we do not 
  215.      * know exactly how random the bytes returned by this call are.  (See 
  216.      * the empty constructor <a href = "#SecureRandom">SecureRandom</a>
  217.      * for a brief description of the underlying algorithm.)
  218.      * The prudent user will err on the side of caution and get extra
  219.      * seed bytes, although it should be noted that seed generation is
  220.      * somewhat costly.
  221.      *
  222.      * @param numBytes the number of seed bytes to generate.
  223.      * 
  224.      * @return the seed bytes.
  225.      */
  226.      public static byte[] getSeed(int numBytes) {
  227.      byte[] retVal = new byte[numBytes];
  228.  
  229.      for (int i=0; i<numBytes; i++)
  230.          retVal[i] = (byte) SeedGenerator.genSeed();
  231.  
  232.      return retVal;
  233.      }
  234.  
  235.  
  236.     /**
  237.      * Helper function to convert a long into a byte array (least significant
  238.      * byte first).
  239.      */
  240.     private static byte[] longToByteArray(long l) {
  241.     byte[] retVal = new byte[8];
  242.  
  243.     for (int i=0; i<8; i++) {
  244.         retVal[i] = (byte) l;
  245.         l >>= 8;
  246.     }
  247.  
  248.     return retVal;
  249.     }
  250. }
  251.