Save This Page
Home » openjdk-7 » javax » crypto » [javadoc | source]
    1   /*
    2    * Copyright 1997-2007 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 javax.crypto;
   27   
   28   import java.util;
   29   
   30   import java.security;
   31   import java.security.Provider.Service;
   32   import java.security.spec;
   33   
   34   import sun.security.jca;
   35   import sun.security.jca.GetInstance.Instance;
   36   
   37   /**
   38    * This class represents a factory for secret keys.
   39    *
   40    * <P> Key factories are used to convert <I>keys</I> (opaque
   41    * cryptographic keys of type <code>Key</code>) into <I>key specifications</I>
   42    * (transparent representations of the underlying key material), and vice
   43    * versa.
   44    * Secret key factories operate only on secret (symmetric) keys.
   45    *
   46    * <P> Key factories are bi-directional, i.e., they allow to build an opaque
   47    * key object from a given key specification (key material), or to retrieve
   48    * the underlying key material of a key object in a suitable format.
   49    *
   50    * <P> Application developers should refer to their provider's documentation
   51    * to find out which key specifications are supported by the
   52    * {@link #generateSecret(java.security.spec.KeySpec) generateSecret} and
   53    * {@link #getKeySpec(javax.crypto.SecretKey, java.lang.Class) getKeySpec}
   54    * methods.
   55    * For example, the DES secret-key factory supplied by the "SunJCE" provider
   56    * supports <code>DESKeySpec</code> as a transparent representation of DES
   57    * keys, and that provider's secret-key factory for Triple DES keys supports
   58    * <code>DESedeKeySpec</code> as a transparent representation of Triple DES
   59    * keys.
   60    *
   61    * @author Jan Luehe
   62    *
   63    * @see SecretKey
   64    * @see javax.crypto.spec.DESKeySpec
   65    * @see javax.crypto.spec.DESedeKeySpec
   66    * @see javax.crypto.spec.PBEKeySpec
   67    * @since 1.4
   68    */
   69   
   70   public class SecretKeyFactory {
   71   
   72       // The provider
   73       private Provider provider;
   74   
   75       // The algorithm associated with this factory
   76       private final String algorithm;
   77   
   78       // The provider implementation (delegate)
   79       private volatile SecretKeyFactorySpi spi;
   80   
   81       // lock for mutex during provider selection
   82       private final Object lock = new Object();
   83   
   84       // remaining services to try in provider selection
   85       // null once provider is selected
   86       private Iterator serviceIterator;
   87   
   88       /**
   89        * Creates a SecretKeyFactory object.
   90        *
   91        * @param keyFacSpi the delegate
   92        * @param provider the provider
   93        * @param algorithm the secret-key algorithm
   94        */
   95       protected SecretKeyFactory(SecretKeyFactorySpi keyFacSpi,
   96                                  Provider provider, String algorithm) {
   97           this.spi = keyFacSpi;
   98           this.provider = provider;
   99           this.algorithm = algorithm;
  100       }
  101   
  102       private SecretKeyFactory(String algorithm) throws NoSuchAlgorithmException {
  103           this.algorithm = algorithm;
  104           List list = GetInstance.getServices("SecretKeyFactory", algorithm);
  105           serviceIterator = list.iterator();
  106           // fetch and instantiate initial spi
  107           if (nextSpi(null) == null) {
  108               throw new NoSuchAlgorithmException
  109                   (algorithm + " SecretKeyFactory not available");
  110           }
  111       }
  112   
  113       /**
  114        * Returns a <code>SecretKeyFactory</code> object that converts
  115        * secret keys of the specified algorithm.
  116        *
  117        * <p> This method traverses the list of registered security Providers,
  118        * starting with the most preferred Provider.
  119        * A new SecretKeyFactory object encapsulating the
  120        * SecretKeyFactorySpi implementation from the first
  121        * Provider that supports the specified algorithm is returned.
  122        *
  123        * <p> Note that the list of registered providers may be retrieved via
  124        * the {@link Security#getProviders() Security.getProviders()} method.
  125        *
  126        * @param algorithm the standard name of the requested secret-key
  127        * algorithm.
  128        * See Appendix A in the <a href=
  129        *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  130        * Java Cryptography Architecture Reference Guide</a>
  131        * for information about standard algorithm names.
  132        *
  133        * @return the new <code>SecretKeyFactory</code> object.
  134        *
  135        * @exception NullPointerException if the specified algorithm
  136        *          is null.
  137        *
  138        * @exception NoSuchAlgorithmException if no Provider supports a
  139        *          SecretKeyFactorySpi implementation for the
  140        *          specified algorithm.
  141        *
  142        * @see java.security.Provider
  143        */
  144       public static final SecretKeyFactory getInstance(String algorithm)
  145               throws NoSuchAlgorithmException {
  146           return new SecretKeyFactory(algorithm);
  147       }
  148   
  149       /**
  150        * Returns a <code>SecretKeyFactory</code> object that converts
  151        * secret keys of the specified algorithm.
  152        *
  153        * <p> A new SecretKeyFactory object encapsulating the
  154        * SecretKeyFactorySpi implementation from the specified provider
  155        * is returned.  The specified provider must be registered
  156        * in the security provider list.
  157        *
  158        * <p> Note that the list of registered providers may be retrieved via
  159        * the {@link Security#getProviders() Security.getProviders()} method.
  160        *
  161        * @param algorithm the standard name of the requested secret-key
  162        * algorithm.
  163        * See Appendix A in the <a href=
  164        *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  165        * Java Cryptography Architecture Reference Guide</a>
  166        * for information about standard algorithm names.
  167        *
  168        * @param provider the name of the provider.
  169        *
  170        * @return the new <code>SecretKeyFactory</code> object.
  171        *
  172        * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi
  173        *          implementation for the specified algorithm is not
  174        *          available from the specified provider.
  175        *
  176        * @exception NullPointerException if the specified algorithm
  177        *          is null.
  178        *
  179        * @throws NoSuchProviderException if the specified provider is not
  180        *          registered in the security provider list.
  181        *
  182        * @exception IllegalArgumentException if the <code>provider</code>
  183        *          is null or empty.
  184        *
  185        * @see java.security.Provider
  186        */
  187       public static final SecretKeyFactory getInstance(String algorithm,
  188               String provider) throws NoSuchAlgorithmException,
  189               NoSuchProviderException {
  190           Instance instance = JceSecurity.getInstance("SecretKeyFactory",
  191                   SecretKeyFactorySpi.class, algorithm, provider);
  192           return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,
  193                   instance.provider, algorithm);
  194       }
  195   
  196       /**
  197        * Returns a <code>SecretKeyFactory</code> object that converts
  198        * secret keys of the specified algorithm.
  199        *
  200        * <p> A new SecretKeyFactory object encapsulating the
  201        * SecretKeyFactorySpi implementation from the specified Provider
  202        * object is returned.  Note that the specified Provider object
  203        * does not have to be registered in the provider list.
  204        *
  205        * @param algorithm the standard name of the requested secret-key
  206        * algorithm.
  207        * See Appendix A in the <a href=
  208        *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  209        * Java Cryptography Architecture Reference Guide</a>
  210        * for information about standard algorithm names.
  211        *
  212        * @param provider the provider.
  213        *
  214        * @return the new <code>SecretKeyFactory</code> object.
  215        *
  216        * @exception NullPointerException if the specified algorithm
  217        * is null.
  218        *
  219        * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi
  220        *          implementation for the specified algorithm is not available
  221        *          from the specified Provider object.
  222        *
  223        * @exception IllegalArgumentException if the <code>provider</code>
  224        *          is null.
  225        *
  226        * @see java.security.Provider
  227        */
  228       public static final SecretKeyFactory getInstance(String algorithm,
  229               Provider provider) throws NoSuchAlgorithmException {
  230           Instance instance = JceSecurity.getInstance("SecretKeyFactory",
  231                   SecretKeyFactorySpi.class, algorithm, provider);
  232           return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,
  233                   instance.provider, algorithm);
  234       }
  235   
  236       /**
  237        * Returns the provider of this <code>SecretKeyFactory</code> object.
  238        *
  239        * @return the provider of this <code>SecretKeyFactory</code> object
  240        */
  241       public final Provider getProvider() {
  242           synchronized (lock) {
  243               // disable further failover after this call
  244               serviceIterator = null;
  245               return provider;
  246           }
  247       }
  248   
  249       /**
  250        * Returns the algorithm name of this <code>SecretKeyFactory</code> object.
  251        *
  252        * <p>This is the same name that was specified in one of the
  253        * <code>getInstance</code> calls that created this
  254        * <code>SecretKeyFactory</code> object.
  255        *
  256        * @return the algorithm name of this <code>SecretKeyFactory</code>
  257        * object.
  258        */
  259       public final String getAlgorithm() {
  260           return this.algorithm;
  261       }
  262   
  263       /**
  264        * Update the active spi of this class and return the next
  265        * implementation for failover. If no more implemenations are
  266        * available, this method returns null. However, the active spi of
  267        * this class is never set to null.
  268        */
  269       private SecretKeyFactorySpi nextSpi(SecretKeyFactorySpi oldSpi) {
  270           synchronized (lock) {
  271               // somebody else did a failover concurrently
  272               // try that spi now
  273               if ((oldSpi != null) && (oldSpi != spi)) {
  274                   return spi;
  275               }
  276               if (serviceIterator == null) {
  277                   return null;
  278               }
  279               while (serviceIterator.hasNext()) {
  280                   Service s = (Service)serviceIterator.next();
  281                   if (JceSecurity.canUseProvider(s.getProvider()) == false) {
  282                       continue;
  283                   }
  284                   try {
  285                       Object obj = s.newInstance(null);
  286                       if (obj instanceof SecretKeyFactorySpi == false) {
  287                           continue;
  288                       }
  289                       SecretKeyFactorySpi spi = (SecretKeyFactorySpi)obj;
  290                       provider = s.getProvider();
  291                       this.spi = spi;
  292                       return spi;
  293                   } catch (NoSuchAlgorithmException e) {
  294                       // ignore
  295                   }
  296               }
  297               serviceIterator = null;
  298               return null;
  299           }
  300       }
  301   
  302       /**
  303        * Generates a <code>SecretKey</code> object from the provided key
  304        * specification (key material).
  305        *
  306        * @param keySpec the specification (key material) of the secret key
  307        *
  308        * @return the secret key
  309        *
  310        * @exception InvalidKeySpecException if the given key specification
  311        * is inappropriate for this secret-key factory to produce a secret key.
  312        */
  313       public final SecretKey generateSecret(KeySpec keySpec)
  314               throws InvalidKeySpecException {
  315           if (serviceIterator == null) {
  316               return spi.engineGenerateSecret(keySpec);
  317           }
  318           Exception failure = null;
  319           SecretKeyFactorySpi mySpi = spi;
  320           do {
  321               try {
  322                   return mySpi.engineGenerateSecret(keySpec);
  323               } catch (Exception e) {
  324                   if (failure == null) {
  325                       failure = e;
  326                   }
  327                   mySpi = nextSpi(mySpi);
  328               }
  329           } while (mySpi != null);
  330           if (failure instanceof InvalidKeySpecException) {
  331               throw (InvalidKeySpecException)failure;
  332           }
  333           throw new InvalidKeySpecException
  334                   ("Could not generate secret key", failure);
  335       }
  336   
  337       /**
  338        * Returns a specification (key material) of the given key object
  339        * in the requested format.
  340        *
  341        * @param key the key
  342        * @param keySpec the requested format in which the key material shall be
  343        * returned
  344        *
  345        * @return the underlying key specification (key material) in the
  346        * requested format
  347        *
  348        * @exception InvalidKeySpecException if the requested key specification is
  349        * inappropriate for the given key (e.g., the algorithms associated with
  350        * <code>key</code> and <code>keySpec</code> do not match, or
  351        * <code>key</code> references a key on a cryptographic hardware device
  352        * whereas <code>keySpec</code> is the specification of a software-based
  353        * key), or the given key cannot be dealt with
  354        * (e.g., the given key has an algorithm or format not supported by this
  355        * secret-key factory).
  356        */
  357       public final KeySpec getKeySpec(SecretKey key, Class keySpec)
  358               throws InvalidKeySpecException {
  359           if (serviceIterator == null) {
  360               return spi.engineGetKeySpec(key, keySpec);
  361           }
  362           Exception failure = null;
  363           SecretKeyFactorySpi mySpi = spi;
  364           do {
  365               try {
  366                   return mySpi.engineGetKeySpec(key, keySpec);
  367               } catch (Exception e) {
  368                   if (failure == null) {
  369                       failure = e;
  370                   }
  371                   mySpi = nextSpi(mySpi);
  372               }
  373           } while (mySpi != null);
  374           if (failure instanceof InvalidKeySpecException) {
  375               throw (InvalidKeySpecException)failure;
  376           }
  377           throw new InvalidKeySpecException
  378                   ("Could not get key spec", failure);
  379       }
  380   
  381       /**
  382        * Translates a key object, whose provider may be unknown or potentially
  383        * untrusted, into a corresponding key object of this secret-key factory.
  384        *
  385        * @param key the key whose provider is unknown or untrusted
  386        *
  387        * @return the translated key
  388        *
  389        * @exception InvalidKeyException if the given key cannot be processed
  390        * by this secret-key factory.
  391        */
  392       public final SecretKey translateKey(SecretKey key)
  393               throws InvalidKeyException {
  394           if (serviceIterator == null) {
  395               return spi.engineTranslateKey(key);
  396           }
  397           Exception failure = null;
  398           SecretKeyFactorySpi mySpi = spi;
  399           do {
  400               try {
  401                   return mySpi.engineTranslateKey(key);
  402               } catch (Exception e) {
  403                   if (failure == null) {
  404                       failure = e;
  405                   }
  406                   mySpi = nextSpi(mySpi);
  407               }
  408           } while (mySpi != null);
  409           if (failure instanceof InvalidKeyException) {
  410               throw (InvalidKeyException)failure;
  411           }
  412           throw new InvalidKeyException
  413                   ("Could not translate key", failure);
  414       }
  415   }

Save This Page
Home » openjdk-7 » javax » crypto » [javadoc | source]