KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > security > KeyFactory


1 /*
2  * @(#)KeyFactory.java 1.32 04/05/05
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.Provider.Service;
13 import java.security.spec.KeySpec JavaDoc;
14 import java.security.spec.InvalidKeySpecException JavaDoc;
15
16 import sun.security.util.Debug;
17 import sun.security.jca.*;
18 import sun.security.jca.GetInstance.Instance;
19
20 /**
21  * Key factories are used to convert <I>keys</I> (opaque
22  * cryptographic keys of type <code>Key</code>) into <I>key specifications</I>
23  * (transparent representations of the underlying key material), and vice
24  * versa.
25  *
26  * <P> Key factories are bi-directional. That is, they allow you to build an
27  * opaque key object from a given key specification (key material), or to
28  * retrieve the underlying key material of a key object in a suitable format.
29  *
30  * <P> Multiple compatible key specifications may exist for the same key.
31  * For example, a DSA public key may be specified using
32  * <code>DSAPublicKeySpec</code> or
33  * <code>X509EncodedKeySpec</code>. A key factory can be used to translate
34  * between compatible key specifications.
35  *
36  * <P> The following is an example of how to use a key factory in order to
37  * instantiate a DSA public key from its encoding.
38  * Assume Alice has received a digital signature from Bob.
39  * Bob also sent her his public key (in encoded format) to verify
40  * his signature. Alice then performs the following actions:
41  *
42  * <pre>
43  * X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
44  * KeyFactory keyFactory = KeyFactory.getInstance("DSA");
45  * PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
46  * Signature sig = Signature.getInstance("DSA");
47  * sig.initVerify(bobPubKey);
48  * sig.update(data);
49  * sig.verify(signature);
50  * </pre>
51  *
52  * @author Jan Luehe
53  *
54  * @version 1.32, 05/05/04
55  *
56  * @see Key
57  * @see PublicKey
58  * @see PrivateKey
59  * @see java.security.spec.KeySpec
60  * @see java.security.spec.DSAPublicKeySpec
61  * @see java.security.spec.X509EncodedKeySpec
62  *
63  * @since 1.2
64  */

