OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / security / SecureRandom.java
1 /* SecureRandom.java --- Secure Random class implementation
2    Copyright (C) 1999, 2001, 2002, 2003, 2005, 2006
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Classpath.
6
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38
39 package java.security;
40
41 import gnu.classpath.SystemProperties;
42 import gnu.java.security.Engine;
43 import gnu.java.security.action.GetSecurityPropertyAction;
44 import gnu.java.security.jce.prng.Sha160RandomSpi;
45
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.lang.reflect.InvocationTargetException;
49 import java.net.MalformedURLException;
50 import java.net.URL;
51 import java.util.Enumeration;
52 import java.util.Random;
53 import java.util.logging.Level;
54 import java.util.logging.Logger;
55
56 /**
57  * An interface to a cryptographically secure pseudo-random number
58  * generator (PRNG). Random (or at least unguessable) numbers are used
59  * in all areas of security and cryptography, from the generation of
60  * keys and initialization vectors to the generation of random padding
61  * bytes.
62  *
63  * @author Mark Benvenuto (ivymccough@worldnet.att.net)
64  * @author Casey Marshall
65  */
66 public class SecureRandom extends Random
67 {
68
69   // Constants and fields.
70   // ------------------------------------------------------------------------
71
72   /** Service name for PRNGs. */
73   private static final String SECURE_RANDOM = "SecureRandom";
74
75   private static final long serialVersionUID = 4940670005562187L;
76
77   //Serialized Field
78   long counter = 0;             //Serialized
79   Provider provider = null;
80   byte[] randomBytes = null;    //Always null
81   int randomBytesUsed = 0;
82   SecureRandomSpi secureRandomSpi = null;
83   byte[] state = null;
84   private String algorithm;
85
86   private boolean isSeeded = false;
87
88   // Constructors.
89   // ------------------------------------------------------------------------
90
91   /**
92      Default constructor for SecureRandom. It constructs a 
93      new SecureRandom by instantating the first SecureRandom 
94      algorithm in the default security provier. 
95
96      It is not seeded and should be seeded using setSeed or else
97      on the first call to getnextBytes it will force a seed.
98
99      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 }