Save This Page
Home » openjdk-7 » sun.security » provider » [javadoc | source]
    1   /*
    2    * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package sun.security.provider;
   27   
   28   import java.io.IOException;
   29   import java.security.MessageDigest;
   30   import java.security.SecureRandomSpi;
   31   import java.security.NoSuchAlgorithmException;
   32   
   33   /**
   34    * <p>This class provides a crytpographically strong pseudo-random number
   35    * generator based on the SHA-1 hash algorithm.
   36    *
   37    * <p>Note that if a seed is not provided, we attempt to provide sufficient
   38    * seed bytes to completely randomize the internal state of the generator
   39    * (20 bytes).  However, our seed generation algorithm has not been thoroughly
   40    * studied or widely deployed.
   41    *
   42    * <p>Also note that when a random object is deserialized,
   43    * <a href="#engineNextBytes(byte[])">engineNextBytes</a> invoked on the
   44    * restored random object will yield the exact same (random) bytes as the
   45    * original object.  If this behaviour is not desired, the restored random
   46    * object should be seeded, using
   47    * <a href="#engineSetSeed(byte[])">engineSetSeed</a>.
   48    *
   49    * @author Benjamin Renaud
   50    * @author Josh Bloch
   51    * @author Gadi Guy
   52    */
   53   
   54   public final class SecureRandom extends SecureRandomSpi
   55   implements java.io.Serializable {
   56   
   57       private static final long serialVersionUID = 3581829991155417889L;
   58   
   59       /**
   60        * This static object will be seeded by SeedGenerator, and used
   61        * to seed future instances of SecureRandom
   62        */
   63       private static SecureRandom seeder;
   64   
   65       private static final int DIGEST_SIZE = 20;
   66       private transient MessageDigest digest;
   67       private byte[] state;
   68       private byte[] remainder;
   69       private int remCount;
   70   
   71       /**
   72        * This empty constructor automatically seeds the generator.  We attempt
   73        * to provide sufficient seed bytes to completely randomize the internal
   74        * state of the generator (20 bytes).  Note, however, that our seed
   75        * generation algorithm has not been thoroughly studied or widely deployed.
   76        *
   77        * <p>The first time this constructor is called in a given Virtual Machine,
   78        * it may take several seconds of CPU time to seed the generator, depending
   79        * on the underlying hardware.  Successive calls run quickly because they
   80        * rely on the same (internal) pseudo-random number generator for their
   81        * seed bits.
   82        */
   83       public SecureRandom() {
   84           init(null);
   85       }
   86   
   87       /**
   88        * This constructor is used to instatiate the private seeder object
   89        * with a given seed from the SeedGenerator.
   90        *
   91        * @param seed the seed.
   92        */
   93       private SecureRandom(byte seed[]) {
   94           init(seed);
   95       }
   96   
   97       /**
   98        * This call, used by the constructors, instantiates the SHA digest
   99        * and sets the seed, if given.
  100        */
  101       private void init(byte[] seed) {
  102           try {
  103               digest = MessageDigest.getInstance ("SHA");
  104           } catch (NoSuchAlgorithmException e) {
  105               throw new InternalError("internal error: SHA-1 not available.");
  106           }
  107   
  108           if (seed != null) {
  109              engineSetSeed(seed);
  110           }
  111       }
  112   
  113       /**
  114        * Returns the given number of seed bytes, computed using the seed
  115        * generation algorithm that this class uses to seed itself.  This
  116        * call may be used to seed other random number generators.  While
  117        * we attempt to return a "truly random" sequence of bytes, we do not
  118        * know exactly how random the bytes returned by this call are.  (See
  119        * the empty constructor <a href = "#SecureRandom">SecureRandom</a>
  120        * for a brief description of the underlying algorithm.)
  121        * The prudent user will err on the side of caution and get extra
  122        * seed bytes, although it should be noted that seed generation is
  123        * somewhat costly.
  124        *
  125        * @param numBytes the number of seed bytes to generate.
  126        *
  127        * @return the seed bytes.
  128        */
  129       public byte[] engineGenerateSeed(int numBytes) {
  130           byte[] b = new byte[numBytes];
  131           SeedGenerator.generateSeed(b);
  132           return b;
  133       }
  134   
  135       /**
  136        * Reseeds this random object. The given seed supplements, rather than
  137        * replaces, the existing seed. Thus, repeated calls are guaranteed
  138        * never to reduce randomness.
  139        *
  140        * @param seed the seed.
  141        */
  142       synchronized public void engineSetSeed(byte[] seed) {
  143           if (state != null) {
  144               digest.update(state);
  145               for (int i = 0; i < state.length; i++)
  146                   state[i] = 0;
  147           }
  148           state = digest.digest(seed);
  149       }
  150   
  151       private static void updateState(byte[] state, byte[] output) {
  152           int last = 1;
  153           int v = 0;
  154           byte t = 0;
  155           boolean zf = false;
  156   
  157           // state(n + 1) = (state(n) + output(n) + 1) % 2^160;
  158           for (int i = 0; i < state.length; i++) {
  159               // Add two bytes
  160               v = (int)state[i] + (int)output[i] + last;
  161               // Result is lower 8 bits
  162               t = (byte)v;
  163               // Store result. Check for state collision.
  164               zf = zf | (state[i] != t);
  165               state[i] = t;
  166               // High 8 bits are carry. Store for next iteration.
  167               last = v >> 8;
  168           }
  169   
  170           // Make sure at least one bit changes!
  171           if (!zf)
  172              state[0]++;
  173       }
  174   
  175       /**
  176        * Generates a user-specified number of random bytes.
  177        *
  178        * @param bytes the array to be filled in with random bytes.
  179        */
  180       public synchronized void engineNextBytes(byte[] result) {
  181           int index = 0;
  182           int todo;
  183           byte[] output = remainder;
  184   
  185           if (state == null) {
  186               if (seeder == null) {
  187                   seeder = new SecureRandom(SeedGenerator.getSystemEntropy());
  188                   seeder.engineSetSeed(engineGenerateSeed(DIGEST_SIZE));
  189               }
  190   
  191               byte[] seed = new byte[DIGEST_SIZE];
  192               seeder.engineNextBytes(seed);
  193               state = digest.digest(seed);
  194           }
  195   
  196           // Use remainder from last time
  197           int r = remCount;
  198           if (r > 0) {
  199               // How many bytes?
  200               todo = (result.length - index) < (DIGEST_SIZE - r) ?
  201                           (result.length - index) : (DIGEST_SIZE - r);
  202               // Copy the bytes, zero the buffer
  203               for (int i = 0; i < todo; i++) {
  204                   result[i] = output[r];
  205                   output[r++] = 0;
  206               }
  207               remCount += todo;
  208               index += todo;
  209           }
  210   
  211           // If we need more bytes, make them.
  212           while (index < result.length) {
  213               // Step the state
  214               digest.update(state);
  215               output = digest.digest();
  216               updateState(state, output);
  217   
  218               // How many bytes?
  219               todo = (result.length - index) > DIGEST_SIZE ?
  220                   DIGEST_SIZE : result.length - index;
  221               // Copy the bytes, zero the buffer
  222               for (int i = 0; i < todo; i++) {
  223                   result[index++] = output[i];
  224                   output[i] = 0;
  225               }
  226               remCount += todo;
  227           }
  228   
  229           // Store remainder for next time
  230           remainder = output;
  231           remCount %= DIGEST_SIZE;
  232       }
  233   
  234       /*
  235        * readObject is called to restore the state of the random object from
  236        * a stream.  We have to create a new instance of MessageDigest, because
  237        * it is not included in the stream (it is marked "transient").
  238        *
  239        * Note that the engineNextBytes() method invoked on the restored random
  240        * object will yield the exact same (random) bytes as the original.
  241        * If you do not want this behaviour, you should re-seed the restored
  242        * random object, using engineSetSeed().
  243        */
  244       private void readObject(java.io.ObjectInputStream s)
  245           throws IOException, ClassNotFoundException {
  246   
  247           s.defaultReadObject ();
  248   
  249           try {
  250               digest = MessageDigest.getInstance ("SHA");
  251           } catch (NoSuchAlgorithmException e) {
  252               throw new InternalError("internal error: SHA-1 not available.");
  253           }
  254       }
  255   }

Save This Page
Home » openjdk-7 » sun.security » provider » [javadoc | source]