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

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