KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > security > KeyPairGenerator


1 /*
2  * @(#)KeyPairGenerator.java 1.56 04/01/28
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7  
8 package java.security;
9
10 import java.util.*;
11
12 import java.security.spec.AlgorithmParameterSpec JavaDoc;
13
14 import java.security.Provider.Service;
15
16 import sun.security.jca.*;
17 import sun.security.jca.GetInstance.Instance;
18
19 /**
20  * The KeyPairGenerator class is used to generate pairs of
21  * public and private keys. Key pair generators are constructed using the
22  * <code>getInstance</code> factory methods (static methods that
23  * return instances of a given class).
24  *
25  * <p>A Key pair generator for a particular algorithm creates a public/private
26  * key pair that can be used with this algorithm. It also associates
27  * algorithm-specific parameters with each of the generated keys.
28  *
29  * <p>There are two ways to generate a key pair: in an algorithm-independent
30  * manner, and in an algorithm-specific manner.
31  * The only difference between the two is the initialization of the object:
32  *
33  * <ul>
34  * <li><b>Algorithm-Independent Initialization</b>
35  * <p>All key pair generators share the concepts of a keysize and a
36  * source of randomness. The keysize is interpreted differently for different
37  * algorithms (e.g., in the case of the <i>DSA</i> algorithm, the keysize
38  * corresponds to the length of the modulus).
39  * There is an
40  * {@link #initialize(int, java.security.SecureRandom) initialize}
41  * method in this KeyPairGenerator class that takes these two universally
42  * shared types of arguments. There is also one that takes just a
43  * <code>keysize</code> argument, and uses the <code>SecureRandom</code>
44  * implementation of the highest-priority installed provider as the source
45  * of randomness. (If none of the installed providers supply an implementation
46  * of <code>SecureRandom</code>, a system-provided source of randomness is
47  * used.)
48  *
49  * <p>Since no other parameters are specified when you call the above
50  * algorithm-independent <code>initialize</code> methods, it is up to the
51  * provider what to do about the algorithm-specific parameters (if any) to be
52  * associated with each of the keys.
53  *
54  * <p>If the algorithm is the <i>DSA</i> algorithm, and the keysize (modulus
55  * size) is 512, 768, or 1024, then the <i>Sun</i> provider uses a set of
56  * precomputed values for the <code>p</code>, <code>q</code>, and
57  * <code>g</code> parameters. If the modulus size is not one of the above
58  * values, the <i>Sun</i> provider creates a new set of parameters. Other
59  * providers might have precomputed parameter sets for more than just the
60  * three modulus sizes mentioned above. Still others might not have a list of
61  * precomputed parameters at all and instead always create new parameter sets.
62  * <p>
63  *
64  * <li><b>Algorithm-Specific Initialization</b>
65  * <p>For situations where a set of algorithm-specific parameters already
66  * exists (e.g., so-called <i>community parameters</i> in DSA), there are two
67  * {@link #initialize(java.security.spec.AlgorithmParameterSpec)
68  * initialize} methods that have an <code>AlgorithmParameterSpec</code>
69  * argument. One also has a <code>SecureRandom</code> argument, while the
70  * the other uses the <code>SecureRandom</code>
71  * implementation of the highest-priority installed provider as the source
72  * of randomness. (If none of the installed providers supply an implementation
73  * of <code>SecureRandom</code>, a system-provided source of randomness is
74  * used.)
75  * </ul>
76  *
77  * <p>In case the client does not explicitly initialize the KeyPairGenerator
78  * (via a call to an <code>initialize</code> method), each provider must
79  * supply (and document) a default initialization.
80  * For example, the <i>Sun</i> provider uses a default modulus size (keysize)
81  * of 1024 bits.
82  *
83  * <p>Note that this class is abstract and extends from
84  * <code>KeyPairGeneratorSpi</code> for historical reasons.
85  * Application developers should only take notice of the methods defined in
86  * this <code>KeyPairGenerator</code> class; all the methods in
87  * the superclass are intended for cryptographic service providers who wish to
88  * supply their own implementations of key pair generators.
89  *
90  * @author Benjamin Renaud
91  *
92  * @version 1.56, 01/28/04
93  *
94  * @see java.security.spec.AlgorithmParameterSpec
95  */

