1 /*
2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4  *
5  *
6  *
7  *
8  *
9  *
10  *
11  *
12  *
13  *
14  *
15  *
16  *
17  *
18  *
19  *
20  *
21  *
22  *
23  *
24  */

25
26 package java.security;
27
28 import java.util.*;
29
30 import java.security.Provider.Service;
31 import java.security.spec.KeySpec;
32 import java.security.spec.InvalidKeySpecException;
33
34 import sun.security.util.Debug;
35 import sun.security.jca.*;
36 import sun.security.jca.GetInstance.Instance;
37
38 /**
39  * Key factories are used to convert <I>keys</I> (opaque
40  * cryptographic keys of type {@code Key}) into <I>key specifications</I>
41  * (transparent representations of the underlying key material), and vice
42  * versa.
43  *
44  * <P> Key factories are bi-directional. That is, they allow you to build an
45  * opaque key object from a given key specification (key material), or to
46  * retrieve the underlying key material of a key object in a suitable format.
47  *
48  * <P> Multiple compatible key specifications may exist for the same key.
49  * For example, a DSA public key may be specified using
50  * {@code DSAPublicKeySpec} or
51  * {@code X509EncodedKeySpec}. A key factory can be used to translate
52  * between compatible key specifications.
53  *
54  * <P> The following is an example of how to use a key factory in order to
55  * instantiate a DSA public key from its encoding.
56  * Assume Alice has received a digital signature from Bob.
57  * Bob also sent her his public key (in encoded format) to verify
58  * his signature. Alice then performs the following actions:
59  *
60  * <pre>
61  * X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
62  * KeyFactory keyFactory = KeyFactory.getInstance("DSA");
63  * PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
64  * Signature sig = Signature.getInstance("DSA");
65  * sig.initVerify(bobPubKey);
66  * sig.update(data);
67  * sig.verify(signature);
68  * </pre>
69  *
70  * <p> Every implementation of the Java platform is required to support the
71  * following standard {@code KeyFactory} algorithms:
72  * <ul>
73  * <li>{@code DiffieHellman}</li>
74  * <li>{@code DSA}</li>
75  * <li>{@code RSA}</li>
76  * </ul>
77  * These algorithms are described in the <a href=
78  * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
79  * KeyFactory section</a> of the
80  * Java Cryptography Architecture Standard Algorithm Name Documentation.
81  * Consult the release documentation for your implementation to see if any
82  * other algorithms are supported.
83  *
84  * @author Jan Luehe
85  *
86  * @see Key
87  * @see PublicKey
88  * @see PrivateKey
89  * @see java.security.spec.KeySpec
90  * @see java.security.spec.DSAPublicKeySpec
91  * @see java.security.spec.X509EncodedKeySpec
92  *
93  * @since 1.2
94  */

95
96 public class KeyFactory {
97
98     private static final Debug debug =
99                         Debug.getInstance("jca""KeyFactory");
100
101     // The algorithm associated with this key factory
102     private final String algorithm;
103
104     // The provider
105     private Provider provider;
106
107     // The provider implementation (delegate)
108     private volatile KeyFactorySpi spi;
109
110     // lock for mutex during provider selection
111     private final Object lock = new Object();
112
113     // remaining services to try in provider selection
114     // null once provider is selected
115     private Iterator<Service> serviceIterator;
116
117     /**
118      * Creates a KeyFactory object.
119      *
120      * @param keyFacSpi the delegate
121      * @param provider the provider
122      * @param algorithm the name of the algorithm
123      * to associate with this {@code KeyFactory}
124      */

125     protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider,
126                          String algorithm) {
127         this.spi = keyFacSpi;
128         this.provider = provider;
129         this.algorithm = algorithm;
130     }
131
132     private KeyFactory(String algorithm) throws NoSuchAlgorithmException {
133         this.algorithm = algorithm;
134         List<Service> list = GetInstance.getServices("KeyFactory", algorithm);
135         serviceIterator = list.iterator();
136         // fetch and instantiate initial spi
137         if (nextSpi(null) == null) {
138             throw new NoSuchAlgorithmException
139                 (algorithm + " KeyFactory not available");
140         }
141     }
142
143     /**
144      * Returns a KeyFactory object that converts
145      * public/private keys of the specified algorithm.
146      *
147      * <p> This method traverses the list of registered security Providers,
148      * starting with the most preferred Provider.
149      * A new KeyFactory object encapsulating the
150      * KeyFactorySpi implementation from the first
151      * Provider that supports the specified algorithm is returned.
152      *
153      * <p> Note that the list of registered providers may be retrieved via
154      * the {@link Security#getProviders() Security.getProviders()} method.
155      *
156      * @param algorithm the name of the requested key algorithm.
157      * See the KeyFactory section in the <a href=
158      * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
159      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
160      * for information about standard algorithm names.
161      *
162      * @return the new KeyFactory object.
163      *
164      * @exception NoSuchAlgorithmException if no Provider supports a
165      *          KeyFactorySpi implementation for the
166      *          specified algorithm.
167      *
168      * @see Provider
169      */

