GNU Classpath (0.95) | |
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.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: }
GNU Classpath (0.95) |