Frames | No Frames |
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.net.MalformedURLException; 49: import java.net.URL; 50: import java.util.Enumeration; 51: import java.util.Random; 52: import java.util.logging.Level; 53: import java.util.logging.Logger; 54: 55: /** 56: * An interface to a cryptographically secure pseudo-random number 57: * generator (PRNG). Random (or at least unguessable) numbers are used 58: * in all areas of security and cryptography, from the generation of 59: * keys and initialization vectors to the generation of random padding 60: * bytes. 61: * 62: * @author Mark Benvenuto (ivymccough@worldnet.att.net) 63: * @author Casey Marshall 64: */ 65: public class SecureRandom extends Random 66: { 67: 68: // Constants and fields. 69: // ------------------------------------------------------------------------ 70: 71: /** Service name for PRNGs. */ 72: private static final String SECURE_RANDOM = "SecureRandom"; 73: 74: private static final long serialVersionUID = 4940670005562187L; 75: 76: //Serialized Field 77: long counter = 0; //Serialized 78: Provider provider = null; 79: byte[] randomBytes = null; //Always null 80: int randomBytesUsed = 0; 81: SecureRandomSpi secureRandomSpi = null; 82: byte[] state = null; 83: private String algorithm; 84: 85: private boolean isSeeded = false; 86: 87: // Constructors. 88: // ------------------------------------------------------------------------ 89: 90: /** 91: Default constructor for SecureRandom. It constructs a 92: new SecureRandom by instantating the first SecureRandom 93: algorithm in the default security provier. 94: 95: It is not seeded and should be seeded using setSeed or else 96: on the first call to getnextBytes it will force a seed. 97: 98: It is maintained for backwards compatibility and programs 99: should use {@link #getInstance(java.lang.String)}. 100: */ 101: public SecureRandom() 102: { 103: Provider[] p = Security.getProviders(); 104: 105: //Format of Key: SecureRandom.algname 106: String key; 107: 108: String classname = null; 109: int i; 110: Enumeration e; 111: for (i = 0; i < p.length; i++) 112: { 113: e = p[i].propertyNames(); 114: while (e.hasMoreElements()) 115: { 116: key = (String) e.nextElement(); 117: if (key.startsWith("SECURERANDOM.")) 118: { 119: if ((classname = p[i].getProperty(key)) != null) 120: { 121: try 122: { 123: secureRandomSpi = (SecureRandomSpi) Class. 124: forName(classname).newInstance(); 125: provider = p[i]; 126: algorithm = key.substring(13); // Minus SecureRandom. 127: return; 128: } 129: catch (ThreadDeath death) 130: { 131: throw death; 132: } 133: catch (Throwable t) 134: { 135: // Ignore. 136: } 137: } 138: } 139: } 140: } 141: 142: // Nothing found. Fall back to SHA1PRNG 143: secureRandomSpi = new Sha160RandomSpi(); 144: algorithm = "Sha160"; 145: } 146: 147: /** 148: A constructor for SecureRandom. It constructs a new 149: SecureRandom by instantating the first SecureRandom algorithm 150: in the default security provier. 151: 152: It is seeded with the passed function and is useful if the user 153: has access to hardware random device (like a radiation detector). 154: 155: It is maintained for backwards compatibility and programs 156: should use getInstance. 157: 158: @param seed Seed bytes for class 159: */ 160: public SecureRandom(byte[] seed) 161: { 162: this(); 163: setSeed(seed); 164: } 165: 166: /** 167: A constructor for SecureRandom. It constructs a new 168: SecureRandom using the specified SecureRandomSpi from 169: the specified security provier. 170: 171: @param secureRandomSpi A SecureRandomSpi class 172: @param provider A Provider class 173: */ 174: protected SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider) 175: { 176: this(secureRandomSpi, provider, "unknown"); 177: } 178: 179: /** 180: * Private constructor called from the getInstance() method. 181: */ 182: private SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider, 183: String algorithm) 184: { 185: this.secureRandomSpi = secureRandomSpi; 186: this.provider = provider; 187: this.algorithm = algorithm; 188: } 189: 190: // Class methods. 191: // ------------------------------------------------------------------------ 192: 193: /** 194: * Returns an instance of a SecureRandom. It creates the class from 195: * the first provider that implements it. 196: * 197: * @param algorithm The algorithm name. 198: * @return A new SecureRandom implementing the given algorithm. 199: * @throws NoSuchAlgorithmException If no installed provider implements 200: * the given algorithm. 201: */ 202: public static SecureRandom getInstance(String algorithm) 203: throws NoSuchAlgorithmException 204: { 205: Provider[] p = Security.getProviders(); 206: 207: for (int i = 0; i < p.length; i++) 208: { 209: try 210: { 211: return getInstance(algorithm, p[i]); 212: } 213: catch (NoSuchAlgorithmException e) 214: { 215: // Ignore. 216: } 217: } 218: 219: // None found. 220: throw new NoSuchAlgorithmException(algorithm); 221: } 222: 223: /** 224: * Returns an instance of a SecureRandom. It creates the class 225: * for the specified algorithm from the named provider. 226: * 227: * @param algorithm The algorithm name. 228: * @param provider The provider name. 229: * @return A new SecureRandom implementing the chosen algorithm. 230: * @throws NoSuchAlgorithmException If the named provider does not implement 231: * the algorithm, or if the implementation cannot be 232: * instantiated. 233: * @throws NoSuchProviderException If no provider named 234: * <code>provider</code> is currently installed. 235: * @throws IllegalArgumentException If <code>provider</code> is null 236: * or is empty. 237: */ 238: public static SecureRandom getInstance(String algorithm, String provider) 239: throws NoSuchAlgorithmException, NoSuchProviderException 240: { 241: if (provider == null || provider.length() == 0) 242: throw new IllegalArgumentException("Illegal provider"); 243: 244: Provider p = Security.getProvider(provider); 245: if (p == null) 246: throw new NoSuchProviderException(provider); 247: 248: return getInstance(algorithm, p); 249: } 250: 251: /** 252: * Returns an instance of a SecureRandom. It creates the class for 253: * the specified algorithm from the given provider. 254: * 255: * @param algorithm The SecureRandom algorithm to create. 256: * @param provider The provider to get the instance from. 257: * @throws NoSuchAlgorithmException If the algorithm cannot be found, or 258: * if the class cannot be instantiated. 259: * @throws IllegalArgumentException If <code>provider</code> is null. 260: */ 261: public static SecureRandom getInstance(String algorithm, Provider provider) 262: throws NoSuchAlgorithmException 263: { 264: if (provider == null) 265: throw new IllegalArgumentException("Illegal provider"); 266: try 267: { 268: return new SecureRandom((SecureRandomSpi) 269: Engine.getInstance(SECURE_RANDOM, algorithm, provider), 270: provider, algorithm); 271: } 272: catch (java.lang.reflect.InvocationTargetException ite) 273: { 274: throw new NoSuchAlgorithmException(algorithm); 275: } 276: catch (ClassCastException cce) 277: { 278: throw new NoSuchAlgorithmException(algorithm); 279: } 280: } 281: 282: // Instance methods. 283: // ------------------------------------------------------------------------ 284: 285: /** 286: Returns the provider being used by the current SecureRandom class. 287: 288: @return The provider from which this SecureRandom was attained 289: */ 290: public final Provider getProvider() 291: { 292: return provider; 293: } 294: 295: /** 296: * Returns the algorithm name used or "unknown" when the algorithm 297: * used couldn't be determined (as when constructed by the protected 298: * 2 argument constructor). 299: * 300: * @since 1.5 301: */ 302: public String getAlgorithm() 303: { 304: return algorithm; 305: } 306: 307: /** 308: Seeds the SecureRandom. The class is re-seeded for each call and 309: each seed builds on the previous seed so as not to weaken security. 310: 311: @param seed seed bytes to seed with 312: */ 313: public void setSeed(byte[] seed) 314: { 315: secureRandomSpi.engineSetSeed(seed); 316: isSeeded = true; 317: } 318: 319: /** 320: Seeds the SecureRandom. The class is re-seeded for each call and 321: each seed builds on the previous seed so as not to weaken security. 322: 323: @param seed 8 seed bytes to seed with 324: */ 325: public void setSeed(long seed) 326: { 327: // This particular setSeed will be called by Random.Random(), via 328: // our own constructor, before secureRandomSpi is initialized. In 329: // this case we can't call a method on secureRandomSpi, and we 330: // definitely don't want to throw a NullPointerException. 331: // Therefore we test. 332: if (secureRandomSpi != null) 333: { 334: byte[] tmp = { (byte) (0xff & (seed >> 56)), 335: (byte) (0xff & (seed >> 48)), 336: (byte) (0xff & (seed >> 40)), 337: (byte) (0xff & (seed >> 32)), 338: (byte) (0xff & (seed >> 24)), 339: (byte) (0xff & (seed >> 16)), 340: (byte) (0xff & (seed >> 8)), 341: (byte) (0xff & seed) 342: }; 343: secureRandomSpi.engineSetSeed(tmp); 344: isSeeded = true; 345: } 346: } 347: 348: /** 349: Generates a user specified number of bytes. This function 350: is the basis for all the random functions. 351: 352: @param bytes array to store generated bytes in 353: */ 354: public void nextBytes(byte[] bytes) 355: { 356: if (!isSeeded) 357: setSeed(getSeed(32)); 358: randomBytesUsed += bytes.length; 359: counter++; 360: secureRandomSpi.engineNextBytes(bytes); 361: } 362: 363: /** 364: Generates an integer containing the user specified 365: number of random bits. It is right justified and padded 366: with zeros. 367: 368: @param numBits number of random bits to get, 0 <= numBits <= 32; 369: 370: @return the random bits 371: */ 372: protected final int next(int numBits) 373: { 374: if (numBits == 0) 375: return 0; 376: 377: byte[] tmp = new byte[(numBits + 7) / 8]; 378: this.nextBytes(tmp); 379: int ret = 0; 380: for (int i = 0; i < tmp.length; i++) 381: ret |= (tmp[i] & 0xFF) << (8 * i); 382: 383: long mask = (1L << numBits) - 1; 384: return (int) (ret & mask); 385: } 386: 387: /** 388: Returns the given number of seed bytes. This method is 389: maintained only for backwards capability. 390: 391: @param numBytes number of seed bytes to get 392: 393: @return an array containing the seed bytes 394: */ 395: public static byte[] getSeed(int numBytes) 396: { 397: byte[] tmp = new byte[numBytes]; 398: generateSeed(tmp); 399: return tmp; 400: } 401: 402: /** 403: Returns the specified number of seed bytes. 404: 405: @param numBytes number of seed bytes to get 406: 407: @return an array containing the seed bytes 408: */ 409: public byte[] generateSeed(int numBytes) 410: { 411: return secureRandomSpi.engineGenerateSeed(numBytes); 412: } 413: 414: // Seed methods. 415: 416: private static final String SECURERANDOM_SOURCE = "securerandom.source"; 417: private static final String JAVA_SECURITY_EGD = "java.security.egd"; 418: private static final Logger logger = Logger.getLogger(SecureRandom.class.getName()); 419: 420: private static int generateSeed(byte[] buffer) 421: { 422: return generateSeed(buffer, 0, buffer.length); 423: } 424: 425: private static int generateSeed(byte[] buffer, int offset, int length) 426: { 427: URL sourceUrl = null; 428: String urlStr = null; 429: 430: GetSecurityPropertyAction action = new GetSecurityPropertyAction(SECURERANDOM_SOURCE); 431: try 432: { 433: urlStr = (String) AccessController.doPrivileged(action); 434: if (urlStr != null) 435: sourceUrl = new URL(urlStr); 436: } 437: catch (MalformedURLException ignored) 438: { 439: logger.log(Level.WARNING, SECURERANDOM_SOURCE + " property is malformed: {0}", 440: urlStr); 441: } 442: 443: if (sourceUrl == null) 444: { 445: try 446: { 447: urlStr = SystemProperties.getProperty(JAVA_SECURITY_EGD); 448: if (urlStr != null) 449: sourceUrl = new URL(urlStr); 450: } 451: catch (MalformedURLException mue) 452: { 453: logger.log(Level.WARNING, JAVA_SECURITY_EGD + " property is malformed: {0}", 454: urlStr); 455: } 456: } 457: 458: if (sourceUrl != null) 459: { 460: try 461: { 462: InputStream in = sourceUrl.openStream(); 463: return in.read(buffer, offset, length); 464: } 465: catch (IOException ioe) 466: { 467: logger.log(Level.FINE, "error reading random bytes", ioe); 468: } 469: } 470: 471: // If we get here, we did not get any seed from a property URL. 472: return VMSecureRandom.generateSeed(buffer, offset, length); 473: } 474: }