001    /* SecureRandom.java --- Secure Random class implementation
002       Copyright (C) 1999, 2001, 2002, 2003, 2005, 2006
003       Free Software Foundation, Inc.
004    
005    This file is part of GNU Classpath.
006    
007    GNU Classpath is free software; you can redistribute it and/or modify
008    it under the terms of the GNU General Public License as published by
009    the Free Software Foundation; either version 2, or (at your option)
010    any later version.
011    
012    GNU Classpath is distributed in the hope that it will be useful, but
013    WITHOUT ANY WARRANTY; without even the implied warranty of
014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015    General Public License for more details.
016    
017    You should have received a copy of the GNU General Public License
018    along with GNU Classpath; see the file COPYING.  If not, write to the
019    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
020    02110-1301 USA.
021    
022    Linking this library statically or dynamically with other modules is
023    making a combined work based on this library.  Thus, the terms and
024    conditions of the GNU General Public License cover the whole
025    combination.
026    
027    As a special exception, the copyright holders of this library give you
028    permission to link this library with independent modules to produce an
029    executable, regardless of the license terms of these independent
030    modules, and to copy and distribute the resulting executable under
031    terms of your choice, provided that you also meet, for each linked
032    independent module, the terms and conditions of the license of that
033    module.  An independent module is a module which is not derived from
034    or based on this library.  If you modify this library, you may extend
035    this exception to your version of the library, but you are not
036    obligated to do so.  If you do not wish to do so, delete this
037    exception statement from your version. */
038    
039    package java.security;
040    
041    import gnu.classpath.SystemProperties;
042    import gnu.java.security.Engine;
043    import gnu.java.security.action.GetSecurityPropertyAction;
044    import gnu.java.security.jce.prng.Sha160RandomSpi;
045    
046    import java.io.IOException;
047    import java.io.InputStream;
048    import java.lang.reflect.InvocationTargetException;
049    import java.net.MalformedURLException;
050    import java.net.URL;
051    import java.util.Enumeration;
052    import java.util.Random;
053    import java.util.logging.Level;
054    import java.util.logging.Logger;
055    
056    /**
057     * An interface to a cryptographically secure pseudo-random number
058     * generator (PRNG). Random (or at least unguessable) numbers are used
059     * in all areas of security and cryptography, from the generation of
060     * keys and initialization vectors to the generation of random padding
061     * bytes.
062     *
063     * @author Mark Benvenuto (ivymccough@worldnet.att.net)
064     * @author Casey Marshall
065     */
066    public class SecureRandom extends Random
067    {
068    
069      // Constants and fields.
070      // ------------------------------------------------------------------------
071    
072      /** Service name for PRNGs. */
073      private static final String SECURE_RANDOM = "SecureRandom";
074    
075      private static final long serialVersionUID = 4940670005562187L;
076    
077      //Serialized Field
078      long counter = 0;             //Serialized
079      Provider provider = null;
080      byte[] randomBytes = null;    //Always null
081      int randomBytesUsed = 0;
082      SecureRandomSpi secureRandomSpi = null;
083      byte[] state = null;
084      private String algorithm;
085    
086      private boolean isSeeded = false;
087    
088      // Constructors.
089      // ------------------------------------------------------------------------
090    
091      /**
092         Default constructor for SecureRandom. It constructs a 
093         new SecureRandom by instantating the first SecureRandom 
094         algorithm in the default security provier. 
095    
096         It is not seeded and should be seeded using setSeed or else
097         on the first call to getnextBytes it will force a seed.
098    
099         It is maintained for backwards compatibility and programs
100         should use {@link #getInstance(java.lang.String)}.
101       */
102      public SecureRandom()
103      {
104        Provider[] p = Security.getProviders();
105    
106        //Format of Key: SecureRandom.algname
107        String key;
108    
109        String classname = null;
110        int i;
111        Enumeration e;
112        for (i = 0; i < p.length; i++)
113          {
114            e = p[i].propertyNames();
115            while (e.hasMoreElements())
116              {
117                key = (String) e.nextElement();
118                if (key.startsWith("SECURERANDOM."))
119                  {
120                    if ((classname = p[i].getProperty(key)) != null)
121                      {
122                        try
123                          {
124                            secureRandomSpi = (SecureRandomSpi) Class.
125                              forName(classname).newInstance();
126                            provider = p[i];
127                            algorithm = key.substring(13); // Minus SecureRandom.
128                            return;
129                          }
130                        catch (ThreadDeath death)
131                          {
132                            throw death;
133                          }
134                        catch (Throwable t)
135                          {
136                            // Ignore.
137                          }
138                      }
139                  }
140              }
141          }
142    
143        // Nothing found. Fall back to SHA1PRNG
144        secureRandomSpi = new Sha160RandomSpi();
145        algorithm = "Sha160";
146      }
147    
148      /**
149         A constructor for SecureRandom. It constructs a new 
150         SecureRandom by instantating the first SecureRandom algorithm 
151         in the default security provier. 
152    
153         It is seeded with the passed function and is useful if the user
154         has access to hardware random device (like a radiation detector).
155    
156         It is maintained for backwards compatibility and programs
157         should use getInstance.
158    
159         @param seed Seed bytes for class
160       */
161      public SecureRandom(byte[] seed)
162      {
163        this();
164        setSeed(seed);
165      }
166    
167      /**
168         A constructor for SecureRandom. It constructs a new 
169         SecureRandom using the specified SecureRandomSpi from
170         the specified security provier. 
171    
172         @param secureRandomSpi A SecureRandomSpi class
173         @param provider A Provider class
174       */
175      protected SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider)
176      {
177        this(secureRandomSpi, provider, "unknown");
178      }
179    
180      /**
181       * Private constructor called from the getInstance() method.
182       */
183      private SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider,
184                           String algorithm)
185      {
186        this.secureRandomSpi = secureRandomSpi;
187        this.provider = provider;
188        this.algorithm = algorithm;
189      }
190    
191      /**
192       * Returns an instance of a <code>SecureRandom</code> from the first provider
193       * that implements it.
194       * 
195       * @param algorithm The algorithm name.
196       * @return A new <code>SecureRandom</code> implementing the given algorithm.
197       * @throws NoSuchAlgorithmException If no installed provider implements the
198       *           given algorithm.
199       * @throws IllegalArgumentException if <code>algorithm</code> is
200       *           <code>null</code> or is an empty string.
201       */
202      public static SecureRandom getInstance(String algorithm)
203          throws NoSuchAlgorithmException
204      {
205        Provider[] p = Security.getProviders();
206        NoSuchAlgorithmException lastException = null;
207        for (int i = 0; i < p.length; i++)
208          try
209            {
210              return getInstance(algorithm, p[i]);
211            }
212          catch (NoSuchAlgorithmException x)
213            {
214              lastException = x;
215            }
216        if (lastException != null)
217          throw lastException;
218        throw new NoSuchAlgorithmException(algorithm);
219      }
220    
221      /**
222       * Returns an instance of a <code>SecureRandom</code> for the specified
223       * algorithm from the named provider.
224       * 
225       * @param algorithm The algorithm name.
226       * @param provider The provider name.
227       * @return A new <code>SecureRandom</code> implementing the chosen
228       *         algorithm.
229       * @throws NoSuchAlgorithmException If the named provider does not implement
230       *           the algorithm, or if the implementation cannot be instantiated.
231       * @throws NoSuchProviderException If no provider named <code>provider</code>
232       *           is currently installed.
233       * @throws IllegalArgumentException if either <code>algorithm</code> or
234       *           <code>provider</code> is <code>null</code> or empty.
235       */
236      public static SecureRandom getInstance(String algorithm, String provider)
237          throws NoSuchAlgorithmException, NoSuchProviderException
238      {
239        if (provider == null)
240          throw new IllegalArgumentException("provider MUST NOT be null");
241        provider = provider.trim();
242        if (provider.length() == 0)
243          throw new IllegalArgumentException("provider MUST NOT be empty");
244        Provider p = Security.getProvider(provider);
245        if (p == null)
246          throw new NoSuchProviderException(provider);
247        return getInstance(algorithm, p);
248      }
249    
250      /**
251       * Returns an instance of a <code>SecureRandom</code> for the specified
252       * algorithm from the given provider.
253       * 
254       * @param algorithm The <code>SecureRandom</code> algorithm to create.
255       * @param provider The provider to use.
256       * @throws NoSuchAlgorithmException If the algorithm cannot be found, or if
257       *           the class cannot be instantiated.
258       * @throws IllegalArgumentException if either <code>algorithm</code> or
259       *           <code>provider</code> is <code>null</code>, or if
260       *           <code>algorithm</code> is an empty string.
261       */
262      public static SecureRandom getInstance(String algorithm, Provider provider)
263          throws NoSuchAlgorithmException
264      {
265        StringBuilder sb = new StringBuilder("SecureRandom for algorithm [")
266            .append(algorithm).append("] from provider[")
267            .append(provider).append("] could not be created");
268        Throwable cause;
269        try
270          {
271            Object spi = Engine.getInstance(SECURE_RANDOM, algorithm, provider);
272            return new SecureRandom((SecureRandomSpi) spi, provider, algorithm);
273          }
274        catch (InvocationTargetException x)
275          {
276            cause = x.getCause();
277            if (cause instanceof NoSuchAlgorithmException)
278              throw (NoSuchAlgorithmException) cause;
279            if (cause == null)
280              cause = x;
281          }
282        catch (ClassCastException x)
283          {
284            cause = x;
285          }
286        NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
287        x.initCause(cause);
288        throw x;
289      }
290    
291      /**
292         Returns the provider being used by the current SecureRandom class.
293    
294         @return The provider from which this SecureRandom was attained
295       */
296      public final Provider getProvider()
297      {
298        return provider;
299      }
300    
301      /**
302       * Returns the algorithm name used or "unknown" when the algorithm
303       * used couldn't be determined (as when constructed by the protected
304       * 2 argument constructor).
305       *
306       * @since 1.5
307       */
308      public String getAlgorithm()
309      {
310        return algorithm;
311      }
312    
313      /**
314         Seeds the SecureRandom. The class is re-seeded for each call and 
315         each seed builds on the previous seed so as not to weaken security.
316    
317         @param seed seed bytes to seed with
318       */
319      public void setSeed(byte[] seed)
320      {
321        secureRandomSpi.engineSetSeed(seed);
322        isSeeded = true;
323      }
324    
325      /**
326         Seeds the SecureRandom. The class is re-seeded for each call and 
327         each seed builds on the previous seed so as not to weaken security.
328    
329         @param seed 8 seed bytes to seed with
330       */
331      public void setSeed(long seed)
332      {
333        // This particular setSeed will be called by Random.Random(), via
334        // our own constructor, before secureRandomSpi is initialized.  In
335        // this case we can't call a method on secureRandomSpi, and we
336        // definitely don't want to throw a NullPointerException.
337        // Therefore we test.
338        if (secureRandomSpi != null)
339          {
340            byte[] tmp = { (byte) (0xff & (seed >> 56)),
341                           (byte) (0xff & (seed >> 48)),
342                           (byte) (0xff & (seed >> 40)),
343                           (byte) (0xff & (seed >> 32)),
344                           (byte) (0xff & (seed >> 24)),
345                           (byte) (0xff & (seed >> 16)),
346                           (byte) (0xff & (seed >> 8)),
347                           (byte) (0xff & seed)
348            };
349            secureRandomSpi.engineSetSeed(tmp);
350            isSeeded = true;
351          }
352      }
353    
354      /**
355         Generates a user specified number of bytes. This function
356         is the basis for all the random functions.
357    
358         @param bytes array to store generated bytes in
359       */
360      public void nextBytes(byte[] bytes)
361      {
362        if (!isSeeded)
363          setSeed(getSeed(32));
364        randomBytesUsed += bytes.length;
365        counter++;
366        secureRandomSpi.engineNextBytes(bytes);
367      }
368    
369      /**
370         Generates an integer containing the user specified
371         number of random bits. It is right justified and padded
372         with zeros.
373    
374         @param numBits number of random bits to get, 0 <= numBits <= 32;
375    
376         @return the random bits
377       */
378      protected final int next(int numBits)
379      {
380        if (numBits == 0)
381          return 0;
382    
383        byte[] tmp = new byte[(numBits + 7) / 8];
384        this.nextBytes(tmp);
385        int ret = 0;
386        for (int i = 0; i < tmp.length; i++)
387          ret |= (tmp[i] & 0xFF) << (8 * i);
388    
389        long mask = (1L << numBits) - 1;
390        return (int) (ret & mask);
391      }
392    
393      /**
394         Returns the given number of seed bytes. This method is
395         maintained only for backwards capability. 
396    
397         @param numBytes number of seed bytes to get
398    
399         @return an array containing the seed bytes
400       */
401      public static byte[] getSeed(int numBytes)
402      {
403        byte[] tmp = new byte[numBytes];
404        generateSeed(tmp);
405        return tmp;
406      }
407    
408      /**
409         Returns the specified number of seed bytes.
410    
411         @param numBytes number of seed bytes to get
412    
413         @return an array containing the seed bytes
414       */
415      public byte[] generateSeed(int numBytes)
416      {
417        return secureRandomSpi.engineGenerateSeed(numBytes);
418      }
419    
420      // Seed methods.
421    
422      private static final String SECURERANDOM_SOURCE = "securerandom.source";
423      private static final String JAVA_SECURITY_EGD = "java.security.egd";
424      private static final Logger logger = Logger.getLogger(SecureRandom.class.getName());
425    
426      private static int generateSeed(byte[] buffer)
427      {
428        return generateSeed(buffer, 0, buffer.length);
429      }
430    
431      private static int generateSeed(byte[] buffer, int offset, int length)
432      {
433        URL sourceUrl = null;
434        String urlStr = null;
435    
436        GetSecurityPropertyAction action = new GetSecurityPropertyAction(SECURERANDOM_SOURCE);
437        try
438          {
439            urlStr = (String) AccessController.doPrivileged(action);
440            if (urlStr != null)
441              sourceUrl = new URL(urlStr);
442          }
443        catch (MalformedURLException ignored)
444          {
445            logger.log(Level.WARNING, SECURERANDOM_SOURCE + " property is malformed: {0}", 
446                       urlStr);
447          }
448    
449        if (sourceUrl == null)
450          {
451            try
452              {
453                urlStr = SystemProperties.getProperty(JAVA_SECURITY_EGD);
454                if (urlStr != null)
455                  sourceUrl = new URL(urlStr);
456              }
457            catch (MalformedURLException mue)
458              {
459                logger.log(Level.WARNING, JAVA_SECURITY_EGD + " property is malformed: {0}",
460                           urlStr);
461              }
462          }
463    
464        if (sourceUrl != null)
465          {
466            try
467              {
468                InputStream in = sourceUrl.openStream();
469                return in.read(buffer, offset, length);
470              }
471            catch (IOException ioe)
472              {
473                logger.log(Level.FINE, "error reading random bytes", ioe);
474              }
475          }
476    
477        // If we get here, we did not get any seed from a property URL.
478        return VMSecureRandom.generateSeed(buffer, offset, length);
479      }
480    }