SecureRandom.java 13.3 KB
Newer Older
Tom Tromey committed
1
/* SecureRandom.java --- Secure Random class implementation
2 3
   Copyright (C) 1999, 2001, 2002, 2003, 2005, 2006
   Free Software Foundation, Inc.
Tom Tromey committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

package java.security;

41
import gnu.classpath.SystemProperties;
42
import gnu.java.lang.CPStringBuilder;
Tom Tromey committed
43
import gnu.java.security.Engine;
44
import gnu.java.security.action.GetSecurityPropertyAction;
45
import gnu.java.security.jce.prng.SecureRandomAdapter;
46
import gnu.java.security.jce.prng.Sha160RandomSpi;
Tom Tromey committed
47

48 49
import java.io.IOException;
import java.io.InputStream;
50
import java.lang.reflect.InvocationTargetException;
51 52
import java.net.MalformedURLException;
import java.net.URL;
Tom Tromey committed
53 54
import java.util.Enumeration;
import java.util.Random;
55 56
import java.util.logging.Level;
import java.util.logging.Logger;
Tom Tromey committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

/**
 * An interface to a cryptographically secure pseudo-random number
 * generator (PRNG). Random (or at least unguessable) numbers are used
 * in all areas of security and cryptography, from the generation of
 * keys and initialization vectors to the generation of random padding
 * bytes.
 *
 * @author Mark Benvenuto (ivymccough@worldnet.att.net)
 * @author Casey Marshall
 */
public class SecureRandom extends Random
{

  // Constants and fields.
  // ------------------------------------------------------------------------

  /** Service name for PRNGs. */
  private static final String SECURE_RANDOM = "SecureRandom";

  private static final long serialVersionUID = 4940670005562187L;

  //Serialized Field
80
  long counter = 0;             //Serialized
Tom Tromey committed
81
  Provider provider = null;
82
  byte[] randomBytes = null;    //Always null
Tom Tromey committed
83 84 85
  int randomBytesUsed = 0;
  SecureRandomSpi secureRandomSpi = null;
  byte[] state = null;
86 87 88
  private String algorithm;

  private boolean isSeeded = false;
Tom Tromey committed
89 90 91 92 93

  // Constructors.
  // ------------------------------------------------------------------------

  /**
94 95 96
     Default constructor for SecureRandom. It constructs a
     new SecureRandom by instantating the first SecureRandom
     algorithm in the default security provier.
Tom Tromey committed
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

     It is not seeded and should be seeded using setSeed or else
     on the first call to getnextBytes it will force a seed.

     It is maintained for backwards compatibility and programs
     should use {@link #getInstance(java.lang.String)}.
   */
  public SecureRandom()
  {
    Provider[] p = Security.getProviders();

    //Format of Key: SecureRandom.algname
    String key;

    String classname = null;
    int i;
    Enumeration e;
    for (i = 0; i < p.length; i++)
      {
        e = p[i].propertyNames();
        while (e.hasMoreElements())
          {
            key = (String) e.nextElement();
            if (key.startsWith("SECURERANDOM."))
              {
                if ((classname = p[i].getProperty(key)) != null)
                  {
                    try
                      {
                        secureRandomSpi = (SecureRandomSpi) Class.
                          forName(classname).newInstance();
                        provider = p[i];
129
                        algorithm = key.substring(13); // Minus SecureRandom.
Tom Tromey committed
130 131 132 133 134 135 136
                        return;
                      }
                    catch (ThreadDeath death)
                      {
                        throw death;
                      }
                    catch (Throwable t)
137 138 139
                      {
                        // Ignore.
                      }
Tom Tromey committed
140 141 142 143 144 145
                  }
              }
          }
      }

    // Nothing found. Fall back to SHA1PRNG
146
    secureRandomSpi = new Sha160RandomSpi();
147
    algorithm = "Sha160";
Tom Tromey committed
148 149 150
  }

  /**
151 152 153
     A constructor for SecureRandom. It constructs a new
     SecureRandom by instantating the first SecureRandom algorithm
     in the default security provier.
Tom Tromey committed
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169

     It is seeded with the passed function and is useful if the user
     has access to hardware random device (like a radiation detector).

     It is maintained for backwards compatibility and programs
     should use getInstance.

     @param seed Seed bytes for class
   */
  public SecureRandom(byte[] seed)
  {
    this();
    setSeed(seed);
  }

