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 }