Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4219386

SecureRandom needs a getInstance method which sets parameters

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Not an Issue
    • Icon: P4 P4
    • None
    • 1.2.0
    • security-libs

      an replaces, the existing seed. Thus, repeated calls=20
           * are guaranteed never to reduce randomness.=20
           *=20
           * <p>This method is defined for compatibility with=20
           * <code>java.util.Random</code>.
           *
           * @param seed the seed.
           */
          public void setSeed(long seed) {
      =09/*=20
      =09 * Ignore call from super constructor (as well as any other calls
      =09 * unfortunate enough to be passing 0). It's critical that we
      =09 * ignore call from superclass constructor, as digest has not
      =09 * yet been initialized at that point.
      =09 */
      =09if (seed !=3D 0)
      =09 secureRandomSpi.engineSetSeed(longToByteArray(seed));
          }

          /**
           * Generates a user-specified number of random bytes. This method is
           * used as the basis of all random entities returned by this class
           * (except seed bytes).
           *=20
           * @param bytes the array to be filled in with random bytes.
           */

          synchronized public void nextBytes(byte[] bytes) {
      =09secureRandomSpi.engineNextBytes(bytes);
          }

          /**
           * Generates an integer containing the user-specified number of
           * pseudo-random bits (right justified, with leading zeros). This
           * method overrides a <code>java.util.Random</code> method, and serves
           * to provide a source of random bits to all of the methods inherited
           * from that class (for example, <code>nextInt</code>,
           * <code>nextLong</code>, and <code>nextFloat</code>).
           *
           * @param numBits number of pseudo-random bits to be generated, where
           * 0 <=3D <code>numBits</code> <=3D 32.
           */
          final protected int next(int numBits) {
      =09int numBytes =3D (numBits+7)/8;
      =09byte b[] =3D new byte[numBytes];
      =09int next =3D 0;
      =20
      =09nextBytes(b);
      =09for (int i=3D0; i<numBytes; i++)
      =09 next =3D (next << 8) + (b[i] & 0xFF);
      =20
      =09return next >>> (numBytes*8 - numBits);
          }

          /**
           * Returns the given number of seed bytes, computed using the seed
           * generation algorithm that this class uses to seed itself. This
           * call may be used to seed other random number generators.
           *
           * <p>This method is only included for backwards compatibility.=20
           * The caller is encouraged to use one of the alternative
           * <code>getInstance</code> methods to obtain a SecureRandom object, an=
      d
           * then call the <code>generateSeed</code> method to obtain seed bytes
           * from that object.
           *
           * @param numBytes the number of seed bytes to generate.
           *=20
           * @return the seed bytes.
           */
           public static byte[] getSeed(int numBytes) {
      =09if (seedGenerator =3D=3D null)
      =09 seedGenerator =3D new SecureRandom();
      =09return seedGenerator.generateSeed(numBytes);
           }

          /**
           * Returns the given number of seed bytes, computed using the seed
           * generation algorithm that this class uses to seed itself. This
           * call may be used to seed other random number generators.
           *
           * @param numBytes the number of seed bytes to generate.
           *=20
           * @return the seed bytes.
           */
          public byte[] generateSeed(int numBytes) {
      =09return secureRandomSpi.engineGenerateSeed(numBytes);
          }

          /**
           * Helper function to convert a long into a byte array (least significa=
      nt
           * byte first).
           */
          private static byte[] longToByteArray(long l) {
      =09byte[] retVal =3D new byte[8];

      =09for (int i=3D0; i<8; i++) {
      =09 retVal[i] =3D (byte) l;
      =09 l >>=3D 8;
      =09}

      =09return retVal;
          }

          /**
           * Gets a default PRNG algorithm by looking through all registered
           * providers. Returns the first PRNG algorithm of the first provider th=
      at
           * has registered a SecureRandom implementation, or null if none of the
           * registered providers supplies a SecureRandom implementation.
           */
          private static String getPrngAlgorithm() {
      =09Provider[] provs =3D Security.getProviders();
      =09for (int i=3D0; i<provs.length; i++) {
      =09 // search the provider's properties list for a=20
      // property name
      =09 // that starts with "SecureRandom."
      =09 for (Enumeration e =3D provs[i].propertyNames();
      =09=09 e.hasMoreElements();) {
      =09=09String propName =3D (String)e.nextElement();
      =09=09if (propName.startsWith("SecureRandom.")) {
      =09=09 int index =3D propName.indexOf(".", 0);
      =09=09 return propName.substring(index+1);
      =09=09}
      =09 }
      =09}
      =09return null;
          }

          // Declare serialVersionUID to be compatible with JDK1.1
          static final long serialVersionUID =3D 4940670005562187L;

          // Retain unused values serialized from JDK1.1
          /**
           * @serial
           */
          private byte[] state;
          /**
           * @serial
           */
          private MessageDigest digest =3D null;
          /**
           * @serial
           *
           * We know that the MessageDigest class does not implement
           * java.io.Serializable. However, since this field is no longer
           * used, it will always be NULL and won't affect the serialization
           * of the SecureRandom class itself.
           */
          private byte[] randomBytes;
          /**
           * @serial
           */
          private int randomBytesUsed;
          /**
           * @serial
           */
          private long counter;
      }
      //=3D=3D=3D=3D End of file SecureRandom.


      //=3D=3D=3D=3D Beginning of file SecureRandomSpi:
      /*
       * @(#)SecureRandomSpi.java=091.2.???? 99/02/23
       *
       */
      =20
      package java.security;

      import java.security.spec.AlgorithmParameterSpec;

      /**
       * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
       * for the <code>SecureRandom</code> class.
       * All the abstract methods in this class must be implemented by each
       * service provider who wishes to supply the implementation
       * of a cryptographically strong pseudo-random number generator.
       *
       * @version 1.2.????, 99/02/23
       *
       * @see SecureRandom
       * @since JDK ???
       * This class has not yet been tested, but is a proposed modification.
       */

      public abstract class SecureRandomSpi implements java.io.Serializable {

          /**
           * Reseeds this random object. The given seed supplements, rather than
           * replaces, the existing seed. Thus, repeated calls should
           * never reduce randomness.
           *
           * @param seed the seed.
           */
          protected abstract void engineSetSeed(byte[] seed);

          /**
           * Generates a user-specified number of random bytes.
           *=20
           * @param bytes the array to be filled in with random bytes.
           */
          protected abstract void engineNextBytes(byte[] bytes);

          /**
           * Returns the given number of seed bytes. This call may be used to
           * seed other random number generators.
           *
           * @param numBytes the number of seed bytes to generate.
           *=20
           * @return the seed bytes.
           */
           protected abstract byte[] engineGenerateSeed(int numBytes);

          /**
           * Initializes this SecureRandom engine with the specified parameter se=
      t.
           *
           * This concrete method has been added to this previously-defined
           * abstract class. (For backwards compatibility, it cannot be abstract.=
      )
           * It may be overridden by a provider to set the algorithm parameters
           * using the specified <code>params</code>. Such an override
           * is expected to throw an InvalidAlgorithmParameterException if
           * a parameter is invalid.
           * If this method is not overridden, it always throws an
           * UnsupportedOperationException.
      =09*
      =09* This method is a proposed modification and has not been tested.
      =09* This method has been "copied" from a similar method in java.security.S=
      ignatureSpi
      =09* in Java JDK1.2.
           *
           * @param params the parameters
           *
           * @exception InvalidAlgorithmParameterException if the given parameter=
      s
           * are inappropriate for this SecureRandom engine
           */
          protected void engineSetParameter(AlgorithmParameterSpec params)
      =09throws InvalidAlgorithmParameterException {
      =09 throw new UnsupportedOperationException();
          }

      }
      //=3D=3D=3D=3D End of file SecureRandomSpi.
      (Review ID: 54708)
      ======================================================================


      Name: jn10789 Date: 03/11/99

      =20
      It would be useful if Java(TM) 2 class=20
      java.security.SecureRandom had a getInstance method which=20
      could conveniently set the parameters of the instance being=20
      created by the getInstance method.

      One reason for such a modified getInstance method is that=20
      many algorithms which may be suitable for an engine for a=20
      SecureRandom pseudorandom number generator (prng) have=20
      parameters which can or should be set by a user or=20
      applications programmer, since the default parameters=20
      used by the provider of an implementation of the algorithm=20
      may not be completely adequate. Two examples of such=20
      algorithms are the quadratic generator of Blum, Blum, and Shub=20
      (1986) and the discrete exponential generator of Haastad et al.=20
      (1993).


      I suggest therefore that class SecureRandom be modified to=20
      include a method with the header

      public static SecureRandom getInstance(AlgorithmParameterSpec=20
      params, String algorithm, String provider)

      and that abstract class java.security.SecureRandomSpi be=20
      modified to include a method with the header

      protected void engineSetParameter(AlgorithmParameterSpec params)


      The purpose of the method SecureRandomSpi.engineSetParameter=20
      is to make it easy to implement the proposed=20
      SecureRandom.getInstance(AlgorithmParameterSpec params,=20
      String algorithm, String provider) method.

      I encountered the need for the proposed getInstance method=20
      while designing, programming, and testing improved=20
      pseudorandom number generators.


      Sincerely,
      Charles Douglas Knechtel
      http://www.aptmath.com


      References:

      L. Blum, M. Blum, and M. Shub. 1986. A simple, unpredictable=20
      pseudo-random number generator. SIAM J. Comput. 15(3):364-383.

      Johan Haastad [H=E5stad], A. W. Schrift, and A. Shamir. 1993. =20
      The discrete logarithm modulo a composite hides O(n) bits. =20
      Journal of Computer and System Sciences [JCSS] 47(3):376-404.


      Source code from Sun Java JDK 1.2 has been modified to=20
      implement the proposed changes and is included below;=20
      however, the modifications have not yet been thoroughly tested:

      //=3D=3D=3D=3D Beginning of file SecureRandom:
      /*
       * @(#)SecureRandom.java=091.2.???? 99/02/23
       *
       */
      =20
      package java.security;

      import java.util.Enumeration;
      import java.security.spec.AlgorithmParameterSpec;

      /**
       * <p>This class is intended to provide a cryptographically=20
      strong pseudo-random number
       * generator (PRNG).
       *
       * <p>Like other algorithm-based classes in Java Security,=20
      SecureRandom=20
       * provides implementation-independent algorithms, whereby a=20
      caller=20
       * (application code) requests a particular PRNG algorithm
       * and is handed back a SecureRandom object for that algorithm.
       It is
       * also possible, if desired, to request a particular algorithm=20
      from a
       * particular provider. See the <code>getInstance</code> methods.
       *
       * <p>Thus, there are two ways to request a SecureRandom object: by
       * specifying either just an algorithm name, or both an=20
      algorithm name
       * and a package provider.
       *
       * <ul>
       *
       * <li>If just an algorithm name is specified, as in:
       * <pre>
       * SecureRandom random =3D=20
      SecureRandom.getInstance("SHA1PRNG");
       * </pre>
       * the system will determine if there is an implementation=20
      of the algorithm
       * requested available in the environment, and if there is=20
      more than one, if
       * there is a preferred one.<p>
       *=20
       * <li>If both an algorithm name and a package provider are=20
      specified, as in:
       * <pre>
       * SecureRandom random =3D=20
      SecureRandom.getInstance("SHA1PRNG", "SUN");
       * </pre>
       * the system will determine if there is an implementation of the
       * algorithm in the package requested, and throw an exception=20
      if there
       * is not.
       *
       * </ul>
       *
       * <p>The SecureRandom implementation attempts to completely
       * randomize the internal state of the generator itself unless
       * the caller follows the call to a <code>getInstance</code>=20
      method
       * with a call to the <code>setSeed</code> method:
       * <pre>
       * SecureRandom random =3D=20
      SecureRandom.getInstance("SHA1PRNG");
       * random.setSeed(seed);
       * </pre>
       *
       * <p>After the caller obtains the SecureRandom object from the
       * <code>getInstance</code> call, it can call=20
      <code>nextBytes</code>
       * to generate random bytes:
       * <pre>
       * byte bytes[] =3D new byte[20];
       * random.nextBytes(bytes);
       * </pre>
       *
       * <p>The caller may also invoke the=20
      <code>generateSeed</code> method
       * to generate a given number of seed bytes=20
      (to seed other random number
       * generators, for example):
       * <pre>
       * byte seed[] =3D random.generateSeed(20);
       * </pre>
       *
       * @see java.security.SecureRandomSpi
       * @see java.util.Random
       *=20
       */

      public class SecureRandom extends java.util.Random {

          /**
           * The provider.
           *
           * @serial
           * @since JDK 1.2
           */
          private Provider provider =3D null;
      =20
          /**
           * The provider implementation.
           *
           * @serial
           * @since JDK 1.2
           */
          private SecureRandomSpi secureRandomSpi =3D null;

          // Seed Generator
          private static SecureRandom seedGenerator =3D null;

          /**
           * <p>By using this constructor, the caller obtains a=20
      SecureRandom object
           * containing the implementation from the highest-priority=20
      installed
           * provider that has a SecureRandom implementation.
           *=20
           * <p>Note that this instance of SecureRandom has not been=20
      seeded.
           * A call to the <code>setSeed</code> method will seed the=20
      SecureRandom
           * object. If a call is not made to <code>setSeed</code>,=20
      the first call
           * to the <code>nextBytes</code> method will force the=20
      SecureRandom object
           * to seed itself.
           *
           * <p>This constructor is provided for backwards=20
      compatibility.=20
           * The caller is encouraged to use one of the alternative
           * <code>getInstance</code> methods to obtain a SecureRandom
       object.
           */
          public SecureRandom() {
      =09/*
      =09 * This call to our superclass constructor will result=20
      in a call
      =09 * to our own <code>setSeed</code> method, which will=20
      return
      =09 * immediately when it is passed zero.
      =09 */
      =09super(0);
      =09String prng =3D getPrngAlgorithm();
      =09if (prng =3D=3D null) {
      =09 // bummer, get the SUN implementation
      =09 this.secureRandomSpi =3D=20
      new sun.security.provider.SecureRandom();
      =09 this.provider =3D new sun.security.provider.Sun();
      =09} else {
      =09 try {
      =09=09SecureRandom random =3D=20
      SecureRandom.getInstance(prng);
      =09=09this.secureRandomSpi =3D random.getSecureRandomSpi();
      =09=09this.provider =3D random.getProvider();
      =09 } catch (NoSuchAlgorithmException nsae) {
      =09=09// never happens, because we made sure the=20
      // algorithm exists
      =09 }
      =09}
          }

          /**
           * <p>By using this constructor, the caller obtains a SecureRandom obje=
      ct
           * containing the implementation from the highest-priority installed
           * provider that has a SecureRandom implementation. This constructor=20
           * uses a user-provided seed in
           * preference to the self-seeding algorithm referred to in the empty
           * constructor description. It may be preferable to the empty construct=
      or
           * if the caller has access to high-quality random bytes from some phys=
      ical
           * device (for example, a radiation detector or a noisy diode).
           *=20
           * <p>This constructor is provided for backwards compatibility.=20
           * The caller is encouraged to use one of the alternative
           * <code>getInstance</code> methods to obtain a SecureRandom object, an=
      d
           * then to call the <code>setSeed</code> method to seed it.
           *=20
           * @param seed the seed.
           */
          public SecureRandom(byte seed[]) {
      =09super(0);
      =09String prng =3D getPrngAlgorithm();
      =09if (prng =3D=3D null) {
      =09 // bummer, get the SUN implementation
      =09 this.secureRandomSpi =3D new sun.security.provider.SecureRandom();
      =09 this.provider =3D new sun.security.provider.Sun();
      =09 this.secureRandomSpi.engineSetSeed(seed);
      =09} else {
      =09 try {
      =09=09SecureRandom random =3D getInstance(prng);
      =09=09this.secureRandomSpi =3D random.getSecureRandomSpi();
      =09=09this.provider =3D random.getProvider();
      =09=09this.secureRandomSpi.engineSetSeed(seed);
      =09 } catch (NoSuchAlgorithmException nsae) {
      =09=09// never happens, because we made sure the
      // algorithm exists
      =09 }
      =09}
          }

          /**
           * Creates a SecureRandom object.
           *
           * @param secureRandomSpi the SecureRandom implementation.
           * @param provider the provider.
           */
          protected SecureRandom(SecureRandomSpi secureRandomSpi,
      =09=09=09 Provider provider) {
      =09super(0);
      =09this.secureRandomSpi =3D secureRandomSpi;
      =09this.provider =3D provider;
          }

          /**
           * Generates a SecureRandom object that implements the specified
           * Pseudo Random Number Generator (PRNG) algorithm. If the default
           * provider package provides an implementation of the requested PRNG,
           * an instance of SecureRandom containing that implementation is return=
      ed.
           * If the PRNG is not available in the default=20
           * package, other packages are searched.
           *
           * <p>Note that the returned instance of SecureRandom has not been seed=
      ed.
           * A call to the <code>setSeed</code> method will seed the SecureRandom
           * object. If a call is not made to <code>setSeed</code>, the first ca=
      ll
           * to the <code>nextBytes</code> method will force the SecureRandom obj=
      ect
           * to seed itself.
           *
           * @param algorithm the name of the PRNG algorithm.
           * See Appendix A in the <a href=3D
           * "../../../guide/security/CryptoSpec.html#AppA">
           * Java Cryptography Architecture API Specification &amp; Reference </a=
      >=20
           * for information about standard PRNG algorithm names.
           *
           * @return the new SecureRandom object.
           *
           * @exception NoSuchAlgorithmException if the PRNG algorithm is
           * not available in the caller's environment.
           *
           * @since JDK1.2
           */
          public static SecureRandom getInstance(String algorithm)
      =09throws NoSuchAlgorithmException {
      =09 try {
      =09=09Object[] objs =3D Security.getImpl(algorithm,
      =09=09=09=09=09=09 "SecureRandom",
      =09=09=09=09=09=09 null);
      =09=09return new SecureRandom((SecureRandomSpi)objs[0],
      =09=09=09=09=09(Provider)objs[1]);
      =09 } catch(NoSuchProviderException e) {
      =09=09throw new NoSuchAlgorithmException(algorithm + " not found");
      =09 }
          }

          /**
           * Generates a SecureRandom object for the specified PRNG
           * algorithm, as supplied from the specified provider, if such a
           * PRNG implementation is available from the provider.
           *
           * <p>Note that the returned instance of SecureRandom has not been seed=
      ed.
           * A call to the <code>setSeed</code> method will seed the SecureRandom
           * object. If a call is not made to <code>setSeed</code>, the first ca=
      ll
           * to the <code>nextBytes</code> method will force the SecureRandom obj=
      ect
           * to seed itself.
           *
           * @param algorithm the name of the PRNG algorithm.
           * See Appendix A in the <a href=3D
           * "../../../guide/security/CryptoSpec.html#AppA">
           * Java Cryptography Architecture API Specification &amp; Reference </a=
      >=20
           * for information about standard PRNG algorithm names.
           *
           * @param provider the name of the provider.
           *
           * @return the new SecureRandom object.
           *
           * @exception NoSuchAlgorithmException if the requested PRNG
           * implementation is not available from the provider.
           *
           * @exception NoSuchProviderException if the provider has not been
           * configured.
           *
           * @see Provider
           *
           * @since JDK1.2
           */
          public static SecureRandom getInstance(String algorithm, String provide=
      r)
      =09throws NoSuchAlgorithmException, NoSuchProviderException
          {
      =09if (provider =3D=3D null || provider.length() =3D=3D 0)
      =09 throw new IllegalArgumentException("missing provider");
      =09Object[] objs =3D Security.getImpl(algorithm, "SecureRandom", provider);
      =09return new SecureRandom((SecureRandomSpi)objs[0], (Provider)objs[1]);
          }

          /**
           * Generates a SecureRandom object=20
           * parameterized by the given parameter set
           * for the specified PRNG algorithm, as supplied from the specified pro=
      vider,
           * if such a PRNG implementation is available from the provider.
           *
           * <p>Note that the returned instance of SecureRandom has not been seed=
      ed.
           * A call to the <code>setSeed</code> method will seed the SecureRandom
           * object. If a call is not made to <code>setSeed</code>, the first ca=
      ll
           * to the <code>nextBytes</code> method will force the SecureRandom obj=
      ect
           * to seed itself.
           *
           * @param algorithm the name of the PRNG algorithm.
           * See Appendix A in the <a href=3D
           * "../../../guide/security/CryptoSpec.html#AppA">
           * Java Cryptography Architecture API Specification &amp; Reference </a=
      >=20
           * for information about standard PRNG algorithm names.
           *
           * @param provider the name of the provider.
           *
           * @return the new SecureRandom object.
           *
           * @exception NoSuchAlgorithmException if the requested PRNG
           * implementation is not available from the provider.
           *
           * @exception NoSuchProviderException if the provider has not been
           * configured.
           *
           * @exception InvalidAlgorithmParameterException if the given parameter=
      s
           * are inappropriate for this SecureRandom engine.
           *
           * @see Provider
           *
           * @since JDK ???
      =09* This method has not yet been tested, but is a proposed modification.
           */
          public static SecureRandom getInstance(AlgorithmParameterSpec params, S=
      tring algorithm,
      =09=09String provider)
      =09throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorit=
      hmParameterException
          {
      =09if (provider =3D=3D null || provider.length() =3D=3D 0)
      =09 throw new IllegalArgumentException("missing provider");
      =09Object[] objs =3D Security.getImpl(algorithm, "SecureRandom", provider);
      =09((SecureRandomSpi)objs[0]).engineSetParameter(params);
      =09return new SecureRandom((SecureRandomSpi)objs[0], (Provider)objs[1]);
          }
      =20
          /**
           * Returns the SecureRandomSpi of this SecureRandom object.
           */
          SecureRandomSpi getSecureRandomSpi() {
      =09return secureRandomSpi;
          }

          /**
           * Returns the provider of this SecureRandom object.
           *
           * @return the provider of this SecureRandom object.
           */
          public final Provider getProvider() {
      =09return provider;
          }

          /**
           * Reseeds this random object. The given seed supplements, rather than
           * replaces, the existing seed. Thus, repeated calls are guaranteed
           * never to reduce randomness.
           *
           * @param seed the seed.
           */
          synchronized public void setSeed(byte[] seed) {
      =09secureRandomSpi.engineSetSeed(seed);
          }

          /**
           * Reseeds this random object, using the eight bytes contained=20
           * in the given <code>long seed</code>. The given seed supplements,=20
           * rather th

            Unassigned Unassigned
            jdn Jeffrey Nisewanger (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: