Save This Page
Home » openjdk-7 » java » security » [javadoc | source]
    1   /*
    2    * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   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</code>) 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</code> or
   51    * <code>X509EncodedKeySpec</code>. 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    * @author Jan Luehe
   71    *
   72    *
   73    * @see Key
   74    * @see PublicKey
   75    * @see PrivateKey
   76    * @see java.security.spec.KeySpec
   77    * @see java.security.spec.DSAPublicKeySpec
   78    * @see java.security.spec.X509EncodedKeySpec
   79    *
   80    * @since 1.2
   81    */
   82   
   83   public class KeyFactory {
   84   
   85       private static final Debug debug =
   86                           Debug.getInstance("jca", "KeyFactory");
   87   
   88       // The algorithm associated with this key factory
   89       private final String algorithm;
   90   
   91       // The provider
   92       private Provider provider;
   93   
   94       // The provider implementation (delegate)
   95       private volatile KeyFactorySpi spi;
   96   
   97       // lock for mutex during provider selection
   98       private final Object lock = new Object();
   99   
  100       // remaining services to try in provider selection
  101       // null once provider is selected
  102       private Iterator<Service> serviceIterator;
  103   
  104       /**
  105        * Creates a KeyFactory object.
  106        *
  107        * @param keyFacSpi the delegate
  108        * @param provider the provider
  109        * @param algorithm the name of the algorithm
  110        * to associate with this <tt>KeyFactory</tt>
  111        */
  112       protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider,
  113                            String algorithm) {
  114           this.spi = keyFacSpi;
  115           this.provider = provider;
  116           this.algorithm = algorithm;
  117       }
  118   
  119       private KeyFactory(String algorithm) throws NoSuchAlgorithmException {
  120           this.algorithm = algorithm;
  121           List<Service> list = GetInstance.getServices("KeyFactory", algorithm);
  122           serviceIterator = list.iterator();
  123           // fetch and instantiate initial spi
  124           if (nextSpi(null) == null) {
  125               throw new NoSuchAlgorithmException
  126                   (algorithm + " KeyFactory not available");
  127           }
  128       }
  129   
  130       /**
  131        * Returns a KeyFactory object that converts
  132        * public/private keys of the specified algorithm.
  133        *
  134        * <p> This method traverses the list of registered security Providers,
  135        * starting with the most preferred Provider.
  136        * A new KeyFactory object encapsulating the
  137        * KeyFactorySpi implementation from the first
  138        * Provider that supports the specified algorithm is returned.
  139        *
  140        * <p> Note that the list of registered providers may be retrieved via
  141        * the {@link Security#getProviders() Security.getProviders()} method.
  142        *
  143        * @param algorithm the name of the requested key algorithm.
  144        * See Appendix A in the <a href=
  145        * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  146        * Java Cryptography Architecture API Specification &amp; Reference </a>
  147        * for information about standard algorithm names.
  148        *
  149        * @return the new KeyFactory object.
  150        *
  151        * @exception NoSuchAlgorithmException if no Provider supports a
  152        *          KeyFactorySpi implementation for the
  153        *          specified algorithm.
  154        *
  155        * @see Provider
  156        */
  157       public static KeyFactory getInstance(String algorithm)
  158               throws NoSuchAlgorithmException {
  159           return new KeyFactory(algorithm);
  160       }
  161   
  162       /**
  163        * Returns a KeyFactory object that converts
  164        * public/private keys of the specified algorithm.
  165        *
  166        * <p> A new KeyFactory object encapsulating the
  167        * KeyFactorySpi implementation from the specified provider
  168        * is returned.  The specified provider must be registered
  169        * in the security provider list.
  170        *
  171        * <p> Note that the list of registered providers may be retrieved via
  172        * the {@link Security#getProviders() Security.getProviders()} method.
  173        *
  174        * @param algorithm the name of the requested key algorithm.
  175        * See Appendix A in the <a href=
  176        * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  177        * Java Cryptography Architecture API Specification &amp; Reference </a>
  178        * for information about standard algorithm names.
  179        *
  180        * @param provider the name of the provider.
  181        *
  182        * @return the new KeyFactory object.
  183        *
  184        * @exception NoSuchAlgorithmException if a KeyFactorySpi
  185        *          implementation for the specified algorithm is not
  186        *          available from the specified provider.
  187        *
  188        * @exception NoSuchProviderException if the specified provider is not
  189        *          registered in the security provider list.
  190        *
  191        * @exception IllegalArgumentException if the provider name is null
  192        *          or empty.
  193        *
  194        * @see Provider
  195        */
  196       public static KeyFactory getInstance(String algorithm, String provider)
  197               throws NoSuchAlgorithmException, NoSuchProviderException {
  198           Instance instance = GetInstance.getInstance("KeyFactory",
  199               KeyFactorySpi.class, algorithm, provider);
  200           return new KeyFactory((KeyFactorySpi)instance.impl,
  201               instance.provider, algorithm);
  202       }
  203   
  204       /**
  205        * Returns a KeyFactory object that converts
  206        * public/private keys of the specified algorithm.
  207        *
  208        * <p> A new KeyFactory object encapsulating the
  209        * KeyFactorySpi implementation from the specified Provider
  210        * object is returned.  Note that the specified Provider object
  211        * does not have to be registered in the provider list.
  212        *
  213        * @param algorithm the name of the requested key algorithm.
  214        * See Appendix A in the <a href=
  215        * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  216        * Java Cryptography Architecture API Specification &amp; Reference </a>
  217        * for information about standard algorithm names.
  218        *
  219        * @param provider the provider.
  220        *
  221        * @return the new KeyFactory object.
  222        *
  223        * @exception NoSuchAlgorithmException if a KeyFactorySpi
  224        *          implementation for the specified algorithm is not available
  225        *          from the specified Provider object.
  226        *
  227        * @exception IllegalArgumentException if the specified provider is null.
  228        *
  229        * @see Provider
  230        *
  231        * @since 1.4
  232        */
  233       public static KeyFactory getInstance(String algorithm, Provider provider)
  234               throws NoSuchAlgorithmException {
  235           Instance instance = GetInstance.getInstance("KeyFactory",
  236               KeyFactorySpi.class, algorithm, provider);
  237           return new KeyFactory((KeyFactorySpi)instance.impl,
  238               instance.provider, algorithm);
  239       }
  240   
  241       /**
  242        * Returns the provider of this key factory object.
  243        *
  244        * @return the provider of this key factory object
  245        */
  246       public final Provider getProvider() {
  247           synchronized (lock) {
  248               // disable further failover after this call
  249               serviceIterator = null;
  250               return provider;
  251           }
  252       }
  253   
  254       /**
  255        * Gets the name of the algorithm
  256        * associated with this <tt>KeyFactory</tt>.
  257        *
  258        * @return the name of the algorithm associated with this
  259        * <tt>KeyFactory</tt>
  260        */
  261       public final String getAlgorithm() {
  262           return this.algorithm;
  263       }
  264   
  265       /**
  266        * Update the active KeyFactorySpi of this class and return the next
  267        * implementation for failover. If no more implemenations are
  268        * available, this method returns null. However, the active spi of
  269        * this class is never set to null.
  270        */
  271       private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {
  272           synchronized (lock) {
  273               // somebody else did a failover concurrently
  274               // try that spi now
  275               if ((oldSpi != null) && (oldSpi != spi)) {
  276                   return spi;
  277               }
  278               if (serviceIterator == null) {
  279                   return null;
  280               }
  281               while (serviceIterator.hasNext()) {
  282                   Service s = serviceIterator.next();
  283                   try {
  284                       Object obj = s.newInstance(null);
  285                       if (obj instanceof KeyFactorySpi == false) {
  286                           continue;
  287                       }
  288                       KeyFactorySpi spi = (KeyFactorySpi)obj;
  289                       provider = s.getProvider();
  290                       this.spi = spi;
  291                       return spi;
  292                   } catch (NoSuchAlgorithmException e) {
  293                       // ignore
  294                   }
  295               }
  296               serviceIterator = null;
  297               return null;
  298           }
  299       }
  300   
  301       /**
  302        * Generates a public key object from the provided key specification
  303        * (key material).
  304        *
  305        * @param keySpec the specification (key material) of the public key.
  306        *
  307        * @return the public key.
  308        *
  309        * @exception InvalidKeySpecException if the given key specification
  310        * is inappropriate for this key factory to produce a public key.
  311        */
  312       public final PublicKey generatePublic(KeySpec keySpec)
  313               throws InvalidKeySpecException {
  314           if (serviceIterator == null) {
  315               return spi.engineGeneratePublic(keySpec);
  316           }
  317           Exception failure = null;
  318           KeyFactorySpi mySpi = spi;
  319           do {
  320               try {
  321                   return mySpi.engineGeneratePublic(keySpec);
  322               } catch (Exception e) {
  323                   if (failure == null) {
  324                       failure = e;
  325                   }
  326                   mySpi = nextSpi(mySpi);
  327               }
  328           } while (mySpi != null);
  329           if (failure instanceof RuntimeException) {
  330               throw (RuntimeException)failure;
  331           }
  332           if (failure instanceof InvalidKeySpecException) {
  333               throw (InvalidKeySpecException)failure;
  334           }
  335           throw new InvalidKeySpecException
  336                   ("Could not generate public key", failure);
  337       }
  338   
  339       /**
  340        * Generates a private key object from the provided key specification
  341        * (key material).
  342        *
  343        * @param keySpec the specification (key material) of the private key.
  344        *
  345        * @return the private key.
  346        *
  347        * @exception InvalidKeySpecException if the given key specification
  348        * is inappropriate for this key factory to produce a private key.
  349        */
  350       public final PrivateKey generatePrivate(KeySpec keySpec)
  351               throws InvalidKeySpecException {
  352           if (serviceIterator == null) {
  353               return spi.engineGeneratePrivate(keySpec);
  354           }
  355           Exception failure = null;
  356           KeyFactorySpi mySpi = spi;
  357           do {
  358               try {
  359                   return mySpi.engineGeneratePrivate(keySpec);
  360               } catch (Exception e) {
  361                   if (failure == null) {
  362                       failure = e;
  363                   }
  364                   mySpi = nextSpi(mySpi);
  365               }
  366           } while (mySpi != null);
  367           if (failure instanceof RuntimeException) {
  368               throw (RuntimeException)failure;
  369           }
  370           if (failure instanceof InvalidKeySpecException) {
  371               throw (InvalidKeySpecException)failure;
  372           }
  373           throw new InvalidKeySpecException
  374                   ("Could not generate private key", failure);
  375       }
  376   
  377       /**
  378        * Returns a specification (key material) of the given key object.
  379        * <code>keySpec</code> identifies the specification class in which
  380        * the key material should be returned. It could, for example, be
  381        * <code>DSAPublicKeySpec.class</code>, to indicate that the
  382        * key material should be returned in an instance of the
  383        * <code>DSAPublicKeySpec</code> class.
  384        *
  385        * @param key the key.
  386        *
  387        * @param keySpec the specification class in which
  388        * the key material should be returned.
  389        *
  390        * @return the underlying key specification (key material) in an instance
  391        * of the requested specification class.
  392        *
  393        * @exception InvalidKeySpecException if the requested key specification is
  394        * inappropriate for the given key, or the given key cannot be processed
  395        * (e.g., the given key has an unrecognized algorithm or format).
  396        */
  397       public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
  398               throws InvalidKeySpecException {
  399           if (serviceIterator == null) {
  400               return spi.engineGetKeySpec(key, keySpec);
  401           }
  402           Exception failure = null;
  403           KeyFactorySpi mySpi = spi;
  404           do {
  405               try {
  406                   return mySpi.engineGetKeySpec(key, keySpec);
  407               } catch (Exception e) {
  408                   if (failure == null) {
  409                       failure = e;
  410                   }
  411                   mySpi = nextSpi(mySpi);
  412               }
  413           } while (mySpi != null);
  414           if (failure instanceof RuntimeException) {
  415               throw (RuntimeException)failure;
  416           }
  417           if (failure instanceof InvalidKeySpecException) {
  418               throw (InvalidKeySpecException)failure;
  419           }
  420           throw new InvalidKeySpecException
  421                   ("Could not get key spec", failure);
  422       }
  423   
  424       /**
  425        * Translates a key object, whose provider may be unknown or potentially
  426        * untrusted, into a corresponding key object of this key factory.
  427        *
  428        * @param key the key whose provider is unknown or untrusted.
  429        *
  430        * @return the translated key.
  431        *
  432        * @exception InvalidKeyException if the given key cannot be processed
  433        * by this key factory.
  434        */
  435       public final Key translateKey(Key key) throws InvalidKeyException {
  436           if (serviceIterator == null) {
  437               return spi.engineTranslateKey(key);
  438           }
  439           Exception failure = null;
  440           KeyFactorySpi mySpi = spi;
  441           do {
  442               try {
  443                   return mySpi.engineTranslateKey(key);
  444               } catch (Exception e) {
  445                   if (failure == null) {
  446                       failure = e;
  447                   }
  448                   mySpi = nextSpi(mySpi);
  449               }
  450           } while (mySpi != null);
  451           if (failure instanceof RuntimeException) {
  452               throw (RuntimeException)failure;
  453           }
  454           if (failure instanceof InvalidKeyException) {
  455               throw (InvalidKeyException)failure;
  456           }
  457           throw new InvalidKeyException
  458                   ("Could not translate key", failure);
  459       }
  460   
  461   }

Save This Page
Home » openjdk-7 » java » security » [javadoc | source]