170     public static KeyFactory getInstance(String algorithm)
171             throws NoSuchAlgorithmException {
172         return new KeyFactory(algorithm);
173     }
174
175     /**
176      * Returns a KeyFactory object that converts
177      * public/private keys of the specified algorithm.
178      *
179      * <p> A new KeyFactory object encapsulating the
180      * KeyFactorySpi implementation from the specified provider
181      * is returned.  The specified provider must be registered
182      * in the security provider list.
183      *
184      * <p> Note that the list of registered providers may be retrieved via
185      * the {@link Security#getProviders() Security.getProviders()} method.
186      *
187      * @param algorithm the name of the requested key algorithm.
188      * See the KeyFactory section in the <a href=
189      * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
190      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
191      * for information about standard algorithm names.
192      *
193      * @param provider the name of the provider.
194      *
195      * @return the new KeyFactory object.
196      *
197      * @exception NoSuchAlgorithmException if a KeyFactorySpi
198      *          implementation for the specified algorithm is not
199      *          available from the specified provider.
200      *
201      * @exception NoSuchProviderException if the specified provider is not
202      *          registered in the security provider list.
203      *
204      * @exception IllegalArgumentException if the provider name is null
205      *          or empty.
206      *
207      * @see Provider
208      */

209     public static KeyFactory getInstance(String algorithm, String provider)
210             throws NoSuchAlgorithmException, NoSuchProviderException {
211         Instance instance = GetInstance.getInstance("KeyFactory",
212             KeyFactorySpi.class, algorithm, provider);
213         return new KeyFactory((KeyFactorySpi)instance.impl,
214             instance.provider, algorithm);
215     }
216
217     /**
218      * Returns a KeyFactory object that converts
219      * public/private keys of the specified algorithm.
220      *
221      * <p> A new KeyFactory object encapsulating the
222      * KeyFactorySpi implementation from the specified Provider
223      * object is returned.  Note that the specified Provider object
224      * does not have to be registered in the provider list.
225      *
226      * @param algorithm the name of the requested key algorithm.
227      * See the KeyFactory section in the <a href=
228      * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
229      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
230      * for information about standard algorithm names.
231      *
232      * @param provider the provider.
233      *
234      * @return the new KeyFactory object.
235      *
236      * @exception NoSuchAlgorithmException if a KeyFactorySpi
237      *          implementation for the specified algorithm is not available
238      *          from the specified Provider object.
239      *
240      * @exception IllegalArgumentException if the specified provider is null.
241      *
242      * @see Provider
243      *
244      * @since 1.4
245      */

246     public static KeyFactory getInstance(String algorithm, Provider provider)
247             throws NoSuchAlgorithmException {
248         Instance instance = GetInstance.getInstance("KeyFactory",
249             KeyFactorySpi.class, algorithm, provider);
250         return new KeyFactory((KeyFactorySpi)instance.impl,
251             instance.provider, algorithm);
252     }
253
254     /**
255      * Returns the provider of this key factory object.
256      *
257      * @return the provider of this key factory object
258      */

259     public final Provider getProvider() {
260         synchronized (lock) {
261             // disable further failover after this call
262             serviceIterator = null;
263             return provider;
264         }
265     }
266
267     /**
268      * Gets the name of the algorithm
269      * associated with this {@code KeyFactory}.
270      *
271      * @return the name of the algorithm associated with this
272      * {@code KeyFactory}
273      */

274     public final String getAlgorithm() {
275         return this.algorithm;
276     }
277
278     /**
279      * Update the active KeyFactorySpi of this class and return the next
280      * implementation for failover. If no more implemenations are
281      * available, this method returns null. However, the active spi of
282      * this class is never set to null.
283      */

284     private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {
285         synchronized (lock) {
286             // somebody else did a failover concurrently
287             // try that spi now
288             if ((oldSpi != null) && (oldSpi != spi)) {
289                 return spi;
290             }
291             if (serviceIterator == null) {
292                 return null;
293             }
294             while (serviceIterator.hasNext()) {
295                 Service s = serviceIterator.next();
296                 try {
297                     Object obj = s.newInstance(null);
298                     if (obj instanceof KeyFactorySpi == false) {
299                         continue;
300                     }
301                     KeyFactorySpi spi = (KeyFactorySpi)obj;
302                     provider = s.getProvider();
303                     this.spi = spi;
304                     return spi;
305                 } catch (NoSuchAlgorithmException e) {
306                     // ignore
307                 }
308             }
309             serviceIterator = null;
310             return null;
311         }
312     }
313
314     /**
315      * Generates a public key object from the provided key specification
316      * (key material).
317      *
318      * @param keySpec the specification (key material) of the public key.
319      *
320      * @return the public key.
321      *
322      * @exception InvalidKeySpecException if the given key specification
323      * is inappropriate for this key factory to produce a public key.
324      */

