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 }