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. package java.security;
  8. import java.util.*;
  9. import java.security.Provider.Service;
  10. import java.security.spec.KeySpec;
  11. import java.security.spec.InvalidKeySpecException;
  12. import sun.security.util.Debug;
  13. import sun.security.jca.*;
  14. import sun.security.jca.GetInstance.Instance;
  15. /**
  16. * Key factories are used to convert <I>keys</I> (opaque
  17. * cryptographic keys of type <code>Key</code>) into <I>key specifications</I>
  18. * (transparent representations of the underlying key material), and vice
  19. * versa.
  20. *
  21. * <P> Key factories are bi-directional. That is, they allow you to build an
  22. * opaque key object from a given key specification (key material), or to
  23. * retrieve the underlying key material of a key object in a suitable format.
  24. *
  25. * <P> Multiple compatible key specifications may exist for the same key.
  26. * For example, a DSA public key may be specified using
  27. * <code>DSAPublicKeySpec</code> or
  28. * <code>X509EncodedKeySpec</code>. A key factory can be used to translate
  29. * between compatible key specifications.
  30. *
  31. * <P> The following is an example of how to use a key factory in order to
  32. * instantiate a DSA public key from its encoding.
  33. * Assume Alice has received a digital signature from Bob.
  34. * Bob also sent her his public key (in encoded format) to verify
  35. * his signature. Alice then performs the following actions:
  36. *
  37. * <pre>
  38. * X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
  39. * KeyFactory keyFactory = KeyFactory.getInstance("DSA");
  40. * PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
  41. * Signature sig = Signature.getInstance("DSA");
  42. * sig.initVerify(bobPubKey);
  43. * sig.update(data);
  44. * sig.verify(signature);
  45. * </pre>
  46. *
  47. * @author Jan Luehe
  48. *
  49. * @version 1.32, 05/05/04
  50. *
  51. * @see Key
  52. * @see PublicKey
  53. * @see PrivateKey
  54. * @see java.security.spec.KeySpec
  55. * @see java.security.spec.DSAPublicKeySpec
  56. * @see java.security.spec.X509EncodedKeySpec
  57. *
  58. * @since 1.2
  59. */
  60. public class KeyFactory {
  61. private static final Debug debug =
  62. Debug.getInstance("jca", "KeyFactory");
  63. // The algorithm associated with this key factory
  64. private final String algorithm;
  65. // The provider
  66. private Provider provider;
  67. // The provider implementation (delegate)
  68. private volatile KeyFactorySpi spi;
  69. // lock for mutex during provider selection
  70. private final Object lock = new Object();
  71. // remaining services to try in provider selection
  72. // null once provider is selected
  73. private Iterator<Service> serviceIterator;
  74. /**
  75. * Creates a KeyFactory object.
  76. *
  77. * @param keyFacSpi the delegate
  78. * @param provider the provider
  79. * @param algorithm the name of the algorithm
  80. * to associate with this <tt>KeyFactory</tt>
  81. */
  82. protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider,
  83. String algorithm) {
  84. this.spi = keyFacSpi;
  85. this.provider = provider;
  86. this.algorithm = algorithm;
  87. }
  88. private KeyFactory(String algorithm) throws NoSuchAlgorithmException {
  89. this.algorithm = algorithm;
  90. List<Service> list = GetInstance.getServices("KeyFactory", algorithm);
  91. serviceIterator = list.iterator();
  92. // fetch and instantiate initial spi
  93. if (nextSpi(null) == null) {
  94. throw new NoSuchAlgorithmException
  95. (algorithm + " KeyFactory not available");
  96. }
  97. }
  98. /**
  99. * Generates a KeyFactory object that implements the specified
  100. * algorithm. If the default provider package
  101. * provides an implementation of the requested algorithm,
  102. * an instance of KeyFactory containing that implementation is returned.
  103. * If the algorithm is not available in the default
  104. * package, other packages are searched.
  105. *
  106. * @param algorithm the name of the requested key algorithm.
  107. * See Appendix A in the <a href=
  108. * "../../../guide/security/CryptoSpec.html#AppA">
  109. * Java Cryptography Architecture API Specification & Reference </a>
  110. * for information about standard algorithm names.
  111. *
  112. * @return a KeyFactory object for the specified algorithm.
  113. *
  114. * @exception NoSuchAlgorithmException if the requested algorithm is
  115. * not available in the default provider package or any of the other
  116. * provider packages that were searched.
  117. */
  118. public static KeyFactory getInstance(String algorithm)
  119. throws NoSuchAlgorithmException {
  120. return new KeyFactory(algorithm);
  121. }
  122. /**
  123. * Generates a KeyFactory object for the specified algorithm from the
  124. * specified provider.
  125. *
  126. * @param algorithm the name of the requested key algorithm.
  127. * See Appendix A in the <a href=
  128. * "../../../guide/security/CryptoSpec.html#AppA">
  129. * Java Cryptography Architecture API Specification & Reference </a>
  130. * for information about standard algorithm names.
  131. *
  132. * @param provider the name of the provider.
  133. *
  134. * @return a KeyFactory object for the specified algorithm.
  135. *
  136. * @exception NoSuchAlgorithmException if the algorithm is
  137. * not available from the specified provider.
  138. *
  139. * @exception NoSuchProviderException if the provider has not been
  140. * configured.
  141. *
  142. * @exception IllegalArgumentException if the provider name is null
  143. * or empty.
  144. *
  145. * @see Provider
  146. */
  147. public static KeyFactory getInstance(String algorithm, String provider)
  148. throws NoSuchAlgorithmException, NoSuchProviderException {
  149. Instance instance = GetInstance.getInstance("KeyFactory",
  150. KeyFactorySpi.class, algorithm, provider);
  151. return new KeyFactory((KeyFactorySpi)instance.impl,
  152. instance.provider, algorithm);
  153. }
  154. /**
  155. * Generates a KeyFactory object for the specified algorithm from the
  156. * specified provider. Note: the <code>provider</code> doesn't have
  157. * to be registered.
  158. *
  159. * @param algorithm the name of the requested key algorithm.
  160. * See Appendix A in the <a href=
  161. * "../../../guide/security/CryptoSpec.html#AppA">
  162. * Java Cryptography Architecture API Specification & Reference </a>
  163. * for information about standard algorithm names.
  164. *
  165. * @param provider the provider.
  166. *
  167. * @return a KeyFactory object for the specified algorithm.
  168. *
  169. * @exception NoSuchAlgorithmException if the algorithm is
  170. * not available from the specified provider.
  171. *
  172. * @exception IllegalArgumentException if the <code>provider</code> is
  173. * null.
  174. *
  175. * @see Provider
  176. *
  177. * @since 1.4
  178. */
  179. public static KeyFactory getInstance(String algorithm, Provider provider)
  180. throws NoSuchAlgorithmException {
  181. Instance instance = GetInstance.getInstance("KeyFactory",
  182. KeyFactorySpi.class, algorithm, provider);
  183. return new KeyFactory((KeyFactorySpi)instance.impl,
  184. instance.provider, algorithm);
  185. }
  186. /**
  187. * Returns the provider of this key factory object.
  188. *
  189. * @return the provider of this key factory object
  190. */
  191. public final Provider getProvider() {
  192. synchronized (lock) {
  193. // disable further failover after this call
  194. serviceIterator = null;
  195. return provider;
  196. }
  197. }
  198. /**
  199. * Gets the name of the algorithm
  200. * associated with this <tt>KeyFactory</tt>.
  201. *
  202. * @return the name of the algorithm associated with this
  203. * <tt>KeyFactory</tt>
  204. */
  205. public final String getAlgorithm() {
  206. return this.algorithm;
  207. }
  208. /**
  209. * Update the active KeyFactorySpi of this class and return the next
  210. * implementation for failover. If no more implemenations are
  211. * available, this method returns null. However, the active spi of
  212. * this class is never set to null.
  213. */
  214. private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {
  215. synchronized (lock) {
  216. // somebody else did a failover concurrently
  217. // try that spi now
  218. if ((oldSpi != null) && (oldSpi != spi)) {
  219. return spi;
  220. }
  221. if (serviceIterator == null) {
  222. return null;
  223. }
  224. while (serviceIterator.hasNext()) {
  225. Service s = serviceIterator.next();
  226. try {
  227. Object obj = s.newInstance(null);
  228. if (obj instanceof KeyFactorySpi == false) {
  229. continue;
  230. }
  231. KeyFactorySpi spi = (KeyFactorySpi)obj;
  232. provider = s.getProvider();
  233. this.spi = spi;
  234. return spi;
  235. } catch (NoSuchAlgorithmException e) {
  236. // ignore
  237. }
  238. }
  239. serviceIterator = null;
  240. return null;
  241. }
  242. }
  243. /**
  244. * Generates a public key object from the provided key specification
  245. * (key material).
  246. *
  247. * @param keySpec the specification (key material) of the public key.
  248. *
  249. * @return the public key.
  250. *
  251. * @exception InvalidKeySpecException if the given key specification
  252. * is inappropriate for this key factory to produce a public key.
  253. */
  254. public final PublicKey generatePublic(KeySpec keySpec)
  255. throws InvalidKeySpecException {
  256. if (serviceIterator == null) {
  257. return spi.engineGeneratePublic(keySpec);
  258. }
  259. Exception failure = null;
  260. KeyFactorySpi mySpi = spi;
  261. do {
  262. try {
  263. return mySpi.engineGeneratePublic(keySpec);
  264. } catch (Exception e) {
  265. if (failure == null) {
  266. failure = e;
  267. }
  268. mySpi = nextSpi(mySpi);
  269. }
  270. } while (mySpi != null);
  271. if (failure instanceof RuntimeException) {
  272. throw (RuntimeException)failure;
  273. }
  274. if (failure instanceof InvalidKeySpecException) {
  275. throw (InvalidKeySpecException)failure;
  276. }
  277. throw new InvalidKeySpecException
  278. ("Could not generate public key", failure);
  279. }
  280. /**
  281. * Generates a private key object from the provided key specification
  282. * (key material).
  283. *
  284. * @param keySpec the specification (key material) of the private key.
  285. *
  286. * @return the private key.
  287. *
  288. * @exception InvalidKeySpecException if the given key specification
  289. * is inappropriate for this key factory to produce a private key.
  290. */
  291. public final PrivateKey generatePrivate(KeySpec keySpec)
  292. throws InvalidKeySpecException {
  293. if (serviceIterator == null) {
  294. return spi.engineGeneratePrivate(keySpec);
  295. }
  296. Exception failure = null;
  297. KeyFactorySpi mySpi = spi;
  298. do {
  299. try {
  300. return mySpi.engineGeneratePrivate(keySpec);
  301. } catch (Exception e) {
  302. if (failure == null) {
  303. failure = e;
  304. }
  305. mySpi = nextSpi(mySpi);
  306. }
  307. } while (mySpi != null);
  308. if (failure instanceof RuntimeException) {
  309. throw (RuntimeException)failure;
  310. }
  311. if (failure instanceof InvalidKeySpecException) {
  312. throw (InvalidKeySpecException)failure;
  313. }
  314. throw new InvalidKeySpecException
  315. ("Could not generate private key", failure);
  316. }
  317. /**
  318. * Returns a specification (key material) of the given key object.
  319. * <code>keySpec</code> identifies the specification class in which
  320. * the key material should be returned. It could, for example, be
  321. * <code>DSAPublicKeySpec.class</code>, to indicate that the
  322. * key material should be returned in an instance of the
  323. * <code>DSAPublicKeySpec</code> class.
  324. *
  325. * @param key the key.
  326. *
  327. * @param keySpec the specification class in which
  328. * the key material should be returned.
  329. *
  330. * @return the underlying key specification (key material) in an instance
  331. * of the requested specification class.
  332. *
  333. * @exception InvalidKeySpecException if the requested key specification is
  334. * inappropriate for the given key, or the given key cannot be processed
  335. * (e.g., the given key has an unrecognized algorithm or format).
  336. */
  337. public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
  338. throws InvalidKeySpecException {
  339. if (serviceIterator == null) {
  340. return spi.engineGetKeySpec(key, keySpec);
  341. }
  342. Exception failure = null;
  343. KeyFactorySpi mySpi = spi;
  344. do {
  345. try {
  346. return mySpi.engineGetKeySpec(key, keySpec);
  347. } catch (Exception e) {
  348. if (failure == null) {
  349. failure = e;
  350. }
  351. mySpi = nextSpi(mySpi);
  352. }
  353. } while (mySpi != null);
  354. if (failure instanceof RuntimeException) {
  355. throw (RuntimeException)failure;
  356. }
  357. if (failure instanceof InvalidKeySpecException) {
  358. throw (InvalidKeySpecException)failure;
  359. }
  360. throw new InvalidKeySpecException
  361. ("Could not get key spec", failure);
  362. }
  363. /**
  364. * Translates a key object, whose provider may be unknown or potentially
  365. * untrusted, into a corresponding key object of this key factory.
  366. *
  367. * @param key the key whose provider is unknown or untrusted.
  368. *
  369. * @return the translated key.
  370. *
  371. * @exception InvalidKeyException if the given key cannot be processed
  372. * by this key factory.
  373. */
  374. public final Key translateKey(Key key) throws InvalidKeyException {
  375. if (serviceIterator == null) {
  376. return spi.engineTranslateKey(key);
  377. }
  378. Exception failure = null;
  379. KeyFactorySpi mySpi = spi;
  380. do {
  381. try {
  382. return mySpi.engineTranslateKey(key);
  383. } catch (Exception e) {
  384. if (failure == null) {
  385. failure = e;
  386. }
  387. mySpi = nextSpi(mySpi);
  388. }
  389. } while (mySpi != null);
  390. if (failure instanceof RuntimeException) {
  391. throw (RuntimeException)failure;
  392. }
  393. if (failure instanceof InvalidKeyException) {
  394. throw (InvalidKeyException)failure;
  395. }
  396. throw new InvalidKeyException
  397. ("Could not translate key", failure);
  398. }
  399. }