325     public final PublicKey generatePublic(KeySpec keySpec)
326             throws InvalidKeySpecException {
327         if (serviceIterator == null) {
328             return spi.engineGeneratePublic(keySpec);
329         }
330         Exception failure = null;
331         KeyFactorySpi mySpi = spi;
332         do {
333             try {
334                 return mySpi.engineGeneratePublic(keySpec);
335             } catch (Exception e) {
336                 if (failure == null) {
337                     failure = e;
338                 }
339                 mySpi = nextSpi(mySpi);
340             }
341         } while (mySpi != null);
342         if (failure instanceof RuntimeException) {
343             throw (RuntimeException)failure;
344         }
345         if (failure instanceof InvalidKeySpecException) {
346             throw (InvalidKeySpecException)failure;
347         }
348         throw new InvalidKeySpecException
349                 ("Could not generate public key", failure);
350     }
351
352     /**
353      * Generates a private key object from the provided key specification
354      * (key material).
355      *
356      * @param keySpec the specification (key material) of the private key.
357      *
358      * @return the private key.
359      *
360      * @exception InvalidKeySpecException if the given key specification
361      * is inappropriate for this key factory to produce a private key.
362      */

363     public final PrivateKey generatePrivate(KeySpec keySpec)
364             throws InvalidKeySpecException {
365         if (serviceIterator == null) {
366             return spi.engineGeneratePrivate(keySpec);
367         }
368         Exception failure = null;
369         KeyFactorySpi mySpi = spi;
370         do {
371             try {
372                 return mySpi.engineGeneratePrivate(keySpec);
373             } catch (Exception e) {
374                 if (failure == null) {
375                     failure = e;
376                 }
377                 mySpi = nextSpi(mySpi);
378             }
379         } while (mySpi != null);
380         if (failure instanceof RuntimeException) {
381             throw (RuntimeException)failure;
382         }
383         if (failure instanceof InvalidKeySpecException) {
384             throw (InvalidKeySpecException)failure;
385         }
386         throw new InvalidKeySpecException
387                 ("Could not generate private key", failure);
388     }
389
390     /**
391      * Returns a specification (key material) of the given key object.
392      * {@code keySpec} identifies the specification class in which
393      * the key material should be returned. It could, for example, be
394      * {@code DSAPublicKeySpec.class}, to indicate that the
395      * key material should be returned in an instance of the
396      * {@code DSAPublicKeySpec} class.
397      *
398      * @param <T> the type of the key specification to be returned
399      *
400      * @param key the key.
401      *
402      * @param keySpec the specification class in which
403      * the key material should be returned.
404      *
405      * @return the underlying key specification (key material) in an instance
406      * of the requested specification class.
407      *
408      * @exception InvalidKeySpecException if the requested key specification is
409      * inappropriate for the given key, or the given key cannot be processed
410      * (e.g., the given key has an unrecognized algorithm or format).
411      */

412     public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
413             throws InvalidKeySpecException {
414         if (serviceIterator == null) {
415             return spi.engineGetKeySpec(key, keySpec);
416         }
417         Exception failure = null;
418         KeyFactorySpi mySpi = spi;
419         do {
420             try {
421                 return mySpi.engineGetKeySpec(key, keySpec);
422             } catch (Exception e) {
423                 if (failure == null) {
424                     failure = e;
425                 }
426                 mySpi = nextSpi(mySpi);
427             }
428         } while (mySpi != null);
429         if (failure instanceof RuntimeException) {
430             throw (RuntimeException)failure;
431         }
432         if (failure instanceof InvalidKeySpecException) {
433             throw (InvalidKeySpecException)failure;
434         }
435         throw new InvalidKeySpecException
436                 ("Could not get key spec", failure);
437     }
438
439     /**
440      * Translates a key object, whose provider may be unknown or potentially
441      * untrusted, into a corresponding key object of this key factory.
442      *
443      * @param key the key whose provider is unknown or untrusted.
444      *
445      * @return the translated key.
446      *
447      * @exception InvalidKeyException if the given key cannot be processed
448      * by this key factory.
449      */

450     public final Key translateKey(Key key) throws InvalidKeyException {
451         if (serviceIterator == null) {
452             return spi.engineTranslateKey(key);
453         }
454         Exception failure = null;
455         KeyFactorySpi mySpi = spi;
456         do {
457             try {
458                 return mySpi.engineTranslateKey(key);
459             } catch (Exception e) {
460                 if (failure == null) {
461                     failure = e;
462                 }
463                 mySpi = nextSpi(mySpi);
464             }
465         } while (mySpi != null);
466         if (failure instanceof RuntimeException) {
467             throw (RuntimeException)failure;
468         }
469         if (failure instanceof InvalidKeyException) {
470             throw (InvalidKeyException)failure;
471         }
472         throw new InvalidKeyException
473                 ("Could not translate key", failure);
474     }
475
476 }
477
Powered by JavaMelody