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

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