96
97 public abstract class KeyPairGenerator extends KeyPairGeneratorSpi JavaDoc {
98
99     private final String JavaDoc algorithm;
100
101     // The provider
102
Provider JavaDoc provider;
103
104     /**
105      * Creates a KeyPairGenerator object for the specified algorithm.
106      *
107      * @param algorithm the standard string name of the algorithm.
108      * See Appendix A in the <a HREF=
109      * "../../../guide/security/CryptoSpec.html#AppA">
110      * Java Cryptography Architecture API Specification &amp; Reference </a>
111      * for information about standard algorithm names.
112      */

113     protected KeyPairGenerator(String JavaDoc algorithm) {
114     this.algorithm = algorithm;
115     }
116     
117     /**
118      * Returns the standard name of the algorithm for this key pair generator.
119      * See Appendix A in the <a HREF=
120      * "../../../guide/security/CryptoSpec.html#AppA">
121      * Java Cryptography Architecture API Specification &amp; Reference </a>
122      * for information about standard algorithm names.
123      *
124      * @return the standard string name of the algorithm.
125      */

126     public String JavaDoc getAlgorithm() {
127     return this.algorithm;
128     }
129
130     private static KeyPairGenerator JavaDoc getInstance(Instance instance,
131         String JavaDoc algorithm) {
132     KeyPairGenerator JavaDoc kpg;
133     if (instance.impl instanceof KeyPairGenerator JavaDoc) {
134         kpg = (KeyPairGenerator JavaDoc)instance.impl;
135     } else {
136         KeyPairGeneratorSpi JavaDoc spi = (KeyPairGeneratorSpi JavaDoc)instance.impl;
137         kpg = new Delegate(spi, algorithm);
138     }
139     kpg.provider = instance.provider;
140     return kpg;
141     }
142
143     /**
144      * Generates a KeyPairGenerator object that implements the specified digest
145      * algorithm. If the default provider package
146      * provides an implementation of the requested digest algorithm,
147      * an instance of KeyPairGenerator containing that implementation is
148      * returned.
149      * If the algorithm is not available in the default
150      * package, other packages are searched.
151      *
152      * @param algorithm the standard string name of the algorithm.
153      * See Appendix A in the <a HREF=
154      * "../../../guide/security/CryptoSpec.html#AppA">
155      * Java Cryptography Architecture API Specification &amp; Reference </a>
156      * for information about standard algorithm names.
157      *
158      * @return the new KeyPairGenerator object.
159      *
160      * @exception NoSuchAlgorithmException if the algorithm is
161      * not available in the environment.
162      */

163     public static KeyPairGenerator JavaDoc getInstance(String JavaDoc algorithm)
164         throws NoSuchAlgorithmException JavaDoc {
165     List<Service> list =
166         GetInstance.getServices("KeyPairGenerator", algorithm);
167     Iterator<Service> t = list.iterator();
168     if (t.hasNext() == false) {
169         throw new NoSuchAlgorithmException JavaDoc
170             (algorithm + " KeyPairGenerator not available");
171     }
172     // find a working Spi or KeyPairGenerator subclass
173
NoSuchAlgorithmException JavaDoc failure = null;
174     do {
175         Service s = t.next();
176         try {
177         Instance instance =
178             GetInstance.getInstance(s, KeyPairGeneratorSpi JavaDoc.class);
179         if (instance.impl instanceof KeyPairGenerator JavaDoc) {
180             return getInstance(instance, algorithm);
181         } else {
182             return new Delegate(instance, t, algorithm);
183         }
184         } catch (NoSuchAlgorithmException JavaDoc e) {
185         if (failure == null) {
186             failure = e;
187         }
188         }
189     } while (t.hasNext());
190     throw failure;
191     }
192
193     /**
194      * Generates a KeyPairGenerator object implementing the specified
195      * algorithm, as supplied from the specified provider,
196      * if such an algorithm is available from the provider.
197      *
198      * @param algorithm the standard string name of the algorithm.
199      * See Appendix A in the <a HREF=
200      * "../../../guide/security/CryptoSpec.html#AppA">
201      * Java Cryptography Architecture API Specification &amp; Reference </a>
202      * for information about standard algorithm names.
203      *
204      * @param provider the string name of the provider.
205      *
206      * @return the new KeyPairGenerator object.
207      *
208      * @exception NoSuchAlgorithmException if the algorithm is
209      * not available from the provider.
210      *
211      * @exception NoSuchProviderException if the provider is not
212      * available in the environment.
213      *
214      * @exception IllegalArgumentException if the provider name is null
215      * or empty.
216      *
217      * @see Provider
218      */

219     public static KeyPairGenerator JavaDoc getInstance(String JavaDoc algorithm,
220         String JavaDoc provider)
221         throws NoSuchAlgorithmException JavaDoc, NoSuchProviderException JavaDoc {
222     Instance instance = GetInstance.getInstance("KeyPairGenerator",
223         KeyPairGeneratorSpi JavaDoc.class, algorithm, provider);
224     return getInstance(instance, algorithm);
225     }
226
227     /**
228      * Generates a KeyPairGenerator object implementing the specified
229      * algorithm, as supplied from the specified provider,
230      * if such an algorithm is available from the provider.
231      * Note: the <code>provider</code> doesn't have to be registered.
232      *
233      * @param algorithm the standard string name of the algorithm.
234      * See Appendix A in the <a HREF=
235      * "../../../guide/security/CryptoSpec.html#AppA">
236      * Java Cryptography Architecture API Specification &amp; Reference </a>
237      * for information about standard algorithm names.
238      *
239      * @param provider the provider.
240      *
241      * @return the new KeyPairGenerator object.
242      *
243      * @exception NoSuchAlgorithmException if the algorithm is
244      * not available from the provider.
245      *
246      * @exception IllegalArgumentException if the <code>provider</code> is
247      * null.
248      *
249      * @see Provider
250      *
251      * @since 1.4
252      */

253     public static KeyPairGenerator JavaDoc getInstance(String JavaDoc algorithm,
254         Provider JavaDoc provider) throws NoSuchAlgorithmException JavaDoc {
255     Instance instance = GetInstance.getInstance("KeyPairGenerator",
256         KeyPairGeneratorSpi JavaDoc.class, algorithm, provider);
257     return getInstance(instance, algorithm);
258     }
259
260     /**
261      * Returns the provider of this key pair generator object.
262      *
263      * @return the provider of this key pair generator object
264      */

265     public final Provider JavaDoc getProvider() {
266     disableFailover();
267     return this.provider;
268     }
269     
270     void disableFailover() {
271     // empty, overridden in Delegate
272
}
273
274     /**
275      * Initializes the key pair generator for a certain keysize using
276      * a default parameter set and the <code>SecureRandom</code>
277      * implementation of the highest-priority installed provider as the source
278      * of randomness.
279      * (If none of the installed providers supply an implementation of
280      * <code>SecureRandom</code>, a system-provided source of randomness is
281      * used.)
282      *
283      * @param keysize the keysize. This is an
284      * algorithm-specific metric, such as modulus length, specified in
285      * number of bits.
286      *
287      * @exception InvalidParameterException if the <code>keysize</code> is not
288      * supported by this KeyPairGenerator object.
289      */

290     public void initialize(int keysize) {
291     initialize(keysize, JCAUtil.getSecureRandom());
292     }
293
294     /**
295      * Initializes the key pair generator for a certain keysize with
296      * the given source of randomness (and a default parameter set).
297      *
298      * @param keysize the keysize. This is an
299      * algorithm-specific metric, such as modulus length, specified in
300      * number of bits.
301      * @param random the source of randomness.
302      *
303      * @exception InvalidParameterException if the <code>keysize</code> is not
304      * supported by this KeyPairGenerator object.
305      *
306      * @since 1.2
307      */

308     public void initialize(int keysize, SecureRandom JavaDoc random) {
309     // This does nothing, because either
310
// 1. the implementation object returned by getInstance() is an
311
// instance of KeyPairGenerator which has its own
312
// initialize(keysize, random) method, so the application would
313
// be calling that method directly, or
314
// 2. the implementation returned by getInstance() is an instance
315
// of Delegate, in which case initialize(keysize, random) is
316
// overridden to call the corresponding SPI method.
317
// (This is a special case, because the API and SPI method have the
318
// same name.)
319
}
320
321     /**
322      * Initializes the key pair generator using the specified parameter
323      * set and the <code>SecureRandom</code>
324      * implementation of the highest-priority installed provider as the source
325      * of randomness.
326      * (If none of the installed providers supply an implementation of
327      * <code>SecureRandom</code>, a system-provided source of randomness is
328      * used.).
329      *
330      * <p>This concrete method has been added to this previously-defined
331      * abstract class.
332      * This method calls the KeyPairGeneratorSpi
333      * {@link KeyPairGeneratorSpi#initialize(
334      * java.security.spec.AlgorithmParameterSpec,
335      * java.security.SecureRandom) initialize} method,
336      * passing it <code>params</code> and a source of randomness (obtained
337      * from the highest-priority installed provider or system-provided if none
338      * of the installed providers supply one).
339      * That <code>initialize</code> method always throws an
340      * UnsupportedOperationException if it is not overridden by the provider.
341      *
342      * @param params the parameter set used to generate the keys.
343      *
344      * @exception InvalidAlgorithmParameterException if the given parameters
345      * are inappropriate for this key pair generator.
346      *
347      * @since 1.2
348      */

349     public void initialize(AlgorithmParameterSpec JavaDoc params)
350         throws InvalidAlgorithmParameterException JavaDoc {
351     initialize(params, JCAUtil.getSecureRandom());
352     }
353
354     /**
355      * Initializes the key pair generator with the given parameter
356      * set and source of randomness.
357      *
358      * <p>This concrete method has been added to this previously-defined
359      * abstract class.
360      * This method calls the KeyPairGeneratorSpi {@link
361      * KeyPairGeneratorSpi#initialize(
362      * java.security.spec.AlgorithmParameterSpec,
363      * java.security.SecureRandom) initialize} method,
364      * passing it <code>params</code> and <code>random</code>.
365      * That <code>initialize</code>
366      * method always throws an
367      * UnsupportedOperationException if it is not overridden by the provider.
368      *
369      * @param params the parameter set used to generate the keys.
370      * @param random the source of randomness.
371      *
372      * @exception InvalidAlgorithmParameterException if the given parameters
373      * are inappropriate for this key pair generator.
374      *
375      * @since 1.2
376      */

377     public void initialize(AlgorithmParameterSpec JavaDoc params,
378                SecureRandom JavaDoc random)
379     throws InvalidAlgorithmParameterException JavaDoc
380     {
381     // This does nothing, because either
382
// 1. the implementation object returned by getInstance() is an
383
// instance of KeyPairGenerator which has its own
384
// initialize(params, random) method, so the application would
385
// be calling that method directly, or
386
// 2. the implementation returned by getInstance() is an instance
387
// of Delegate, in which case initialize(params, random) is
388
// overridden to call the corresponding SPI method.
389
// (This is a special case, because the API and SPI method have the
390
// same name.)
391
}
392
393     /**
394      * Generates a key pair.
395      *
396      * <p>If this KeyPairGenerator has not been initialized explicitly,
397      * provider-specific defaults will be used for the size and other
398      * (algorithm-specific) values of the generated keys.
399      *
400      * <p>This will generate a new key pair every time it is called.
401      *
402      * <p>This method is functionally equivalent to
403      * {@link #generateKeyPair() generateKeyPair}.
404      *
405      * @return the generated key pair
406      *
407      * @since 1.2
408      */

409     public final KeyPair JavaDoc genKeyPair() {
410     return generateKeyPair();
411     }
412
413     /**
414      * Generates a key pair.
415      *
416      * <p>If this KeyPairGenerator has not been initialized explicitly,
417      * provider-specific defaults will be used for the size and other
418      * (algorithm-specific) values of the generated keys.
419      *
420      * <p>This will generate a new key pair every time it is called.
421      *
422      * <p>This method is functionally equivalent to
423      * {@link #genKeyPair() genKeyPair}.
424      *
425      * @return the generated key pair
426      */

427     public KeyPair JavaDoc generateKeyPair() {
428     // This does nothing (except returning null), because either:
429
//
430
// 1. the implementation object returned by getInstance() is an
431
// instance of KeyPairGenerator which has its own implementation
432
// of generateKeyPair (overriding this one), so the application
433
// would be calling that method directly, or
434
//
435
// 2. the implementation returned by getInstance() is an instance
436
// of Delegate, in which case generateKeyPair is
437
// overridden to invoke the corresponding SPI method.
438
//
439
// (This is a special case, because in JDK 1.1.x the generateKeyPair
440
// method was used both as an API and a SPI method.)
441
return null;
442     }
443
444
445     /*
446      * The following class allows providers to extend from KeyPairGeneratorSpi
447      * rather than from KeyPairGenerator. It represents a KeyPairGenerator
448      * with an encapsulated, provider-supplied SPI object (of type
449      * KeyPairGeneratorSpi).
450      * If the provider implementation is an instance of KeyPairGeneratorSpi,
451      * the getInstance() methods above return an instance of this class, with
452      * the SPI object encapsulated.
453      *
454      * Note: All SPI methods from the original KeyPairGenerator class have been
455      * moved up the hierarchy into a new class (KeyPairGeneratorSpi), which has
456      * been interposed in the hierarchy between the API (KeyPairGenerator)
457      * and its original parent (Object).
458      */

459      
460     //
461
// error failover notes:
462
//
463
// . we failover if the implementation throws an error during init
464
// by retrying the init on other providers
465
//
466
// . we also failover if the init succeeded but the subsequent call
467
// to generateKeyPair() fails. In order for this to work, we need
468
// to remember the parameters to the last successful call to init
469
// and initialize() the next spi using them.
470
//
471
// . although not specified, KeyPairGenerators could be thread safe,
472
// so we make sure we do not interfere with that
473
//
474
// . failover is not available, if:
475
// . getInstance(algorithm, provider) was used
476
// . a provider extends KeyPairGenerator rather than
477
// KeyPairGeneratorSpi (JDK 1.1 style)
478
// . once getProvider() is called
479
//
480

481     private static final class Delegate extends KeyPairGenerator JavaDoc {
482
483     // The provider implementation (delegate)
484
private volatile KeyPairGeneratorSpi JavaDoc spi;
485     
486     private final Object JavaDoc lock = new Object JavaDoc();
487     
488     private Iterator<Service> serviceIterator;
489     
490     private final static int I_NONE = 1;
491     private final static int I_SIZE = 2;
492     private final static int I_PARAMS = 3;
493     
494     private int initType;
495     private int initKeySize;
496     private AlgorithmParameterSpec JavaDoc initParams;
497     private SecureRandom JavaDoc initRandom;
498
499     // constructor
500
Delegate(KeyPairGeneratorSpi JavaDoc spi, String JavaDoc algorithm) {
501         super(algorithm);
502         this.spi = spi;
503     }
504     
505     Delegate(Instance instance, Iterator<Service> serviceIterator,
506         String JavaDoc algorithm) {
507         super(algorithm);
508         spi = (KeyPairGeneratorSpi JavaDoc)instance.impl;
509         provider = instance.provider;
510         this.serviceIterator = serviceIterator;
511         initType = I_NONE;
512     }
513     
514     /**
515      * Update the active spi of this class and return the next
516      * implementation for failover. If no more implemenations are
517      * available, this method returns null. However, the active spi of
518      * this class is never set to null.
519      */

520     private KeyPairGeneratorSpi JavaDoc nextSpi(KeyPairGeneratorSpi JavaDoc oldSpi,
521         boolean reinit) {
522         synchronized (lock) {
523         // somebody else did a failover concurrently
524
// try that spi now
525
if ((oldSpi != null) && (oldSpi != spi)) {
526             return spi;
527         }
528         if (serviceIterator == null) {
529             return null;
530         }
531         while (serviceIterator.hasNext()) {
532             Service s = serviceIterator.next();
533             try {
534             Object JavaDoc inst = s.newInstance(null);
535             // ignore non-spis
536
if (inst instanceof KeyPairGeneratorSpi JavaDoc == false) {
537                 continue;
538             }
539             if (inst instanceof KeyPairGenerator JavaDoc) {
540                 continue;
541             }
542             KeyPairGeneratorSpi JavaDoc spi = (KeyPairGeneratorSpi JavaDoc)inst;
543             if (reinit) {
544                 if (initType == I_SIZE) {
545                 spi.initialize(initKeySize, initRandom);
546                 } else if (initType == I_PARAMS) {
547                 spi.initialize(initParams, initRandom);
548                 } else if (initType != I_NONE) {
549                 throw new AssertionError JavaDoc
550                     ("KeyPairGenerator initType: " + initType);
551                 }
552             }
553             provider = s.getProvider();
554             this.spi = spi;
555             return spi;
556             } catch (Exception JavaDoc e) {
557             // ignore
558
}
559         }
560         disableFailover();
561         return null;
562         }
563     }
564     
565     void disableFailover() {
566         serviceIterator = null;
567         initType = 0;
568         initParams = null;
569         initRandom = null;
570     }
571
572     // engine method
573
public void initialize(int keysize, SecureRandom JavaDoc random) {
574         if (serviceIterator == null) {
575         spi.initialize(keysize, random);
576         return;
577         }
578         RuntimeException JavaDoc failure = null;
579         KeyPairGeneratorSpi JavaDoc mySpi = spi;
580         do {
581         try {
582             mySpi.initialize(keysize, random);
583             initType = I_SIZE;
584             initKeySize = keysize;
585             initParams = null;
586             initRandom = random;
587             return;
588         } catch (RuntimeException JavaDoc e) {
589             if (failure == null) {
590             failure = e;
591             }
592             mySpi = nextSpi(mySpi, false);
593         }
594         } while (mySpi != null);
595         throw failure;
596     }
597
598     // engine method
599
public void initialize(AlgorithmParameterSpec JavaDoc params,
600         SecureRandom JavaDoc random) throws InvalidAlgorithmParameterException JavaDoc {
601         if (serviceIterator == null) {
602         spi.initialize(params, random);
603         return;
604         }
605         Exception JavaDoc failure = null;
606         KeyPairGeneratorSpi JavaDoc mySpi = spi;
607         do {
608         try {
609             mySpi.initialize(params, random);
610             initType = I_PARAMS;
611             initKeySize = 0;
612             initParams = params;
613             initRandom = random;
614             return;
615         } catch (Exception JavaDoc e) {
616             if (failure == null) {
617             failure = e;
618             }
619             mySpi = nextSpi(mySpi, false);
620         }
621         } while (mySpi != null);
622         if (failure instanceof RuntimeException JavaDoc) {
623         throw (RuntimeException JavaDoc)failure;
624         }
625         // must be an InvalidAlgorithmParameterException
626
throw (InvalidAlgorithmParameterException JavaDoc)failure;
627     }
628
629     // engine method
630
public KeyPair JavaDoc generateKeyPair() {
631         if (serviceIterator == null) {
632         return spi.generateKeyPair();
633         }
634         RuntimeException JavaDoc failure = null;
635         KeyPairGeneratorSpi JavaDoc mySpi = spi;
636         do {
637         try {
638             return mySpi.generateKeyPair();
639         } catch (RuntimeException JavaDoc e) {
640             if (failure == null) {
641             failure = e;
642             }
643             mySpi = nextSpi(mySpi, true);
644         }
645         } while (mySpi != null);
646         throw failure;
647     }
648     }
649
650 }
651
652
Popular Tags