1 /* 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.crypto; 27 28 import java.util; 29 30 import java.security; 31 import java.security.Provider.Service; 32 import java.security.spec; 33 34 import sun.security.jca; 35 import sun.security.jca.GetInstance.Instance; 36 37 /** 38 * This class provides the functionality of a secret (symmetric) key generator. 39 * 40 * <p>Key generators are constructed using one of the <code>getInstance</code> 41 * class methods of this class. 42 * 43 * <p>KeyGenerator objects are reusable, i.e., after a key has been 44 * generated, the same KeyGenerator object can be re-used to generate further 45 * keys. 46 * 47 * <p>There are two ways to generate a key: in an algorithm-independent 48 * manner, and in an algorithm-specific manner. 49 * The only difference between the two is the initialization of the object: 50 * 51 * <ul> 52 * <li><b>Algorithm-Independent Initialization</b> 53 * <p>All key generators share the concepts of a <i>keysize</i> and a 54 * <i>source of randomness</i>. 55 * There is an 56 * {@link #init(int, java.security.SecureRandom) init} 57 * method in this KeyGenerator class that takes these two universally 58 * shared types of arguments. There is also one that takes just a 59 * <code>keysize</code> argument, and uses the SecureRandom implementation 60 * of the highest-priority installed provider as the source of randomness 61 * (or a system-provided source of randomness if none of the installed 62 * providers supply a SecureRandom implementation), and one that takes just a 63 * source of randomness. 64 * 65 * <p>Since no other parameters are specified when you call the above 66 * algorithm-independent <code>init</code> methods, it is up to the 67 * provider what to do about the algorithm-specific parameters (if any) to be 68 * associated with each of the keys. 69 * <p> 70 * 71 * <li><b>Algorithm-Specific Initialization</b> 72 * <p>For situations where a set of algorithm-specific parameters already 73 * exists, there are two 74 * {@link #init(java.security.spec.AlgorithmParameterSpec) init} 75 * methods that have an <code>AlgorithmParameterSpec</code> 76 * argument. One also has a <code>SecureRandom</code> argument, while the 77 * other uses the SecureRandom implementation 78 * of the highest-priority installed provider as the source of randomness 79 * (or a system-provided source of randomness if none of the installed 80 * providers supply a SecureRandom implementation). 81 * </ul> 82 * 83 * <p>In case the client does not explicitly initialize the KeyGenerator 84 * (via a call to an <code>init</code> method), each provider must 85 * supply (and document) a default initialization. 86 * 87 * <p> Every implementation of the Java platform is required to support the 88 * following standard <code>KeyGenerator</code> algorithms with the keysizes in 89 * parentheses: 90 * <ul> 91 * <li><tt>AES</tt> (128)</li> 92 * <li><tt>DES</tt> (56)</li> 93 * <li><tt>DESede</tt> (168)</li> 94 * <li><tt>HmacSHA1</tt></li> 95 * <li><tt>HmacSHA256</tt></li> 96 * </ul> 97 * These algorithms are described in the <a href= 98 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator"> 99 * KeyGenerator section</a> of the 100 * Java Cryptography Architecture Standard Algorithm Name Documentation. 101 * Consult the release documentation for your implementation to see if any 102 * other algorithms are supported. 103 * 104 * @author Jan Luehe 105 * 106 * @see SecretKey 107 * @since 1.4 108 */ 109 110 public class KeyGenerator { 111 112 // see java.security.KeyPairGenerator for failover notes 113 114 private final static int I_NONE = 1; 115 private final static int I_RANDOM = 2; 116 private final static int I_PARAMS = 3; 117 private final static int I_SIZE = 4; 118 119 // The provider 120 private Provider provider; 121 122 // The provider implementation (delegate) 123 private volatile KeyGeneratorSpi spi; 124 125 // The algorithm 126 private final String algorithm; 127 128 private final Object lock = new Object(); 129 130 private Iterator serviceIterator; 131 132 private int initType; 133 private int initKeySize; 134 private AlgorithmParameterSpec initParams; 135 private SecureRandom initRandom; 136 137 /** 138 * Creates a KeyGenerator object. 139 * 140 * @param keyGenSpi the delegate 141 * @param provider the provider 142 * @param algorithm the algorithm 143 */ 144 protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider, 145 String algorithm) { 146 this.spi = keyGenSpi; 147 this.provider = provider; 148 this.algorithm = algorithm; 149 } 150 151 private KeyGenerator(String algorithm) throws NoSuchAlgorithmException { 152 this.algorithm = algorithm; 153 List list = GetInstance.getServices("KeyGenerator", algorithm); 154 serviceIterator = list.iterator(); 155 initType = I_NONE; 156 // fetch and instantiate initial spi 157 if (nextSpi(null, false) == null) { 158 throw new NoSuchAlgorithmException 159 (algorithm + " KeyGenerator not available"); 160 } 161 } 162 163 /** 164 * Returns the algorithm name of this <code>KeyGenerator</code> object. 165 * 166 * <p>This is the same name that was specified in one of the 167 * <code>getInstance</code> calls that created this 168 * <code>KeyGenerator</code> object. 169 * 170 * @return the algorithm name of this <code>KeyGenerator</code> object. 171 */ 172 public final String getAlgorithm() { 173 return this.algorithm; 174 } 175 176 /** 177 * Returns a <code>KeyGenerator</code> object that generates secret keys 178 * for the specified algorithm. 179 * 180 * <p> This method traverses the list of registered security Providers, 181 * starting with the most preferred Provider. 182 * A new KeyGenerator object encapsulating the 183 * KeyGeneratorSpi implementation from the first 184 * Provider that supports the specified algorithm is returned. 185 * 186 * <p> Note that the list of registered providers may be retrieved via 187 * the {@link Security#getProviders() Security.getProviders()} method. 188 * 189 * @param algorithm the standard name of the requested key algorithm. 190 * See the KeyGenerator section in the <a href= 191 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator"> 192 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 193 * for information about standard algorithm names. 194 * 195 * @return the new <code>KeyGenerator</code> object. 196 * 197 * @exception NullPointerException if the specified algorithm is null. 198 * 199 * @exception NoSuchAlgorithmException if no Provider supports a 200 * KeyGeneratorSpi implementation for the 201 * specified algorithm. 202 * 203 * @see java.security.Provider 204 */ 205 public static final KeyGenerator getInstance(String algorithm) 206 throws NoSuchAlgorithmException { 207 return new KeyGenerator(algorithm); 208 } 209 210 /** 211 * Returns a <code>KeyGenerator</code> object that generates secret keys 212 * for the specified algorithm. 213 * 214 * <p> A new KeyGenerator object encapsulating the 215 * KeyGeneratorSpi implementation from the specified provider 216 * is returned. The specified provider must be registered 217 * in the security provider list. 218 * 219 * <p> Note that the list of registered providers may be retrieved via 220 * the {@link Security#getProviders() Security.getProviders()} method. 221 * 222 * @param algorithm the standard name of the requested key algorithm. 223 * See the KeyGenerator section in the <a href= 224 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator"> 225 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 226 * for information about standard algorithm names. 227 * 228 * @param provider the name of the provider. 229 * 230 * @return the new <code>KeyGenerator</code> object. 231 * 232 * @exception NullPointerException if the specified algorithm is null. 233 * 234 * @exception NoSuchAlgorithmException if a KeyGeneratorSpi 235 * implementation for the specified algorithm is not 236 * available from the specified provider. 237 * 238 * @exception NoSuchProviderException if the specified provider is not 239 * registered in the security provider list. 240 * 241 * @exception IllegalArgumentException if the <code>provider</code> 242 * is null or empty. 243 * 244 * @see java.security.Provider 245 */ 246 public static final KeyGenerator getInstance(String algorithm, 247 String provider) throws NoSuchAlgorithmException, 248 NoSuchProviderException { 249 Instance instance = JceSecurity.getInstance("KeyGenerator", 250 KeyGeneratorSpi.class, algorithm, provider); 251 return new KeyGenerator((KeyGeneratorSpi)instance.impl, 252 instance.provider, algorithm); 253 } 254 255 /** 256 * Returns a <code>KeyGenerator</code> object that generates secret keys 257 * for the specified algorithm. 258 * 259 * <p> A new KeyGenerator object encapsulating the 260 * KeyGeneratorSpi implementation from the specified Provider 261 * object is returned. Note that the specified Provider object 262 * does not have to be registered in the provider list. 263 * 264 * @param algorithm the standard name of the requested key algorithm. 265 * See the KeyGenerator section in the <a href= 266 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator"> 267 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 268 * for information about standard algorithm names. 269 * 270 * @param provider the provider. 271 * 272 * @return the new <code>KeyGenerator</code> object. 273 * 274 * @exception NullPointerException if the specified algorithm is null. 275 * 276 * @exception NoSuchAlgorithmException if a KeyGeneratorSpi 277 * implementation for the specified algorithm is not available 278 * from the specified Provider object. 279 * 280 * @exception IllegalArgumentException if the <code>provider</code> 281 * is null. 282 * 283 * @see java.security.Provider 284 */ 285 public static final KeyGenerator getInstance(String algorithm, 286 Provider provider) throws NoSuchAlgorithmException { 287 Instance instance = JceSecurity.getInstance("KeyGenerator", 288 KeyGeneratorSpi.class, algorithm, provider); 289 return new KeyGenerator((KeyGeneratorSpi)instance.impl, 290 instance.provider, algorithm); 291 } 292 293 /** 294 * Returns the provider of this <code>KeyGenerator</code> object. 295 * 296 * @return the provider of this <code>KeyGenerator</code> object 297 */ 298 public final Provider getProvider() { 299 synchronized (lock) { 300 disableFailover(); 301 return provider; 302 } 303 } 304 305 /** 306 * Update the active spi of this class and return the next 307 * implementation for failover. If no more implemenations are 308 * available, this method returns null. However, the active spi of 309 * this class is never set to null. 310 */ 311 private KeyGeneratorSpi nextSpi(KeyGeneratorSpi oldSpi, 312 boolean reinit) { 313 synchronized (lock) { 314 // somebody else did a failover concurrently 315 // try that spi now 316 if ((oldSpi != null) && (oldSpi != spi)) { 317 return spi; 318 } 319 if (serviceIterator == null) { 320 return null; 321 } 322 while (serviceIterator.hasNext()) { 323 Service s = (Service)serviceIterator.next(); 324 if (JceSecurity.canUseProvider(s.getProvider()) == false) { 325 continue; 326 } 327 try { 328 Object inst = s.newInstance(null); 329 // ignore non-spis 330 if (inst instanceof KeyGeneratorSpi == false) { 331 continue; 332 } 333 KeyGeneratorSpi spi = (KeyGeneratorSpi)inst; 334 if (reinit) { 335 if (initType == I_SIZE) { 336 spi.engineInit(initKeySize, initRandom); 337 } else if (initType == I_PARAMS) { 338 spi.engineInit(initParams, initRandom); 339 } else if (initType == I_RANDOM) { 340 spi.engineInit(initRandom); 341 } else if (initType != I_NONE) { 342 throw new AssertionError 343 ("KeyGenerator initType: " + initType); 344 } 345 } 346 provider = s.getProvider(); 347 this.spi = spi; 348 return spi; 349 } catch (Exception e) { 350 // ignore 351 } 352 } 353 disableFailover(); 354 return null; 355 } 356 } 357 358 void disableFailover() { 359 serviceIterator = null; 360 initType = 0; 361 initParams = null; 362 initRandom = null; 363 } 364 365 /** 366 * Initializes this key generator. 367 * 368 * @param random the source of randomness for this generator 369 */ 370 public final void init(SecureRandom random) { 371 if (serviceIterator == null) { 372 spi.engineInit(random); 373 return; 374 } 375 RuntimeException failure = null; 376 KeyGeneratorSpi mySpi = spi; 377 do { 378 try { 379 mySpi.engineInit(random); 380 initType = I_RANDOM; 381 initKeySize = 0; 382 initParams = null; 383 initRandom = random; 384 return; 385 } catch (RuntimeException e) { 386 if (failure == null) { 387 failure = e; 388 } 389 mySpi = nextSpi(mySpi, false); 390 } 391 } while (mySpi != null); 392 throw failure; 393 } 394 395 /** 396 * Initializes this key generator with the specified parameter set. 397 * 398 * <p> If this key generator requires any random bytes, it will get them 399 * using the 400 * {@link SecureRandom <code>SecureRandom</code>} 401 * implementation of the highest-priority installed 402 * provider as the source of randomness. 403 * (If none of the installed providers supply an implementation of 404 * SecureRandom, a system-provided source of randomness will be used.) 405 * 406 * @param params the key generation parameters 407 * 408 * @exception InvalidAlgorithmParameterException if the given parameters 409 * are inappropriate for this key generator 410 */ 411 public final void init(AlgorithmParameterSpec params) 412 throws InvalidAlgorithmParameterException 413 { 414 init(params, JceSecurity.RANDOM); 415 } 416 417 /** 418 * Initializes this key generator with the specified parameter 419 * set and a user-provided source of randomness. 420 * 421 * @param params the key generation parameters 422 * @param random the source of randomness for this key generator 423 * 424 * @exception InvalidAlgorithmParameterException if <code>params</code> is 425 * inappropriate for this key generator 426 */ 427 public final void init(AlgorithmParameterSpec params, SecureRandom random) 428 throws InvalidAlgorithmParameterException 429 { 430 if (serviceIterator == null) { 431 spi.engineInit(params, random); 432 return; 433 } 434 Exception failure = null; 435 KeyGeneratorSpi mySpi = spi; 436 do { 437 try { 438 mySpi.engineInit(params, random); 439 initType = I_PARAMS; 440 initKeySize = 0; 441 initParams = params; 442 initRandom = random; 443 return; 444 } catch (Exception e) { 445 if (failure == null) { 446 failure = e; 447 } 448 mySpi = nextSpi(mySpi, false); 449 } 450 } while (mySpi != null); 451 if (failure instanceof InvalidAlgorithmParameterException) { 452 throw (InvalidAlgorithmParameterException)failure; 453 } 454 if (failure instanceof RuntimeException) { 455 throw (RuntimeException)failure; 456 } 457 throw new InvalidAlgorithmParameterException("init() failed", failure); 458 } 459 460 /** 461 * Initializes this key generator for a certain keysize. 462 * 463 * <p> If this key generator requires any random bytes, it will get them 464 * using the 465 * {@link SecureRandom <code>SecureRandom</code>} 466 * implementation of the highest-priority installed 467 * provider as the source of randomness. 468 * (If none of the installed providers supply an implementation of 469 * SecureRandom, a system-provided source of randomness will be used.) 470 * 471 * @param keysize the keysize. This is an algorithm-specific metric, 472 * specified in number of bits. 473 * 474 * @exception InvalidParameterException if the keysize is wrong or not 475 * supported. 476 */ 477 public final void init(int keysize) { 478 init(keysize, JceSecurity.RANDOM); 479 } 480 481 /** 482 * Initializes this key generator for a certain keysize, using a 483 * user-provided source of randomness. 484 * 485 * @param keysize the keysize. This is an algorithm-specific metric, 486 * specified in number of bits. 487 * @param random the source of randomness for this key generator 488 * 489 * @exception InvalidParameterException if the keysize is wrong or not 490 * supported. 491 */ 492 public final void init(int keysize, SecureRandom random) { 493 if (serviceIterator == null) { 494 spi.engineInit(keysize, random); 495 return; 496 } 497 RuntimeException failure = null; 498 KeyGeneratorSpi mySpi = spi; 499 do { 500 try { 501 mySpi.engineInit(keysize, random); 502 initType = I_SIZE; 503 initKeySize = keysize; 504 initParams = null; 505 initRandom = random; 506 return; 507 } catch (RuntimeException e) { 508 if (failure == null) { 509 failure = e; 510 } 511 mySpi = nextSpi(mySpi, false); 512 } 513 } while (mySpi != null); 514 throw failure; 515 } 516 517 /** 518 * Generates a secret key. 519 * 520 * @return the new key 521 */ 522 public final SecretKey generateKey() { 523 if (serviceIterator == null) { 524 return spi.engineGenerateKey(); 525 } 526 RuntimeException failure = null; 527 KeyGeneratorSpi mySpi = spi; 528 do { 529 try { 530 return mySpi.engineGenerateKey(); 531 } catch (RuntimeException e) { 532 if (failure == null) { 533 failure = e; 534 } 535 mySpi = nextSpi(mySpi, true); 536 } 537 } while (mySpi != null); 538 throw failure; 539 } 540 }