1 /* 2 * Copyright (c) 1997, 2013, 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<Service> 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<Service> list = 154 GetInstance.getServices("KeyGenerator", algorithm); 155 serviceIterator = list.iterator(); 156 initType = I_NONE; 157 // fetch and instantiate initial spi 158 if (nextSpi(null, false) == null) { 159 throw new NoSuchAlgorithmException 160 (algorithm + " KeyGenerator not available"); 161 } 162 } 163 164 /** 165 * Returns the algorithm name of this <code>KeyGenerator</code> object. 166 * 167 * <p>This is the same name that was specified in one of the 168 * <code>getInstance</code> calls that created this 169 * <code>KeyGenerator</code> object. 170 * 171 * @return the algorithm name of this <code>KeyGenerator</code> object. 172 */ 173 public final String getAlgorithm() { 174 return this.algorithm; 175 } 176 177 /** 178 * Returns a <code>KeyGenerator</code> object that generates secret keys 179 * for the specified algorithm. 180 * 181 * <p> This method traverses the list of registered security Providers, 182 * starting with the most preferred Provider. 183 * A new KeyGenerator object encapsulating the 184 * KeyGeneratorSpi implementation from the first 185 * Provider that supports the specified algorithm is returned. 186 * 187 * <p> Note that the list of registered providers may be retrieved via 188 * the {@link Security#getProviders() Security.getProviders()} method. 189 * 190 * @param algorithm the standard name of the requested key algorithm. 191 * See the KeyGenerator section in the <a href= 192 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator"> 193 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 194 * for information about standard algorithm names. 195 * 196 * @return the new <code>KeyGenerator</code> object. 197 * 198 * @exception NullPointerException if the specified algorithm is null. 199 * 200 * @exception NoSuchAlgorithmException if no Provider supports a 201 * KeyGeneratorSpi implementation for the 202 * specified algorithm. 203 * 204 * @see java.security.Provider 205 */ 206 public static final KeyGenerator getInstance(String algorithm) 207 throws NoSuchAlgorithmException { 208 return new KeyGenerator(algorithm); 209 } 210 211 /** 212 * Returns a <code>KeyGenerator</code> object that generates secret keys 213 * for the specified algorithm. 214 * 215 * <p> A new KeyGenerator object encapsulating the 216 * KeyGeneratorSpi implementation from the specified provider 217 * is returned. The specified provider must be registered 218 * in the security provider list. 219 * 220 * <p> Note that the list of registered providers may be retrieved via 221 * the {@link Security#getProviders() Security.getProviders()} method. 222 * 223 * @param algorithm the standard name of the requested key algorithm. 224 * See the KeyGenerator section in the <a href= 225 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator"> 226 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 227 * for information about standard algorithm names. 228 * 229 * @param provider the name of the provider. 230 * 231 * @return the new <code>KeyGenerator</code> object. 232 * 233 * @exception NullPointerException if the specified algorithm is null. 234 * 235 * @exception NoSuchAlgorithmException if a KeyGeneratorSpi 236 * implementation for the specified algorithm is not 237 * available from the specified provider. 238 * 239 * @exception NoSuchProviderException if the specified provider is not 240 * registered in the security provider list. 241 * 242 * @exception IllegalArgumentException if the <code>provider</code> 243 * is null or empty. 244 * 245 * @see java.security.Provider 246 */ 247 public static final KeyGenerator getInstance(String algorithm, 248 String provider) throws NoSuchAlgorithmException, 249 NoSuchProviderException { 250 Instance instance = JceSecurity.getInstance("KeyGenerator", 251 KeyGeneratorSpi.class, algorithm, provider); 252 return new KeyGenerator((KeyGeneratorSpi)instance.impl, 253 instance.provider, algorithm); 254 } 255 256 /** 257 * Returns a <code>KeyGenerator</code> object that generates secret keys 258 * for the specified algorithm. 259 * 260 * <p> A new KeyGenerator object encapsulating the 261 * KeyGeneratorSpi implementation from the specified Provider 262 * object is returned. Note that the specified Provider object 263 * does not have to be registered in the provider list. 264 * 265 * @param algorithm the standard name of the requested key algorithm. 266 * See the KeyGenerator section in the <a href= 267 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator"> 268 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 269 * for information about standard algorithm names. 270 * 271 * @param provider the provider. 272 * 273 * @return the new <code>KeyGenerator</code> object. 274 * 275 * @exception NullPointerException if the specified algorithm is null. 276 * 277 * @exception NoSuchAlgorithmException if a KeyGeneratorSpi 278 * implementation for the specified algorithm is not available 279 * from the specified Provider object. 280 * 281 * @exception IllegalArgumentException if the <code>provider</code> 282 * is null. 283 * 284 * @see java.security.Provider 285 */ 286 public static final KeyGenerator getInstance(String algorithm, 287 Provider provider) throws NoSuchAlgorithmException { 288 Instance instance = JceSecurity.getInstance("KeyGenerator", 289 KeyGeneratorSpi.class, algorithm, provider); 290 return new KeyGenerator((KeyGeneratorSpi)instance.impl, 291 instance.provider, algorithm); 292 } 293 294 /** 295 * Returns the provider of this <code>KeyGenerator</code> object. 296 * 297 * @return the provider of this <code>KeyGenerator</code> object 298 */ 299 public final Provider getProvider() { 300 synchronized (lock) { 301 disableFailover(); 302 return provider; 303 } 304 } 305 306 /** 307 * Update the active spi of this class and return the next 308 * implementation for failover. If no more implemenations are 309 * available, this method returns null. However, the active spi of 310 * this class is never set to null. 311 */ 312 private KeyGeneratorSpi nextSpi(KeyGeneratorSpi oldSpi, 313 boolean reinit) { 314 synchronized (lock) { 315 // somebody else did a failover concurrently 316 // try that spi now 317 if ((oldSpi != null) && (oldSpi != spi)) { 318 return spi; 319 } 320 if (serviceIterator == null) { 321 return null; 322 } 323 while (serviceIterator.hasNext()) { 324 Service s = serviceIterator.next(); 325 if (JceSecurity.canUseProvider(s.getProvider()) == false) { 326 continue; 327 } 328 try { 329 Object inst = s.newInstance(null); 330 // ignore non-spis 331 if (inst instanceof KeyGeneratorSpi == false) { 332 continue; 333 } 334 KeyGeneratorSpi spi = (KeyGeneratorSpi)inst; 335 if (reinit) { 336 if (initType == I_SIZE) { 337 spi.engineInit(initKeySize, initRandom); 338 } else if (initType == I_PARAMS) { 339 spi.engineInit(initParams, initRandom); 340 } else if (initType == I_RANDOM) { 341 spi.engineInit(initRandom); 342 } else if (initType != I_NONE) { 343 throw new AssertionError 344 ("KeyGenerator initType: " + initType); 345 } 346 } 347 provider = s.getProvider(); 348 this.spi = spi; 349 return spi; 350 } catch (Exception e) { 351 // ignore 352 } 353 } 354 disableFailover(); 355 return null; 356 } 357 } 358 359 void disableFailover() { 360 serviceIterator = null; 361 initType = 0; 362 initParams = null; 363 initRandom = null; 364 } 365 366 /** 367 * Initializes this key generator. 368 * 369 * @param random the source of randomness for this generator 370 */ 371 public final void init(SecureRandom random) { 372 if (serviceIterator == null) { 373 spi.engineInit(random); 374 return; 375 } 376 RuntimeException failure = null; 377 KeyGeneratorSpi mySpi = spi; 378 do { 379 try { 380 mySpi.engineInit(random); 381 initType = I_RANDOM; 382 initKeySize = 0; 383 initParams = null; 384 initRandom = random; 385 return; 386 } catch (RuntimeException e) { 387 if (failure == null) { 388 failure = e; 389 } 390 mySpi = nextSpi(mySpi, false); 391 } 392 } while (mySpi != null); 393 throw failure; 394 } 395 396 /** 397 * Initializes this key generator with the specified parameter set. 398 * 399 * <p> If this key generator requires any random bytes, it will get them 400 * using the 401 * {@link java.security.SecureRandom} 402 * implementation of the highest-priority installed 403 * provider as the source of randomness. 404 * (If none of the installed providers supply an implementation of 405 * SecureRandom, a system-provided source of randomness will be used.) 406 * 407 * @param params the key generation parameters 408 * 409 * @exception InvalidAlgorithmParameterException if the given parameters 410 * are inappropriate for this key generator 411 */ 412 public final void init(AlgorithmParameterSpec params) 413 throws InvalidAlgorithmParameterException 414 { 415 init(params, JceSecurity.RANDOM); 416 } 417 418 /** 419 * Initializes this key generator with the specified parameter 420 * set and a user-provided source of randomness. 421 * 422 * @param params the key generation parameters 423 * @param random the source of randomness for this key generator 424 * 425 * @exception InvalidAlgorithmParameterException if <code>params</code> is 426 * inappropriate for this key generator 427 */ 428 public final void init(AlgorithmParameterSpec params, SecureRandom random) 429 throws InvalidAlgorithmParameterException 430 { 431 if (serviceIterator == null) { 432 spi.engineInit(params, random); 433 return; 434 } 435 Exception failure = null; 436 KeyGeneratorSpi mySpi = spi; 437 do { 438 try { 439 mySpi.engineInit(params, random); 440 initType = I_PARAMS; 441 initKeySize = 0; 442 initParams = params; 443 initRandom = random; 444 return; 445 } catch (Exception e) { 446 if (failure == null) { 447 failure = e; 448 } 449 mySpi = nextSpi(mySpi, false); 450 } 451 } while (mySpi != null); 452 if (failure instanceof InvalidAlgorithmParameterException) { 453 throw (InvalidAlgorithmParameterException)failure; 454 } 455 if (failure instanceof RuntimeException) { 456 throw (RuntimeException)failure; 457 } 458 throw new InvalidAlgorithmParameterException("init() failed", failure); 459 } 460 461 /** 462 * Initializes this key generator for a certain keysize. 463 * 464 * <p> If this key generator requires any random bytes, it will get them 465 * using the 466 * {@link java.security.SecureRandom} 467 * implementation of the highest-priority installed 468 * provider as the source of randomness. 469 * (If none of the installed providers supply an implementation of 470 * SecureRandom, a system-provided source of randomness will be used.) 471 * 472 * @param keysize the keysize. This is an algorithm-specific metric, 473 * specified in number of bits. 474 * 475 * @exception InvalidParameterException if the keysize is wrong or not 476 * supported. 477 */ 478 public final void init(int keysize) { 479 init(keysize, JceSecurity.RANDOM); 480 } 481 482 /** 483 * Initializes this key generator for a certain keysize, using a 484 * user-provided source of randomness. 485 * 486 * @param keysize the keysize. This is an algorithm-specific metric, 487 * specified in number of bits. 488 * @param random the source of randomness for this key generator 489 * 490 * @exception InvalidParameterException if the keysize is wrong or not 491 * supported. 492 */ 493 public final void init(int keysize, SecureRandom random) { 494 if (serviceIterator == null) { 495 spi.engineInit(keysize, random); 496 return; 497 } 498 RuntimeException failure = null; 499 KeyGeneratorSpi mySpi = spi; 500 do { 501 try { 502 mySpi.engineInit(keysize, random); 503 initType = I_SIZE; 504 initKeySize = keysize; 505 initParams = null; 506 initRandom = random; 507 return; 508 } catch (RuntimeException e) { 509 if (failure == null) { 510 failure = e; 511 } 512 mySpi = nextSpi(mySpi, false); 513 } 514 } while (mySpi != null); 515 throw failure; 516 } 517 518 /** 519 * Generates a secret key. 520 * 521 * @return the new key 522 */ 523 public final SecretKey generateKey() { 524 if (serviceIterator == null) { 525 return spi.engineGenerateKey(); 526 } 527 RuntimeException failure = null; 528 KeyGeneratorSpi mySpi = spi; 529 do { 530 try { 531 return mySpi.engineGenerateKey(); 532 } catch (RuntimeException e) { 533 if (failure == null) { 534 failure = e; 535 } 536 mySpi = nextSpi(mySpi, true); 537 } 538 } while (mySpi != null); 539 throw failure; 540 } 541 }