Save This Page
Home » openjdk-7 » java » security » [javadoc | source]
    1   /*
    2    * Copyright (c) 1997, 2011, Oracle and/or its affiliates. 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.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * 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    * <p> Every implementation of the Java platform is required to support the
   71    * following standard <code>KeyFactory</code> algorithms:
   72    * <ul>
   73    * <li><tt>DiffieHellman</tt></li>
   74    * <li><tt>DSA</tt></li>
   75    * <li><tt>RSA</tt></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 <tt>KeyFactory</tt>
  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 <tt>KeyFactory</tt>.
  270        *
  271        * @return the name of the algorithm associated with this
  272        * <tt>KeyFactory</tt>
  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</code> identifies the specification class in which
  393        * the key material should be returned. It could, for example, be
  394        * <code>DSAPublicKeySpec.class</code>, to indicate that the
  395        * key material should be returned in an instance of the
  396        * <code>DSAPublicKeySpec</code> class.
  397        *
  398        * @param key the key.
  399        *
  400        * @param keySpec the specification class in which
  401        * the key material should be returned.
  402        *
  403        * @return the underlying key specification (key material) in an instance
  404        * of the requested specification class.
  405        *
  406        * @exception InvalidKeySpecException if the requested key specification is
  407        * inappropriate for the given key, or the given key cannot be processed
  408        * (e.g., the given key has an unrecognized algorithm or format).
  409        */
  410       public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
  411               throws InvalidKeySpecException {
  412           if (serviceIterator == null) {
  413               return spi.engineGetKeySpec(key, keySpec);
  414           }
  415           Exception failure = null;
  416           KeyFactorySpi mySpi = spi;
  417           do {
  418               try {
  419                   return mySpi.engineGetKeySpec(key, keySpec);
  420               } catch (Exception e) {
  421                   if (failure == null) {
  422                       failure = e;
  423                   }
  424                   mySpi = nextSpi(mySpi);
  425               }
  426           } while (mySpi != null);
  427           if (failure instanceof RuntimeException) {
  428               throw (RuntimeException)failure;
  429           }
  430           if (failure instanceof InvalidKeySpecException) {
  431               throw (InvalidKeySpecException)failure;
  432           }
  433           throw new InvalidKeySpecException
  434                   ("Could not get key spec", failure);
  435       }
  436   
  437       /**
  438        * Translates a key object, whose provider may be unknown or potentially
  439        * untrusted, into a corresponding key object of this key factory.
  440        *
  441        * @param key the key whose provider is unknown or untrusted.
  442        *
  443        * @return the translated key.
  444        *
  445        * @exception InvalidKeyException if the given key cannot be processed
  446        * by this key factory.
  447        */
  448       public final Key translateKey(Key key) throws InvalidKeyException {
  449           if (serviceIterator == null) {
  450               return spi.engineTranslateKey(key);
  451           }
  452           Exception failure = null;
  453           KeyFactorySpi mySpi = spi;
  454           do {
  455               try {
  456                   return mySpi.engineTranslateKey(key);
  457               } catch (Exception e) {
  458                   if (failure == null) {
  459                       failure = e;
  460                   }
  461                   mySpi = nextSpi(mySpi);
  462               }
  463           } while (mySpi != null);
  464           if (failure instanceof RuntimeException) {
  465               throw (RuntimeException)failure;
  466           }
  467           if (failure instanceof InvalidKeyException) {
  468               throw (InvalidKeyException)failure;
  469           }
  470           throw new InvalidKeyException
  471                   ("Could not translate key", failure);
  472       }
  473   
  474   }

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