home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / security / SecureRandom.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  10.0 KB  |  293 lines

  1. /*
  2.  * @(#)SecureRandom.java    1.21 98/03/18
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.security;
  16.  
  17. import java.io.IOException;
  18. import java.util.*;
  19.  
  20. /**
  21.  * <p>This class provides a crytpographically strong pseudo-random number
  22.  * generator based on the SHA-1 hash algorithm.
  23.  *
  24.  * <p>The calls inherited from Random will be implemented in terms of the
  25.  * strengthened functionality.
  26.  *
  27.  * <p>Note that if a seed is not provided, we attempt to provide sufficient
  28.  * seed bytes to completely randomize the internal state of the generator
  29.  * (20 bytes).  However, our seed generation algorithm has not been thoroughly
  30.  * studied or widely deployed.  It relies on counting the number of times that
  31.  * the calling thread can yield while waiting for another thread to sleep for
  32.  * a specified interval. 
  33.  *
  34.  * <p>Also note that when a random object is deserialized,
  35.  * <a href="#nextBytes(byte[])">nextBytes</a> invoked on the restored random
  36.  * object will yield the exact same (random) bytes as the original object.
  37.  * If this behaviour is not desired, the restored random object should be
  38.  * seeded, using <a href="#setSeed(byte[])">setSeed</a>.
  39.  *
  40.  * @see java.util.Random
  41.  * 
  42.  * @version 1.2 96/09/15
  43.  * @author Benjamin Renaud
  44.  * @author Josh Bloch 
  45.  */
  46.  
  47. public class SecureRandom extends Random {
  48.     private byte[] state;
  49.     private transient MessageDigest digest;
  50.  
  51.     /**
  52.      * Used by the empty constructor to seed the SecureRandom under
  53.      * construction
  54.      */
  55.     private static SecureRandom generatorGenerator;
  56.  
  57.     /**
  58.      * This empty constructor automatically seeds the generator.  We attempt
  59.      * to provide sufficient seed bytes to completely randomize the internal
  60.      * state of the generator (20 bytes).  Note, however, that our seed
  61.      * generation algorithm has not been thoroughly studied or widely deployed.
  62.      * It relies on counting the number of times that the calling thread
  63.      * can yield while waiting for another thread to sleep for a specified
  64.      * interval. 
  65.      * 
  66.      * <p>The first time this constructor is called in a given Virtual Machine,
  67.      * it may take several seconds of CPU time to seed the generator, depending
  68.      * on the underlying hardware.  Successive calls run quickly because they
  69.      * rely on the same (internal) pseudo-random number generator for their
  70.      * seed bits.
  71.      *
  72.      * <p>The seeding procedure implemented by this constructor ensures that
  73.      * the sequence of pseudo-random bytes produced by each SecureRandom 
  74.      * instance yields no useful information about the byte-sequence produced
  75.      * by any other instance.  If however, the user wishes to produce multiple 
  76.      * instances with truly unrelated seeds, the following code yields
  77.      * the desired result (at substantial CPU cost per instance!):<p>
  78.      *
  79.      * <pre>
  80.      * SecureRandom rnd = new SecureRandom(SecureRandom.getSeed(20));
  81.      * </pre>
  82.      */
  83.     public SecureRandom() {
  84.     this(nextSeed());
  85.     }
  86.  
  87.     /**
  88.      * This call, used exclusively by the empty constructor, returns 20 seed
  89.      * bytes to seed the SecureRandom instance under construction.  The first
  90.      * time this method is called, creates a class-wide generator-generator.
  91.      * This involves generating 20 "real-random" bytes with getSeed, which is
  92.      * very time consuming!
  93.      */
  94.     private synchronized static byte[] nextSeed() {
  95.     if (generatorGenerator == null)
  96.         generatorGenerator = new SecureRandom(getSeed(20));
  97.  
  98.     byte seed[] = new byte[20];
  99.     generatorGenerator.nextBytes(seed);
  100.     return seed;
  101.     }
  102.  
  103.  
  104.     /**
  105.      * This constructor uses a user-provided seed in preference to the 
  106.      * self-seeding algorithm referred to in the empty constructor 
  107.      * description. It may be preferable to the empty constructor if the 
  108.      * caller has access to high-quality random bytes from some physical 
  109.      * device (for example, a radiation detector or a noisy diode).
  110.      * 
  111.      * @param seed the seed.
  112.      */
  113.     public SecureRandom(byte seed[]) {
  114.     /*
  115.      * This call to our superclass constructor will result in a call
  116.      * to our own setSeed method, which will return immediately when
  117.      * it is passed zero.
  118.      */
  119.     super(0);
  120.  
  121.     try {
  122.         digest = MessageDigest.getInstance("SHA");
  123.     } catch (NoSuchAlgorithmException e) {
  124.         throw new InternalError("internal error: SHA-1 not available.");
  125.     }
  126.  
  127.     setSeed(seed);
  128.     }
  129.  
  130.     /**
  131.      * Reseeds this random object. The given seed supplements, rather than
  132.      * replaces, the existing seed. Thus, repeated calls are guaranteed
  133.      * never to reduce randomness.
  134.      *
  135.      * @param seed the seed.
  136.      */
  137.     synchronized public void setSeed(byte[] seed) {
  138.     if (state != null)
  139.         digest.update(state);
  140.     state = digest.digest(seed);
  141.     }
  142.  
  143.     /**
  144.      * Reseeds this random object, using the eight bytes contained 
  145.      * in the given <code>long seed</code>. The given seed supplements, 
  146.      * rather than replaces, the existing seed. Thus, repeated calls 
  147.      * are guaranteed never to reduce randomness. 
  148.      * 
  149.      * <p>This method is defined for compatibility with 
  150.      * <code>java.util.Random</code>.
  151.      *
  152.      * @param seed the seed.
  153.      */
  154.     public void setSeed(long seed) {
  155.     /* 
  156.      * Ignore call from super constructor (as well as any other calls
  157.      * unfortunate enough to be passing 0).  It's critical that we
  158.      * ignore call from superclass constructor, as digest has not
  159.      * yet been initialized at that point.
  160.      */
  161.     if (seed != 0)
  162.         setSeed(longToByteArray(seed));
  163.     }
  164.  
  165.     private byte[] randomBytes = null;
  166.     private int randomBytesUsed = 12;
  167.     private long counter = 0;    /* # of times we've generated randomBytes */
  168.  
  169.     /**
  170.      * Generates a user-specified number of random bytes.  This method is
  171.      * used as the basis of all random entities returned by this class
  172.      * (except seed bytes).  Thus, it may be overridden to change the
  173.      * behavior of the class.
  174.      * 
  175.      * @param bytes the array to be filled in with random bytes.
  176.      */
  177.  
  178.     synchronized public void nextBytes(byte[] bytes) {
  179.     int numRequested = bytes.length;
  180.     int numGot = 0;
  181.  
  182.     /*
  183.      *  This method follows IEEE P1363, Appendix G.7, page 88
  184.      *  (expansion of source bits):
  185.      *
  186.      *  A cryptographically strong hash function (such as SHA-1)
  187.      *  computed over a true-random seed value concatenated with
  188.      *  a counter which is incremented for each operation.  [For
  189.      *  example, one could have 256 bits of true-random seed and
  190.      *  a 64 bit counter, all hashed by SHA to yield 160 bits of
  191.      *  output, from which only 64 are used -- with the counter
  192.      *  incremented by 1 for each output batch. ]
  193.      */
  194.  
  195.     while (numGot < numRequested) {
  196.         /* If no more random bytes, make some more */
  197.         if (randomBytes == null || randomBytesUsed == randomBytes.length) {
  198.         digest.update(state);
  199.         randomBytes = digest.digest(longToByteArray(counter++));
  200.         randomBytesUsed = 12;
  201.         }
  202.  
  203.         bytes[numGot++] = randomBytes[randomBytesUsed++];
  204.     }
  205.     }
  206.  
  207.     /**
  208.      * Generates an integer containing the user-specified number of
  209.      * pseudo-random bits (right justified, with leading zeros).  This
  210.      * method overrides a <code>java.util.Random</code> method, and serves 
  211.      * to provide a source of random bits to all of the methods inherited 
  212.      * from that class (for example, <code>nextInt</code>, 
  213.      * <code>nextLong</code>, and <code>nextFloat</code>).
  214.      *
  215.      * @param numBits number of pseudo-random bits to be generated, where 
  216.      * 0 <= <code>numBits</code> <= 32.
  217.      */
  218.     final protected int next(int numBits) {
  219.     int numBytes = (numBits+7)/8;
  220.     byte b[] = new byte[numBytes];
  221.         int next = 0;
  222.  
  223.     nextBytes(b);
  224.     for (int i=0; i<numBytes; i++)
  225.         next = (next << 8) + (b[i] & 0xFF);
  226.  
  227.         return next >>> (numBytes*8 - numBits);
  228.     }
  229.  
  230.     /**
  231.      * Returns the given number of seed bytes, computed using the seed
  232.      * generation algorithm that this class uses to seed itself.  This
  233.      * call may be used to seed other random number generators.  While
  234.      * we attempt to return a "truly random" sequence of bytes, we do not 
  235.      * know exactly how random the bytes returned by this call are.  (See 
  236.      * the empty constructor <a href = "#SecureRandom">SecureRandom</a>
  237.      * for a brief description of the underlying algorithm.)
  238.      * The prudent user will err on the side of caution and get extra
  239.      * seed bytes, although it should be noted that seed generation is
  240.      * somewhat costly.
  241.      *
  242.      * @param numBytes the number of seed bytes to generate.
  243.      * 
  244.      * @return the seed bytes.
  245.      */
  246.      public static byte[] getSeed(int numBytes) {
  247.      byte[] retVal = new byte[numBytes];
  248.  
  249.      for (int i=0; i<numBytes; i++)
  250.          retVal[i] = (byte) SeedGenerator.genSeed();
  251.  
  252.      return retVal;
  253.      }
  254.  
  255.  
  256.     /**
  257.      * Helper function to convert a long into a byte array (least significant
  258.      * byte first).
  259.      */
  260.     private static byte[] longToByteArray(long l) {
  261.     byte[] retVal = new byte[8];
  262.  
  263.     for (int i=0; i<8; i++) {
  264.         retVal[i] = (byte) l;
  265.         l >>= 8;
  266.     }
  267.  
  268.     return retVal;
  269.     }
  270.  
  271.     /*
  272.      * readObject is called to restore the state of the random object from
  273.      * a stream.  We have to create a new instance of MessageDigest, because
  274.      * it is not included in the stream (it is marked "transient").
  275.      *
  276.      * Note that the nextBytes() method invoked on the restored random object
  277.      * will yield the exact same (random) bytes as the original. If you do not
  278.      * want this behaviour, you should re-seed the restored random object,
  279.      * using setSeed().
  280.      */
  281.     private void readObject(java.io.ObjectInputStream s)
  282.     throws IOException, ClassNotFoundException {
  283.  
  284.         s.defaultReadObject();
  285.  
  286.         try {
  287.         digest = MessageDigest.getInstance("SHA");
  288.         } catch (NoSuchAlgorithmException e) {
  289.         throw new InternalError("internal error: SHA-1 not available");
  290.         }
  291.     }
  292. }
  293.