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