001 /*
002 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.security;
027
028 import java.util.*;
029
030 import java.security.Provider.Service;
031 import java.security.spec.KeySpec;
032 import java.security.spec.InvalidKeySpecException;
033
034 import sun.security.util.Debug;
035 import sun.security.jca.*;
036 import sun.security.jca.GetInstance.Instance;
037
038 /**
039 * Key factories are used to convert <I>keys</I> (opaque
040 * cryptographic keys of type <code>Key</code>) into <I>key specifications</I>
041 * (transparent representations of the underlying key material), and vice
042 * versa.
043 *
044 * <P> Key factories are bi-directional. That is, they allow you to build an
045 * opaque key object from a given key specification (key material), or to
046 * retrieve the underlying key material of a key object in a suitable format.
047 *
048 * <P> Multiple compatible key specifications may exist for the same key.
049 * For example, a DSA public key may be specified using
050 * <code>DSAPublicKeySpec</code> or
051 * <code>X509EncodedKeySpec</code>. A key factory can be used to translate
052 * between compatible key specifications.
053 *
054 * <P> The following is an example of how to use a key factory in order to
055 * instantiate a DSA public key from its encoding.
056 * Assume Alice has received a digital signature from Bob.
057 * Bob also sent her his public key (in encoded format) to verify
058 * his signature. Alice then performs the following actions:
059 *
060 * <pre>
061 * X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
062 * KeyFactory keyFactory = KeyFactory.getInstance("DSA");
063 * PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
064 * Signature sig = Signature.getInstance("DSA");
065 * sig.initVerify(bobPubKey);
066 * sig.update(data);
067 * sig.verify(signature);
068 * </pre>
069 *
070 * @author Jan Luehe
071 *
072 * @version 1.41, 05/05/07
073 *
074 * @see Key
075 * @see PublicKey
076 * @see PrivateKey
077 * @see java.security.spec.KeySpec
078 * @see java.security.spec.DSAPublicKeySpec
079 * @see java.security.spec.X509EncodedKeySpec
080 *
081 * @since 1.2
082 */
083
084 public class KeyFactory {
085
086 private static final Debug debug = Debug.getInstance("jca",
087 "KeyFactory");
088
089 // The algorithm associated with this key factory
090 private final String algorithm;
091
092 // The provider
093 private Provider provider;
094
095 // The provider implementation (delegate)
096 private volatile KeyFactorySpi spi;
097
098 // lock for mutex during provider selection
099 private final Object lock = new Object();
100
101 // remaining services to try in provider selection
102 // null once provider is selected
103 private Iterator<Service> serviceIterator;
104
105 /**
106 * Creates a KeyFactory object.
107 *
108 * @param keyFacSpi the delegate
109 * @param provider the provider
110 * @param algorithm the name of the algorithm
111 * to associate with this <tt>KeyFactory</tt>
112 */
113 protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider,
114 String algorithm) {
115 this .spi = keyFacSpi;
116 this .provider = provider;
117 this .algorithm = algorithm;
118 }
119
120 private KeyFactory(String algorithm)
121 throws NoSuchAlgorithmException {
122 this .algorithm = algorithm;
123 List<Service> list = GetInstance.getServices("KeyFactory",
124 algorithm);
125 serviceIterator = list.iterator();
126 // fetch and instantiate initial spi
127 if (nextSpi(null) == null) {
128 throw new NoSuchAlgorithmException(algorithm
129 + " KeyFactory not available");
130 }
131 }
132
133 /**
134 * Returns a KeyFactory object that converts
135 * public/private keys of the specified algorithm.
136 *
137 * <p> This method traverses the list of registered security Providers,
138 * starting with the most preferred Provider.
139 * A new KeyFactory object encapsulating the
140 * KeyFactorySpi implementation from the first
141 * Provider that supports the specified algorithm is returned.
142 *
143 * <p> Note that the list of registered providers may be retrieved via
144 * the {@link Security#getProviders() Security.getProviders()} method.
145 *
146 * @param algorithm the name of the requested key algorithm.
147 * See Appendix A in the <a href=
148 * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
149 * Java Cryptography Architecture API Specification & Reference </a>
150 * for information about standard algorithm names.
151 *
152 * @return the new KeyFactory object.
153 *
154 * @exception NoSuchAlgorithmException if no Provider supports a
155 * KeyFactorySpi implementation for the
156 * specified algorithm.
157 *
158 * @see Provider
159 */
160 public static KeyFactory getInstance(String algorithm)
161 throws NoSuchAlgorithmException {
162 return new KeyFactory(algorithm);
163 }
164
165 /**
166 * Returns a KeyFactory object that converts
167 * public/private keys of the specified algorithm.
168 *
169 * <p> A new KeyFactory object encapsulating the
170 * KeyFactorySpi implementation from the specified provider
171 * is returned. The specified provider must be registered
172 * in the security provider list.
173 *
174 * <p> Note that the list of registered providers may be retrieved via
175 * the {@link Security#getProviders() Security.getProviders()} method.
176 *
177 * @param algorithm the name of the requested key algorithm.
178 * See Appendix A in the <a href=
179 * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
180 * Java Cryptography Architecture API Specification & Reference </a>
181 * for information about standard algorithm names.
182 *
183 * @param provider the name of the provider.
184 *
185 * @return the new KeyFactory object.
186 *
187 * @exception NoSuchAlgorithmException if a KeyFactorySpi
188 * implementation for the specified algorithm is not
189 * available from the specified provider.
190 *
191 * @exception NoSuchProviderException if the specified provider is not
192 * registered in the security provider list.
193 *
194 * @exception IllegalArgumentException if the provider name is null
195 * or empty.
196 *
197 * @see Provider
198 */
199 public static KeyFactory getInstance(String algorithm,
200 String provider) throws NoSuchAlgorithmException,
201 NoSuchProviderException {
202 Instance instance = GetInstance.getInstance("KeyFactory",
203 KeyFactorySpi.class, algorithm, provider);
204 return new KeyFactory((KeyFactorySpi) instance.impl,
205 instance.provider, algorithm);
206 }
207
208 /**
209 * Returns a KeyFactory object that converts
210 * public/private keys of the specified algorithm.
211 *
212 * <p> A new KeyFactory object encapsulating the
213 * KeyFactorySpi implementation from the specified Provider
214 * object is returned. Note that the specified Provider object
215 * does not have to be registered in the provider list.
216 *
217 * @param algorithm the name of the requested key algorithm.
218 * See Appendix A in the <a href=
219 * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
220 * Java Cryptography Architecture API Specification & Reference </a>
221 * for information about standard algorithm names.
222 *
223 * @param provider the provider.
224 *
225 * @return the new KeyFactory object.
226 *
227 * @exception NoSuchAlgorithmException if a KeyFactorySpi
228 * implementation for the specified algorithm is not available
229 * from the specified Provider object.
230 *
231 * @exception IllegalArgumentException if the specified provider is null.
232 *
233 * @see Provider
234 *
235 * @since 1.4
236 */
237 public static KeyFactory getInstance(String algorithm,
238 Provider provider) throws NoSuchAlgorithmException {
239 Instance instance = GetInstance.getInstance("KeyFactory",
240 KeyFactorySpi.class, algorithm, provider);
241 return new KeyFactory((KeyFactorySpi) instance.impl,
242 instance.provider, algorithm);
243 }
244
245 /**
246 * Returns the provider of this key factory object.
247 *
248 * @return the provider of this key factory object
249 */
250 public final Provider getProvider() {
251 synchronized (lock) {
252 // disable further failover after this call
253 serviceIterator = null;
254 return provider;
255 }
256 }
257
258 /**
259 * Gets the name of the algorithm
260 * associated with this <tt>KeyFactory</tt>.
261 *
262 * @return the name of the algorithm associated with this
263 * <tt>KeyFactory</tt>
264 */
265 public final String getAlgorithm() {
266 return this .algorithm;
267 }
268
269 /**
270 * Update the active KeyFactorySpi of this class and return the next
271 * implementation for failover. If no more implemenations are
272 * available, this method returns null. However, the active spi of
273 * this class is never set to null.
274 */
275 private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {
276 synchronized (lock) {
277 // somebody else did a failover concurrently
278 // try that spi now
279 if ((oldSpi != null) && (oldSpi != spi)) {
280 return spi;
281 }
282 if (serviceIterator == null) {
283 return null;
284 }
285 while (serviceIterator.hasNext()) {
286 Service s = serviceIterator.next();
287 try {
288 Object obj = s.newInstance(null);
289 if (obj instanceof KeyFactorySpi == false) {
290 continue;
291 }
292 KeyFactorySpi spi = (KeyFactorySpi) obj;
293 provider = s.getProvider();
294 this .spi = spi;
295 return spi;
296 } catch (NoSuchAlgorithmException e) {
297 // ignore
298 }
299 }
300 serviceIterator = null;
301 return null;
302 }
303 }
304
305 /**
306 * Generates a public key object from the provided key specification
307 * (key material).
308 *
309 * @param keySpec the specification (key material) of the public key.
310 *
311 * @return the public key.
312 *
313 * @exception InvalidKeySpecException if the given key specification
314 * is inappropriate for this key factory to produce a public key.
315 */
316 public final PublicKey generatePublic(KeySpec keySpec)
317 throws InvalidKeySpecException {
318 if (serviceIterator == null) {
319 return spi.engineGeneratePublic(keySpec);
320 }
321 Exception failure = null;
322 KeyFactorySpi mySpi = spi;
323 do {
324 try {
325 return mySpi.engineGeneratePublic(keySpec);
326 } catch (Exception e) {
327 if (failure == null) {
328 failure = e;
329 }
330 mySpi = nextSpi(mySpi);
331 }
332 } while (mySpi != null);
333 if (failure instanceof RuntimeException) {
334 throw (RuntimeException) failure;
335 }
336 if (failure instanceof InvalidKeySpecException) {
337 throw (InvalidKeySpecException) failure;
338 }
339 throw new InvalidKeySpecException(
340 "Could not generate public key", failure);
341 }
342
343 /**
344 * Generates a private key object from the provided key specification
345 * (key material).
346 *
347 * @param keySpec the specification (key material) of the private key.
348 *
349 * @return the private key.
350 *
351 * @exception InvalidKeySpecException if the given key specification
352 * is inappropriate for this key factory to produce a private key.
353 */
354 public final PrivateKey generatePrivate(KeySpec keySpec)
355 throws InvalidKeySpecException {
356 if (serviceIterator == null) {
357 return spi.engineGeneratePrivate(keySpec);
358 }
359 Exception failure = null;
360 KeyFactorySpi mySpi = spi;
361 do {
362 try {
363 return mySpi.engineGeneratePrivate(keySpec);
364 } catch (Exception e) {
365 if (failure == null) {
366 failure = e;
367 }
368 mySpi = nextSpi(mySpi);
369 }
370 } while (mySpi != null);
371 if (failure instanceof RuntimeException) {
372 throw (RuntimeException) failure;
373 }
374 if (failure instanceof InvalidKeySpecException) {
375 throw (InvalidKeySpecException) failure;
376 }
377 throw new InvalidKeySpecException(
378 "Could not generate private key", failure);
379 }
380
381 /**
382 * Returns a specification (key material) of the given key object.
383 * <code>keySpec</code> identifies the specification class in which
384 * the key material should be returned. It could, for example, be
385 * <code>DSAPublicKeySpec.class</code>, to indicate that the
386 * key material should be returned in an instance of the
387 * <code>DSAPublicKeySpec</code> class.
388 *
389 * @param key the key.
390 *
391 * @param keySpec the specification class in which
392 * the key material should be returned.
393 *
394 * @return the underlying key specification (key material) in an instance
395 * of the requested specification class.
396 *
397 * @exception InvalidKeySpecException if the requested key specification is
398 * inappropriate for the given key, or the given key cannot be processed
399 * (e.g., the given key has an unrecognized algorithm or format).
400 */
401 public final <T extends KeySpec> T getKeySpec(Key key,
402 Class<T> keySpec) throws InvalidKeySpecException {
403 if (serviceIterator == null) {
404 return spi.engineGetKeySpec(key, keySpec);
405 }
406 Exception failure = null;
407 KeyFactorySpi mySpi = spi;
408 do {
409 try {
410 return mySpi.engineGetKeySpec(key, keySpec);
411 } catch (Exception e) {
412 if (failure == null) {
413 failure = e;
414 }
415 mySpi = nextSpi(mySpi);
416 }
417 } while (mySpi != null);
418 if (failure instanceof RuntimeException) {
419 throw (RuntimeException) failure;
420 }
421 if (failure instanceof InvalidKeySpecException) {
422 throw (InvalidKeySpecException) failure;
423 }
424 throw new InvalidKeySpecException("Could not get key spec",
425 failure);
426 }
427
428 /**
429 * Translates a key object, whose provider may be unknown or potentially
430 * untrusted, into a corresponding key object of this key factory.
431 *
432 * @param key the key whose provider is unknown or untrusted.
433 *
434 * @return the translated key.
435 *
436 * @exception InvalidKeyException if the given key cannot be processed
437 * by this key factory.
438 */
439 public final Key translateKey(Key key) throws InvalidKeyException {
440 if (serviceIterator == null) {
441 return spi.engineTranslateKey(key);
442 }
443 Exception failure = null;
444 KeyFactorySpi mySpi = spi;
445 do {
446 try {
447 return mySpi.engineTranslateKey(key);
448 } catch (Exception e) {
449 if (failure == null) {
450 failure = e;
451 }
452 mySpi = nextSpi(mySpi);
453 }
454 } while (mySpi != null);
455 if (failure instanceof RuntimeException) {
456 throw (RuntimeException) failure;
457 }
458 if (failure instanceof InvalidKeyException) {
459 throw (InvalidKeyException) failure;
460 }
461 throw new InvalidKeyException("Could not translate key",
462 failure);
463 }
464
465 }
|