65
66 public class KeyFactory {
67
68     private static final Debug debug =
69             Debug.getInstance("jca", "KeyFactory");
70     
71     // The algorithm associated with this key factory
72
private final String JavaDoc algorithm;
73
74     // The provider
75
private Provider JavaDoc provider;
76
77     // The provider implementation (delegate)
78
private volatile KeyFactorySpi JavaDoc spi;
79
80     // lock for mutex during provider selection
81
private final Object JavaDoc lock = new Object JavaDoc();
82
83     // remaining services to try in provider selection
84
// null once provider is selected
85
private Iterator<Service> serviceIterator;
86     
87     /**
88      * Creates a KeyFactory object.
89      *
90      * @param keyFacSpi the delegate
91      * @param provider the provider
92      * @param algorithm the name of the algorithm
93      * to associate with this <tt>KeyFactory</tt>
94      */

95     protected KeyFactory(KeyFactorySpi JavaDoc keyFacSpi, Provider JavaDoc provider,
96              String JavaDoc algorithm) {
97     this.spi = keyFacSpi;
98     this.provider = provider;
99     this.algorithm = algorithm;
100     }
101     
102     private KeyFactory(String JavaDoc algorithm) throws NoSuchAlgorithmException JavaDoc {
103     this.algorithm = algorithm;
104     List<Service> list = GetInstance.getServices("KeyFactory", algorithm);
105     serviceIterator = list.iterator();
106     // fetch and instantiate initial spi
107
if (nextSpi(null) == null) {
108         throw new NoSuchAlgorithmException JavaDoc
109             (algorithm + " KeyFactory not available");
110     }
111     }
112
113     /**
114      * Generates a KeyFactory object that implements the specified
115      * algorithm. If the default provider package
116      * provides an implementation of the requested algorithm,
117      * an instance of KeyFactory containing that implementation is returned.
118      * If the algorithm is not available in the default
119      * package, other packages are searched.
120      *
121      * @param algorithm the name of the requested key algorithm.
122      * See Appendix A in the <a HREF=
123      * "../../../guide/security/CryptoSpec.html#AppA">
124      * Java Cryptography Architecture API Specification &amp; Reference </a>
125      * for information about standard algorithm names.
126      *
127      * @return a KeyFactory object for the specified algorithm.
128      *
129      * @exception NoSuchAlgorithmException if the requested algorithm is
130      * not available in the default provider package or any of the other
131      * provider packages that were searched.
132      */

133     public static KeyFactory JavaDoc getInstance(String JavaDoc algorithm)
134         throws NoSuchAlgorithmException JavaDoc {
135     return new KeyFactory JavaDoc(algorithm);
136     }
137
138     /**
139      * Generates a KeyFactory object for the specified algorithm from the
140      * specified provider.
141      *
142      * @param algorithm the name of the requested key algorithm.
143      * See Appendix A in the <a HREF=
144      * "../../../guide/security/CryptoSpec.html#AppA">
145      * Java Cryptography Architecture API Specification &amp; Reference </a>
146      * for information about standard algorithm names.
147      *
148      * @param provider the name of the provider.
149      *
150      * @return a KeyFactory object for the specified algorithm.
151      *
152      * @exception NoSuchAlgorithmException if the algorithm is
153      * not available from the specified provider.
154      *
155      * @exception NoSuchProviderException if the provider has not been
156      * configured.
157      *
158      * @exception IllegalArgumentException if the provider name is null
159      * or empty.
160      *
161      * @see Provider
162      */

163     public static KeyFactory JavaDoc getInstance(String JavaDoc algorithm, String JavaDoc provider)
164         throws NoSuchAlgorithmException JavaDoc, NoSuchProviderException JavaDoc {
165     Instance instance = GetInstance.getInstance("KeyFactory",
166         KeyFactorySpi JavaDoc.class, algorithm, provider);
167     return new KeyFactory JavaDoc((KeyFactorySpi JavaDoc)instance.impl,
168         instance.provider, algorithm);
169     }
170
171     /**
172      * Generates a KeyFactory object for the specified algorithm from the
173      * specified provider. Note: the <code>provider</code> doesn't have
174      * to be registered.
175      *
176      * @param algorithm the name of the requested key algorithm.
177      * See Appendix A in the <a HREF=
178      * "../../../guide/security/CryptoSpec.html#AppA">
179      * Java Cryptography Architecture API Specification &amp; Reference </a>
180      * for information about standard algorithm names.
181      *
182      * @param provider the provider.
183      *
184      * @return a KeyFactory object for the specified algorithm.
185      *
186      * @exception NoSuchAlgorithmException if the algorithm is
187      * not available from the specified provider.
188      *
189      * @exception IllegalArgumentException if the <code>provider</code> is
190      * null.
191      *
192      * @see Provider
193      *
194      * @since 1.4
195      */

196     public static KeyFactory JavaDoc getInstance(String JavaDoc algorithm, Provider JavaDoc provider)
197         throws NoSuchAlgorithmException JavaDoc {
198     Instance instance = GetInstance.getInstance("KeyFactory",
199         KeyFactorySpi JavaDoc.class, algorithm, provider);
200     return new KeyFactory JavaDoc((KeyFactorySpi JavaDoc)instance.impl,
201         instance.provider, algorithm);
202     }
203
204     /**
205      * Returns the provider of this key factory object.
206      *
207      * @return the provider of this key factory object
208      */

209     public final Provider JavaDoc getProvider() {
210     synchronized (lock) {
211         // disable further failover after this call
212
serviceIterator = null;
213         return provider;
214     }
215     }
216
217     /**
218      * Gets the name of the algorithm
219      * associated with this <tt>KeyFactory</tt>.
220      *
221      * @return the name of the algorithm associated with this
222      * <tt>KeyFactory</tt>
223      */

224     public final String JavaDoc getAlgorithm() {
225     return this.algorithm;
226     }
227
228     /**
229      * Update the active KeyFactorySpi of this class and return the next
230      * implementation for failover. If no more implemenations are
231      * available, this method returns null. However, the active spi of
232      * this class is never set to null.
233      */

234     private KeyFactorySpi JavaDoc nextSpi(KeyFactorySpi JavaDoc oldSpi) {
235     synchronized (lock) {
236         // somebody else did a failover concurrently
237
// try that spi now
238
if ((oldSpi != null) && (oldSpi != spi)) {
239         return spi;
240         }
241         if (serviceIterator == null) {
242         return null;
243         }
244         while (serviceIterator.hasNext()) {
245         Service s = serviceIterator.next();
246         try {
247             Object JavaDoc obj = s.newInstance(null);
248             if (obj instanceof KeyFactorySpi JavaDoc == false) {
249             continue;
250             }
251             KeyFactorySpi JavaDoc spi = (KeyFactorySpi JavaDoc)obj;
252             provider = s.getProvider();
253             this.spi = spi;
254             return spi;
255         } catch (NoSuchAlgorithmException JavaDoc e) {
256             // ignore
257
}
258         }
259         serviceIterator = null;
260         return null;
261     }
262     }
263
264     /**
265      * Generates a public key object from the provided key specification
266      * (key material).
267      *
268      * @param keySpec the specification (key material) of the public key.
269      *
270      * @return the public key.
271      *
272      * @exception InvalidKeySpecException if the given key specification
273      * is inappropriate for this key factory to produce a public key.
274      */

275     public final PublicKey JavaDoc generatePublic(KeySpec JavaDoc keySpec)
276         throws InvalidKeySpecException JavaDoc {
277     if (serviceIterator == null) {
278         return spi.engineGeneratePublic(keySpec);
279     }
280     Exception JavaDoc failure = null;
281     KeyFactorySpi JavaDoc mySpi = spi;
282     do {
283         try {
284         return mySpi.engineGeneratePublic(keySpec);
285         } catch (Exception JavaDoc e) {
286         if (failure == null) {
287             failure = e;
288         }
289         mySpi = nextSpi(mySpi);
290         }
291     } while (mySpi != null);
292     if (failure instanceof RuntimeException JavaDoc) {
293         throw (RuntimeException JavaDoc)failure;
294     }
295     if (failure instanceof InvalidKeySpecException JavaDoc) {
296         throw (InvalidKeySpecException JavaDoc)failure;
297     }
298     throw new InvalidKeySpecException JavaDoc
299         ("Could not generate public key", failure);
300     }
301     
302     /**
303      * Generates a private key object from the provided key specification
304      * (key material).
305      *
306      * @param keySpec the specification (key material) of the private key.
307      *
308      * @return the private key.
309      *
310      * @exception InvalidKeySpecException if the given key specification
311      * is inappropriate for this key factory to produce a private key.
312      */

313     public final PrivateKey JavaDoc generatePrivate(KeySpec JavaDoc keySpec)
314         throws InvalidKeySpecException JavaDoc {
315     if (serviceIterator == null) {
316         return spi.engineGeneratePrivate(keySpec);
317     }
318     Exception JavaDoc failure = null;
319     KeyFactorySpi JavaDoc mySpi = spi;
320     do {
321         try {
322         return mySpi.engineGeneratePrivate(keySpec);
323         } catch (Exception JavaDoc e) {
324         if (failure == null) {
325             failure = e;
326         }
327         mySpi = nextSpi(mySpi);
328         }
329     } while (mySpi != null);
330     if (failure instanceof RuntimeException JavaDoc) {
331         throw (RuntimeException JavaDoc)failure;
332     }
333     if (failure instanceof InvalidKeySpecException JavaDoc) {
334         throw (InvalidKeySpecException JavaDoc)failure;
335     }
336     throw new InvalidKeySpecException JavaDoc
337         ("Could not generate private key", failure);
338     }
339
340     /**
341      * Returns a specification (key material) of the given key object.
342      * <code>keySpec</code> identifies the specification class in which
343      * the key material should be returned. It could, for example, be
344      * <code>DSAPublicKeySpec.class</code>, to indicate that the
345      * key material should be returned in an instance of the
346      * <code>DSAPublicKeySpec</code> class.
347      *
348      * @param key the key.
349      *
350      * @param keySpec the specification class in which
351      * the key material should be returned.
352      *
353      * @return the underlying key specification (key material) in an instance
354      * of the requested specification class.
355      *
356      * @exception InvalidKeySpecException if the requested key specification is
357      * inappropriate for the given key, or the given key cannot be processed
358      * (e.g., the given key has an unrecognized algorithm or format).
359      */

360     public final <T extends KeySpec JavaDoc> T getKeySpec(Key JavaDoc key, Class JavaDoc<T> keySpec)
361         throws InvalidKeySpecException JavaDoc {
362     if (serviceIterator == null) {
363         return spi.engineGetKeySpec(key, keySpec);
364     }
365     Exception JavaDoc failure = null;
366     KeyFactorySpi JavaDoc mySpi = spi;
367     do {
368         try {
369         return mySpi.engineGetKeySpec(key, keySpec);
370         } catch (Exception JavaDoc e) {
371         if (failure == null) {
372             failure = e;
373         }
374         mySpi = nextSpi(mySpi);
375         }
376     } while (mySpi != null);
377     if (failure instanceof RuntimeException JavaDoc) {
378         throw (RuntimeException JavaDoc)failure;
379     }
380     if (failure instanceof InvalidKeySpecException JavaDoc) {
381         throw (InvalidKeySpecException JavaDoc)failure;
382     }
383     throw new InvalidKeySpecException JavaDoc
384         ("Could not get key spec", failure);
385     }
386
387     /**
388      * Translates a key object, whose provider may be unknown or potentially
389      * untrusted, into a corresponding key object of this key factory.
390      *
391      * @param key the key whose provider is unknown or untrusted.
392      *
393      * @return the translated key.
394      *
395      * @exception InvalidKeyException if the given key cannot be processed
396      * by this key factory.
397      */

398     public final Key JavaDoc translateKey(Key JavaDoc key) throws InvalidKeyException JavaDoc {
399     if (serviceIterator == null) {
400         return spi.engineTranslateKey(key);
401     }
402     Exception JavaDoc failure = null;
403     KeyFactorySpi JavaDoc mySpi = spi;
404     do {
405         try {
406         return mySpi.engineTranslateKey(key);
407         } catch (Exception JavaDoc e) {
408         if (failure == null) {
409             failure = e;
410         }
411         mySpi = nextSpi(mySpi);
412         }
413     } while (mySpi != null);
414     if (failure instanceof RuntimeException JavaDoc) {
415         throw (RuntimeException JavaDoc)failure;
416     }
417     if (failure instanceof InvalidKeyException JavaDoc) {
418         throw (InvalidKeyException JavaDoc)failure;
419     }
420     throw new InvalidKeyException JavaDoc
421         ("Could not translate key", failure);
422     }
423
424 }
425
Popular Tags