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 provides the functionality of a secret (symmetric) key generator.
   39    *
   40    * <p>Key generators are constructed using one of the <code>getInstance</code>
   41    * class methods of this class.
   42    *
   43    * <p>KeyGenerator objects are reusable, i.e., after a key has been
   44    * generated, the same KeyGenerator object can be re-used to generate further
   45    * keys.
   46    *
   47    * <p>There are two ways to generate a key: in an algorithm-independent
   48    * manner, and in an algorithm-specific manner.
   49    * The only difference between the two is the initialization of the object:
   50    *
   51    * <ul>
   52    * <li><b>Algorithm-Independent Initialization</b>
   53    * <p>All key generators share the concepts of a <i>keysize</i> and a
   54    * <i>source of randomness</i>.
   55    * There is an
   56    * {@link #init(int, java.security.SecureRandom) init}
   57    * method in this KeyGenerator class that takes these two universally
   58    * shared types of arguments. There is also one that takes just a
   59    * <code>keysize</code> argument, and uses the SecureRandom implementation
   60    * of the highest-priority installed provider as the source of randomness
   61    * (or a system-provided source of randomness if none of the installed
   62    * providers supply a SecureRandom implementation), and one that takes just a
   63    * source of randomness.
   64    *
   65    * <p>Since no other parameters are specified when you call the above
   66    * algorithm-independent <code>init</code> methods, it is up to the
   67    * provider what to do about the algorithm-specific parameters (if any) to be
   68    * associated with each of the keys.
   69    * <p>
   70    *
   71    * <li><b>Algorithm-Specific Initialization</b>
   72    * <p>For situations where a set of algorithm-specific parameters already
   73    * exists, there are two
   74    * {@link #init(java.security.spec.AlgorithmParameterSpec) init}
   75    * methods that have an <code>AlgorithmParameterSpec</code>
   76    * argument. One also has a <code>SecureRandom</code> argument, while the
   77    * other uses the SecureRandom implementation
   78    * of the highest-priority installed provider as the source of randomness
   79    * (or a system-provided source of randomness if none of the installed
   80    * providers supply a SecureRandom implementation).
   81    * </ul>
   82    *
   83    * <p>In case the client does not explicitly initialize the KeyGenerator
   84    * (via a call to an <code>init</code> method), each provider must
   85    * supply (and document) a default initialization.
   86    *
   87    * <p> Every implementation of the Java platform is required to support the
   88    * following standard <code>KeyGenerator</code> algorithms with the keysizes in
   89    * parentheses:
   90    * <ul>
   91    * <li><tt>AES</tt> (128)</li>
   92    * <li><tt>DES</tt> (56)</li>
   93    * <li><tt>DESede</tt> (168)</li>
   94    * <li><tt>HmacSHA1</tt></li>
   95    * <li><tt>HmacSHA256</tt></li>
   96    * </ul>
   97    * These algorithms are described in the <a href=
   98    * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
   99    * KeyGenerator section</a> of the
  100    * Java Cryptography Architecture Standard Algorithm Name Documentation.
  101    * Consult the release documentation for your implementation to see if any
  102    * other algorithms are supported.
  103    *
  104    * @author Jan Luehe
  105    *
  106    * @see SecretKey
  107    * @since 1.4
  108    */
  109   
  110   public class KeyGenerator {
  111   
  112       // see java.security.KeyPairGenerator for failover notes
  113   
  114       private final static int I_NONE   = 1;
  115       private final static int I_RANDOM = 2;
  116       private final static int I_PARAMS = 3;
  117       private final static int I_SIZE   = 4;
  118   
  119       // The provider
  120       private Provider provider;
  121   
  122       // The provider implementation (delegate)
  123       private volatile KeyGeneratorSpi spi;
  124   
  125       // The algorithm
  126       private final String algorithm;
  127   
  128       private final Object lock = new Object();
  129   
  130       private Iterator serviceIterator;
  131   
  132       private int initType;
  133       private int initKeySize;
  134       private AlgorithmParameterSpec initParams;
  135       private SecureRandom initRandom;
  136   
  137       /**
  138        * Creates a KeyGenerator object.
  139        *
  140        * @param keyGenSpi the delegate
  141        * @param provider the provider
  142        * @param algorithm the algorithm
  143        */
  144       protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,
  145                              String algorithm) {
  146           this.spi = keyGenSpi;
  147           this.provider = provider;
  148           this.algorithm = algorithm;
  149       }
  150   
  151       private KeyGenerator(String algorithm) throws NoSuchAlgorithmException {
  152           this.algorithm = algorithm;
  153           List list = GetInstance.getServices("KeyGenerator", algorithm);
  154           serviceIterator = list.iterator();
  155           initType = I_NONE;
  156           // fetch and instantiate initial spi
  157           if (nextSpi(null, false) == null) {
  158               throw new NoSuchAlgorithmException
  159                   (algorithm + " KeyGenerator not available");
  160           }
  161       }
  162   
  163       /**
  164        * Returns the algorithm name of this <code>KeyGenerator</code> object.
  165        *
  166        * <p>This is the same name that was specified in one of the
  167        * <code>getInstance</code> calls that created this
  168        * <code>KeyGenerator</code> object.
  169        *
  170        * @return the algorithm name of this <code>KeyGenerator</code> object.
  171        */
  172       public final String getAlgorithm() {
  173           return this.algorithm;
  174       }
  175   
  176       /**
  177        * Returns a <code>KeyGenerator</code> object that generates secret keys
  178        * for the specified algorithm.
  179        *
  180        * <p> This method traverses the list of registered security Providers,
  181        * starting with the most preferred Provider.
  182        * A new KeyGenerator object encapsulating the
  183        * KeyGeneratorSpi implementation from the first
  184        * Provider that supports the specified algorithm is returned.
  185        *
  186        * <p> Note that the list of registered providers may be retrieved via
  187        * the {@link Security#getProviders() Security.getProviders()} method.
  188        *
  189        * @param algorithm the standard name of the requested key algorithm.
  190        * See the KeyGenerator section in the <a href=
  191        * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
  192        * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
  193        * for information about standard algorithm names.
  194        *
  195        * @return the new <code>KeyGenerator</code> object.
  196        *
  197        * @exception NullPointerException if the specified algorithm is null.
  198        *
  199        * @exception NoSuchAlgorithmException if no Provider supports a
  200        *          KeyGeneratorSpi implementation for the
  201        *          specified algorithm.
  202        *
  203        * @see java.security.Provider
  204        */
  205       public static final KeyGenerator getInstance(String algorithm)
  206               throws NoSuchAlgorithmException {
  207           return new KeyGenerator(algorithm);
  208       }
  209   
  210       /**
  211        * Returns a <code>KeyGenerator</code> object that generates secret keys
  212        * for the specified algorithm.
  213        *
  214        * <p> A new KeyGenerator object encapsulating the
  215        * KeyGeneratorSpi implementation from the specified provider
  216        * is returned.  The specified provider must be registered
  217        * in the security provider list.
  218        *
  219        * <p> Note that the list of registered providers may be retrieved via
  220        * the {@link Security#getProviders() Security.getProviders()} method.
  221        *
  222        * @param algorithm the standard name of the requested key algorithm.
  223        * See the KeyGenerator section in the <a href=
  224        * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
  225        * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
  226        * for information about standard algorithm names.
  227        *
  228        * @param provider the name of the provider.
  229        *
  230        * @return the new <code>KeyGenerator</code> object.
  231        *
  232        * @exception NullPointerException if the specified algorithm is null.
  233        *
  234        * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
  235        *          implementation for the specified algorithm is not
  236        *          available from the specified provider.
  237        *
  238        * @exception NoSuchProviderException if the specified provider is not
  239        *          registered in the security provider list.
  240        *
  241        * @exception IllegalArgumentException if the <code>provider</code>
  242        *          is null or empty.
  243        *
  244        * @see java.security.Provider
  245        */
  246       public static final KeyGenerator getInstance(String algorithm,
  247               String provider) throws NoSuchAlgorithmException,
  248               NoSuchProviderException {
  249           Instance instance = JceSecurity.getInstance("KeyGenerator",
  250                   KeyGeneratorSpi.class, algorithm, provider);
  251           return new KeyGenerator((KeyGeneratorSpi)instance.impl,
  252                   instance.provider, algorithm);
  253       }
  254   
  255       /**
  256        * Returns a <code>KeyGenerator</code> object that generates secret keys
  257        * for the specified algorithm.
  258        *
  259        * <p> A new KeyGenerator object encapsulating the
  260        * KeyGeneratorSpi implementation from the specified Provider
  261        * object is returned.  Note that the specified Provider object
  262        * does not have to be registered in the provider list.
  263        *
  264        * @param algorithm the standard name of the requested key algorithm.
  265        * See the KeyGenerator section in the <a href=
  266        * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
  267        * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
  268        * for information about standard algorithm names.
  269        *
  270        * @param provider the provider.
  271        *
  272        * @return the new <code>KeyGenerator</code> object.
  273        *
  274        * @exception NullPointerException if the specified algorithm is null.
  275        *
  276        * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
  277        *          implementation for the specified algorithm is not available
  278        *          from the specified Provider object.
  279        *
  280        * @exception IllegalArgumentException if the <code>provider</code>
  281        *          is null.
  282        *
  283        * @see java.security.Provider
  284        */
  285       public static final KeyGenerator getInstance(String algorithm,
  286               Provider provider) throws NoSuchAlgorithmException {
  287           Instance instance = JceSecurity.getInstance("KeyGenerator",
  288                   KeyGeneratorSpi.class, algorithm, provider);
  289           return new KeyGenerator((KeyGeneratorSpi)instance.impl,
  290                   instance.provider, algorithm);
  291       }
  292   
  293       /**
  294        * Returns the provider of this <code>KeyGenerator</code> object.
  295        *
  296        * @return the provider of this <code>KeyGenerator</code> object
  297        */
  298       public final Provider getProvider() {
  299           synchronized (lock) {
  300               disableFailover();
  301               return provider;
  302           }
  303       }
  304   
  305       /**
  306        * Update the active spi of this class and return the next
  307        * implementation for failover. If no more implemenations are
  308        * available, this method returns null. However, the active spi of
  309        * this class is never set to null.
  310        */
  311       private KeyGeneratorSpi nextSpi(KeyGeneratorSpi oldSpi,
  312               boolean reinit) {
  313           synchronized (lock) {
  314               // somebody else did a failover concurrently
  315               // try that spi now
  316               if ((oldSpi != null) && (oldSpi != spi)) {
  317                   return spi;
  318               }
  319               if (serviceIterator == null) {
  320                   return null;
  321               }
  322               while (serviceIterator.hasNext()) {
  323                   Service s = (Service)serviceIterator.next();
  324                   if (JceSecurity.canUseProvider(s.getProvider()) == false) {
  325                       continue;
  326                   }
  327                   try {
  328                       Object inst = s.newInstance(null);
  329                       // ignore non-spis
  330                       if (inst instanceof KeyGeneratorSpi == false) {
  331                           continue;
  332                       }
  333                       KeyGeneratorSpi spi = (KeyGeneratorSpi)inst;
  334                       if (reinit) {
  335                           if (initType == I_SIZE) {
  336                               spi.engineInit(initKeySize, initRandom);
  337                           } else if (initType == I_PARAMS) {
  338                               spi.engineInit(initParams, initRandom);
  339                           } else if (initType == I_RANDOM) {
  340                               spi.engineInit(initRandom);
  341                           } else if (initType != I_NONE) {
  342                               throw new AssertionError
  343                                   ("KeyGenerator initType: " + initType);
  344                           }
  345                       }
  346                       provider = s.getProvider();
  347                       this.spi = spi;
  348                       return spi;
  349                   } catch (Exception e) {
  350                       // ignore
  351                   }
  352               }
  353               disableFailover();
  354               return null;
  355           }
  356       }
  357   
  358       void disableFailover() {
  359           serviceIterator = null;
  360           initType = 0;
  361           initParams = null;
  362           initRandom = null;
  363       }
  364   
  365       /**
  366        * Initializes this key generator.
  367        *
  368        * @param random the source of randomness for this generator
  369        */
  370       public final void init(SecureRandom random) {
  371           if (serviceIterator == null) {
  372               spi.engineInit(random);
  373               return;
  374           }
  375           RuntimeException failure = null;
  376           KeyGeneratorSpi mySpi = spi;
  377           do {
  378               try {
  379                   mySpi.engineInit(random);
  380                   initType = I_RANDOM;
  381                   initKeySize = 0;
  382                   initParams = null;
  383                   initRandom = random;
  384                   return;
  385               } catch (RuntimeException e) {
  386                   if (failure == null) {
  387                       failure = e;
  388                   }
  389                   mySpi = nextSpi(mySpi, false);
  390               }
  391           } while (mySpi != null);
  392           throw failure;
  393       }
  394   
  395       /**
  396        * Initializes this key generator with the specified parameter set.
  397        *
  398        * <p> If this key generator requires any random bytes, it will get them
  399        * using the
  400        * {@link SecureRandom <code>SecureRandom</code>}
  401        * implementation of the highest-priority installed
  402        * provider as the source of randomness.
  403        * (If none of the installed providers supply an implementation of
  404        * SecureRandom, a system-provided source of randomness will be used.)
  405        *
  406        * @param params the key generation parameters
  407        *
  408        * @exception InvalidAlgorithmParameterException if the given parameters
  409        * are inappropriate for this key generator
  410        */
  411       public final void init(AlgorithmParameterSpec params)
  412           throws InvalidAlgorithmParameterException
  413       {
  414           init(params, JceSecurity.RANDOM);
  415       }
  416   
  417       /**
  418        * Initializes this key generator with the specified parameter
  419        * set and a user-provided source of randomness.
  420        *
  421        * @param params the key generation parameters
  422        * @param random the source of randomness for this key generator
  423        *
  424        * @exception InvalidAlgorithmParameterException if <code>params</code> is
  425        * inappropriate for this key generator
  426        */
  427       public final void init(AlgorithmParameterSpec params, SecureRandom random)
  428           throws InvalidAlgorithmParameterException
  429       {
  430           if (serviceIterator == null) {
  431               spi.engineInit(params, random);
  432               return;
  433           }
  434           Exception failure = null;
  435           KeyGeneratorSpi mySpi = spi;
  436           do {
  437               try {
  438                   mySpi.engineInit(params, random);
  439                   initType = I_PARAMS;
  440                   initKeySize = 0;
  441                   initParams = params;
  442                   initRandom = random;
  443                   return;
  444               } catch (Exception e) {
  445                   if (failure == null) {
  446                       failure = e;
  447                   }
  448                   mySpi = nextSpi(mySpi, false);
  449               }
  450           } while (mySpi != null);
  451           if (failure instanceof InvalidAlgorithmParameterException) {
  452               throw (InvalidAlgorithmParameterException)failure;
  453           }
  454           if (failure instanceof RuntimeException) {
  455               throw (RuntimeException)failure;
  456           }
  457           throw new InvalidAlgorithmParameterException("init() failed", failure);
  458       }
  459   
  460       /**
  461        * Initializes this key generator for a certain keysize.
  462        *
  463        * <p> If this key generator requires any random bytes, it will get them
  464        * using the
  465        * {@link SecureRandom <code>SecureRandom</code>}
  466        * implementation of the highest-priority installed
  467        * provider as the source of randomness.
  468        * (If none of the installed providers supply an implementation of
  469        * SecureRandom, a system-provided source of randomness will be used.)
  470        *
  471        * @param keysize the keysize. This is an algorithm-specific metric,
  472        * specified in number of bits.
  473        *
  474        * @exception InvalidParameterException if the keysize is wrong or not
  475        * supported.
  476        */
  477       public final void init(int keysize) {
  478           init(keysize, JceSecurity.RANDOM);
  479       }
  480   
  481       /**
  482        * Initializes this key generator for a certain keysize, using a
  483        * user-provided source of randomness.
  484        *
  485        * @param keysize the keysize. This is an algorithm-specific metric,
  486        * specified in number of bits.
  487        * @param random the source of randomness for this key generator
  488        *
  489        * @exception InvalidParameterException if the keysize is wrong or not
  490        * supported.
  491        */
  492       public final void init(int keysize, SecureRandom random) {
  493           if (serviceIterator == null) {
  494               spi.engineInit(keysize, random);
  495               return;
  496           }
  497           RuntimeException failure = null;
  498           KeyGeneratorSpi mySpi = spi;
  499           do {
  500               try {
  501                   mySpi.engineInit(keysize, random);
  502                   initType = I_SIZE;
  503                   initKeySize = keysize;
  504                   initParams = null;
  505                   initRandom = random;
  506                   return;
  507               } catch (RuntimeException e) {
  508                   if (failure == null) {
  509                       failure = e;
  510                   }
  511                   mySpi = nextSpi(mySpi, false);
  512               }
  513           } while (mySpi != null);
  514           throw failure;
  515       }
  516   
  517       /**
  518        * Generates a secret key.
  519        *
  520        * @return the new key
  521        */
  522       public final SecretKey generateKey() {
  523           if (serviceIterator == null) {
  524               return spi.engineGenerateKey();
  525           }
  526           RuntimeException failure = null;
  527           KeyGeneratorSpi mySpi = spi;
  528           do {
  529               try {
  530                   return mySpi.engineGenerateKey();
  531               } catch (RuntimeException e) {
  532                   if (failure == null) {
  533                       failure = e;
  534                   }
  535                   mySpi = nextSpi(mySpi, true);
  536               }
  537           } while (mySpi != null);
  538           throw failure;
  539      }
  540   }

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