  /**
170
     A constructor for SecureRandom. It constructs a new
Tom Tromey committed
171
     SecureRandom using the specified SecureRandomSpi from
172
     the specified security provier.
Tom Tromey committed
173 174 175 176 177 178

     @param secureRandomSpi A SecureRandomSpi class
     @param provider A Provider class
   */
  protected SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider)
  {
179 180 181 182 183 184 185
    this(secureRandomSpi, provider, "unknown");
  }

  /**
   * Private constructor called from the getInstance() method.
   */
  private SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider,
186
                       String algorithm)
187
  {
Tom Tromey committed
188 189
    this.secureRandomSpi = secureRandomSpi;
    this.provider = provider;
190
    this.algorithm = algorithm;
Tom Tromey committed
191 192 193
  }

  /**
194 195
   * Returns an instance of a <code>SecureRandom</code> from the first provider
   * that implements it.
196
   *
Tom Tromey committed
197
   * @param algorithm The algorithm name.
198 199 200 201 202
   * @return A new <code>SecureRandom</code> implementing the given algorithm.
   * @throws NoSuchAlgorithmException If no installed provider implements the
   *           given algorithm.
   * @throws IllegalArgumentException if <code>algorithm</code> is
   *           <code>null</code> or is an empty string.
Tom Tromey committed
203 204
   */
  public static SecureRandom getInstance(String algorithm)
205
      throws NoSuchAlgorithmException
Tom Tromey committed
206 207
  {
    Provider[] p = Security.getProviders();
208
    NoSuchAlgorithmException lastException = null;
Tom Tromey committed
209
    for (int i = 0; i < p.length; i++)
210 211 212 213 214 215 216 217 218 219
      try
        {
          return getInstance(algorithm, p[i]);
        }
      catch (NoSuchAlgorithmException x)
        {
          lastException = x;
        }
    if (lastException != null)
      throw lastException;
Tom Tromey committed
220 221 222 223
    throw new NoSuchAlgorithmException(algorithm);
  }

  /**
224 225
   * Returns an instance of a <code>SecureRandom</code> for the specified
   * algorithm from the named provider.
226
   *
Tom Tromey committed
227
   * @param algorithm The algorithm name.
228 229 230
   * @param provider The provider name.
   * @return A new <code>SecureRandom</code> implementing the chosen
   *         algorithm.
Tom Tromey committed
231
   * @throws NoSuchAlgorithmException If the named provider does not implement
232 233 234 235 236
   *           the algorithm, or if the implementation cannot be instantiated.
   * @throws NoSuchProviderException If no provider named <code>provider</code>
   *           is currently installed.
   * @throws IllegalArgumentException if either <code>algorithm</code> or
   *           <code>provider</code> is <code>null</code> or empty.
Tom Tromey committed
237 238
   */
  public static SecureRandom getInstance(String algorithm, String provider)
239
      throws NoSuchAlgorithmException, NoSuchProviderException
Tom Tromey committed
240
  {
241 242 243 244 245
    if (provider == null)
      throw new IllegalArgumentException("provider MUST NOT be null");
    provider = provider.trim();
    if (provider.length() == 0)
      throw new IllegalArgumentException("provider MUST NOT be empty");
Tom Tromey committed
246 247 248 249 250 251 252
    Provider p = Security.getProvider(provider);
    if (p == null)
      throw new NoSuchProviderException(provider);
    return getInstance(algorithm, p);
  }

  /**
253 254
   * Returns an instance of a <code>SecureRandom</code> for the specified
   * algorithm from the given provider.
255
   *
256 257 258 259 260 261 262
   * @param algorithm The <code>SecureRandom</code> algorithm to create.
   * @param provider The provider to use.
   * @throws NoSuchAlgorithmException If the algorithm cannot be found, or if
   *           the class cannot be instantiated.
   * @throws IllegalArgumentException if either <code>algorithm</code> or
   *           <code>provider</code> is <code>null</code>, or if
   *           <code>algorithm</code> is an empty string.
Tom Tromey committed
263 264
   */
  public static SecureRandom getInstance(String algorithm, Provider provider)
265
      throws NoSuchAlgorithmException
Tom Tromey committed
266
  {
267
    CPStringBuilder sb = new CPStringBuilder("SecureRandom for algorithm [")
268 269 270
        .append(algorithm).append("] from provider[")
        .append(provider).append("] could not be created");
    Throwable cause;
Tom Tromey committed
271 272
    try
      {
273 274
        Object spi = Engine.getInstance(SECURE_RANDOM, algorithm, provider);
        return new SecureRandom((SecureRandomSpi) spi, provider, algorithm);
Tom Tromey committed
275
      }
276
    catch (InvocationTargetException x)
Tom Tromey committed
277
      {
278 279 280 281 282
        cause = x.getCause();
        if (cause instanceof NoSuchAlgorithmException)
          throw (NoSuchAlgorithmException) cause;
        if (cause == null)
          cause = x;
Tom Tromey committed
283
      }
284
    catch (ClassCastException x)
Tom Tromey committed
285
      {
286
        cause = x;
Tom Tromey committed
287
      }
288 289 290
    NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
    x.initCause(cause);
    throw x;
Tom Tromey committed
291 292 293 294 295 296 297 298 299 300 301 302 303
  }

  /**
     Returns the provider being used by the current SecureRandom class.

     @return The provider from which this SecureRandom was attained
   */
  public final Provider getProvider()
  {
    return provider;
  }

  /**
304 305 306 307 308 309 310 311 312 313 314 315
   * Returns the algorithm name used or "unknown" when the algorithm
   * used couldn't be determined (as when constructed by the protected
   * 2 argument constructor).
   *
   * @since 1.5
   */
  public String getAlgorithm()
  {
    return algorithm;
  }

  /**
316
     Seeds the SecureRandom. The class is re-seeded for each call and
Tom Tromey committed
317 318 319 320 321 322 323
     each seed builds on the previous seed so as not to weaken security.

     @param seed seed bytes to seed with
   */
  public void setSeed(byte[] seed)
  {
    secureRandomSpi.engineSetSeed(seed);
324
    isSeeded = true;
Tom Tromey committed
325 326 327
  }

  /**
328
     Seeds the SecureRandom. The class is re-seeded for each call and
Tom Tromey committed
329 330 331 332 333 334 335 336 337 338 339 340 341 342
     each seed builds on the previous seed so as not to weaken security.

     @param seed 8 seed bytes to seed with
   */
  public void setSeed(long seed)
  {
    // This particular setSeed will be called by Random.Random(), via
    // our own constructor, before secureRandomSpi is initialized.  In
    // this case we can't call a method on secureRandomSpi, and we
    // definitely don't want to throw a NullPointerException.
    // Therefore we test.
    if (secureRandomSpi != null)
      {
        byte[] tmp = { (byte) (0xff & (seed >> 56)),
343 344 345 346 347 348 349
                       (byte) (0xff & (seed >> 48)),
                       (byte) (0xff & (seed >> 40)),
                       (byte) (0xff & (seed >> 32)),
                       (byte) (0xff & (seed >> 24)),
                       (byte) (0xff & (seed >> 16)),
                       (byte) (0xff & (seed >> 8)),
                       (byte) (0xff & seed)
Tom Tromey committed
350 351
        };
        secureRandomSpi.engineSetSeed(tmp);
352
        isSeeded = true;
Tom Tromey committed
353 354 355 356 357 358 359 360 361 362 363
      }
  }

  /**
     Generates a user specified number of bytes. This function
     is the basis for all the random functions.

     @param bytes array to store generated bytes in
   */
  public void nextBytes(byte[] bytes)
  {
364 365
    if (!isSeeded)
      setSeed(getSeed(32));
Tom Tromey committed
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
    randomBytesUsed += bytes.length;
    counter++;
    secureRandomSpi.engineNextBytes(bytes);
  }

  /**
     Generates an integer containing the user specified
     number of random bits. It is right justified and padded
     with zeros.

     @param numBits number of random bits to get, 0 <= numBits <= 32;

     @return the random bits
   */
  protected final int next(int numBits)
  {
    if (numBits == 0)
      return 0;

385 386
    byte[] tmp = new byte[(numBits + 7) / 8];
    this.nextBytes(tmp);
Tom Tromey committed
387 388 389 390 391 392 393 394 395 396
    int ret = 0;
    for (int i = 0; i < tmp.length; i++)
      ret |= (tmp[i] & 0xFF) << (8 * i);

    long mask = (1L << numBits) - 1;
    return (int) (ret & mask);
  }

  /**
     Returns the given number of seed bytes. This method is
397
     maintained only for backwards capability.
Tom Tromey committed
398 399 400 401 402 403 404

     @param numBytes number of seed bytes to get

     @return an array containing the seed bytes
   */
  public static byte[] getSeed(int numBytes)
  {
405
    return SecureRandomAdapter.getSeed(numBytes);
Tom Tromey committed
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
  }

  /**
     Returns the specified number of seed bytes.

     @param numBytes number of seed bytes to get

     @return an array containing the seed bytes
   */
  public byte[] generateSeed(int numBytes)
  {
    return secureRandomSpi.engineGenerateSeed(numBytes);
  }

}