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.util.Debug;
   35   import sun.security.jca;
   36   import sun.security.jca.GetInstance.Instance;
   37   
   38   /**
   39    * This class provides the functionality of a key agreement (or key
   40    * exchange) protocol.
   41    * <p>
   42    * The keys involved in establishing a shared secret are created by one of the
   43    * key generators (<code>KeyPairGenerator</code> or
   44    * <code>KeyGenerator</code>), a <code>KeyFactory</code>, or as a result from
   45    * an intermediate phase of the key agreement protocol.
   46    *
   47    * <p> For each of the correspondents in the key exchange, <code>doPhase</code>
   48    * needs to be called. For example, if this key exchange is with one other
   49    * party, <code>doPhase</code> needs to be called once, with the
   50    * <code>lastPhase</code> flag set to <code>true</code>.
   51    * If this key exchange is
   52    * with two other parties, <code>doPhase</code> needs to be called twice,
   53    * the first time setting the <code>lastPhase</code> flag to
   54    * <code>false</code>, and the second time setting it to <code>true</code>.
   55    * There may be any number of parties involved in a key exchange.
   56    *
   57    * @author Jan Luehe
   58    *
   59    * @see KeyGenerator
   60    * @see SecretKey
   61    * @since 1.4
   62    */
   63   
   64   public class KeyAgreement {
   65   
   66       private static final Debug debug =
   67                           Debug.getInstance("jca", "KeyAgreement");
   68   
   69       // The provider
   70       private Provider provider;
   71   
   72       // The provider implementation (delegate)
   73       private KeyAgreementSpi spi;
   74   
   75       // The name of the key agreement algorithm.
   76       private final String algorithm;
   77   
   78       // next service to try in provider selection
   79       // null once provider is selected
   80       private Service firstService;
   81   
   82       // remaining services to try in provider selection
   83       // null once provider is selected
   84       private Iterator serviceIterator;
   85   
   86       private final Object lock;
   87   
   88       /**
   89        * Creates a KeyAgreement object.
   90        *
   91        * @param keyAgreeSpi the delegate
   92        * @param provider the provider
   93        * @param algorithm the algorithm
   94        */
   95       protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider,
   96                              String algorithm) {
   97           this.spi = keyAgreeSpi;
   98           this.provider = provider;
   99           this.algorithm = algorithm;
  100           lock = null;
  101       }
  102   
  103       private KeyAgreement(Service s, Iterator t, String algorithm) {
  104           firstService = s;
  105           serviceIterator = t;
  106           this.algorithm = algorithm;
  107           lock = new Object();
  108       }
  109   
  110       /**
  111        * Returns the algorithm name of this <code>KeyAgreement</code> object.
  112        *
  113        * <p>This is the same name that was specified in one of the
  114        * <code>getInstance</code> calls that created this
  115        * <code>KeyAgreement</code> object.
  116        *
  117        * @return the algorithm name of this <code>KeyAgreement</code> object.
  118        */
  119       public final String getAlgorithm() {
  120           return this.algorithm;
  121       }
  122   
  123       /**
  124        * Returns a <code>KeyAgreement</code> object that implements the
  125        * specified key agreement algorithm.
  126        *
  127        * <p> This method traverses the list of registered security Providers,
  128        * starting with the most preferred Provider.
  129        * A new KeyAgreement object encapsulating the
  130        * KeyAgreementSpi implementation from the first
  131        * Provider that supports the specified algorithm is returned.
  132        *
  133        * <p> Note that the list of registered providers may be retrieved via
  134        * the {@link Security#getProviders() Security.getProviders()} method.
  135        *
  136        * @param algorithm the standard name of the requested key agreement
  137        * algorithm.
  138        * See Appendix A in the
  139        * <a href=
  140        *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  141        * Java Cryptography Architecture Reference Guide</a>
  142        * for information about standard algorithm names.
  143        *
  144        * @return the new <code>KeyAgreement</code> object.
  145        *
  146        * @exception NullPointerException if the specified algorithm
  147        *          is null.
  148        *
  149        * @exception NoSuchAlgorithmException if no Provider supports a
  150        *          KeyAgreementSpi implementation for the
  151        *          specified algorithm.
  152        *
  153        * @see java.security.Provider
  154        */
  155       public static final KeyAgreement getInstance(String algorithm)
  156               throws NoSuchAlgorithmException {
  157           List services = GetInstance.getServices("KeyAgreement", algorithm);
  158           // make sure there is at least one service from a signed provider
  159           Iterator t = services.iterator();
  160           while (t.hasNext()) {
  161               Service s = (Service)t.next();
  162               if (JceSecurity.canUseProvider(s.getProvider()) == false) {
  163                   continue;
  164               }
  165               return new KeyAgreement(s, t, algorithm);
  166           }
  167           throw new NoSuchAlgorithmException
  168                                   ("Algorithm " + algorithm + " not available");
  169       }
  170   
  171       /**
  172        * Returns a <code>KeyAgreement</code> object that implements the
  173        * specified key agreement algorithm.
  174        *
  175        * <p> A new KeyAgreement object encapsulating the
  176        * KeyAgreementSpi implementation from the specified provider
  177        * is returned.  The specified provider must be registered
  178        * in the security provider list.
  179        *
  180        * <p> Note that the list of registered providers may be retrieved via
  181        * the {@link Security#getProviders() Security.getProviders()} method.
  182        *
  183        * @param algorithm the standard name of the requested key agreement
  184        * algorithm.
  185        * See Appendix A in the
  186        * <a href=
  187        *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  188        * Java Cryptography Architecture Reference Guide</a>
  189        * for information about standard algorithm names.
  190        *
  191        * @param provider the name of the provider.
  192        *
  193        * @return the new <code>KeyAgreement</code> object.
  194        *
  195        * @exception NullPointerException if the specified algorithm
  196        *          is null.
  197        *
  198        * @exception NoSuchAlgorithmException if a KeyAgreementSpi
  199        *          implementation for the specified algorithm is not
  200        *          available from the specified provider.
  201        *
  202        * @exception NoSuchProviderException if the specified provider is not
  203        *          registered in the security provider list.
  204        *
  205        * @exception IllegalArgumentException if the <code>provider</code>
  206        *          is null or empty.
  207        *
  208        * @see java.security.Provider
  209        */
  210       public static final KeyAgreement getInstance(String algorithm,
  211               String provider) throws NoSuchAlgorithmException,
  212               NoSuchProviderException {
  213           Instance instance = JceSecurity.getInstance
  214                   ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
  215           return new KeyAgreement((KeyAgreementSpi)instance.impl,
  216                   instance.provider, algorithm);
  217       }
  218   
  219       /**
  220        * Returns a <code>KeyAgreement</code> object that implements the
  221        * specified key agreement algorithm.
  222        *
  223        * <p> A new KeyAgreement object encapsulating the
  224        * KeyAgreementSpi implementation from the specified Provider
  225        * object is returned.  Note that the specified Provider object
  226        * does not have to be registered in the provider list.
  227        *
  228        * @param algorithm the standard name of the requested key agreement
  229        * algorithm.
  230        * See Appendix A in the
  231        * <a href=
  232        *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  233        * Java Cryptography Architecture Reference Guide</a>
  234        * for information about standard algorithm names.
  235        *
  236        * @param provider the provider.
  237        *
  238        * @return the new <code>KeyAgreement</code> object.
  239        *
  240        * @exception NullPointerException if the specified algorithm
  241        *          is null.
  242        *
  243        * @exception NoSuchAlgorithmException if a KeyAgreementSpi
  244        *          implementation for the specified algorithm is not available
  245        *          from the specified Provider object.
  246        *
  247        * @exception IllegalArgumentException if the <code>provider</code>
  248        *          is null.
  249        *
  250        * @see java.security.Provider
  251        */
  252       public static final KeyAgreement getInstance(String algorithm,
  253               Provider provider) throws NoSuchAlgorithmException {
  254           Instance instance = JceSecurity.getInstance
  255                   ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
  256           return new KeyAgreement((KeyAgreementSpi)instance.impl,
  257                   instance.provider, algorithm);
  258       }
  259   
  260       // max number of debug warnings to print from chooseFirstProvider()
  261       private static int warnCount = 10;
  262   
  263       /**
  264        * Choose the Spi from the first provider available. Used if
  265        * delayed provider selection is not possible because init()
  266        * is not the first method called.
  267        */
  268       void chooseFirstProvider() {
  269           if (spi != null) {
  270               return;
  271           }
  272           synchronized (lock) {
  273               if (spi != null) {
  274                   return;
  275               }
  276               if (debug != null) {
  277                   int w = --warnCount;
  278                   if (w >= 0) {
  279                       debug.println("KeyAgreement.init() not first method "
  280                           + "called, disabling delayed provider selection");
  281                       if (w == 0) {
  282                           debug.println("Further warnings of this type will "
  283                               + "be suppressed");
  284                       }
  285                       new Exception("Call trace").printStackTrace();
  286                   }
  287               }
  288               Exception lastException = null;
  289               while ((firstService != null) || serviceIterator.hasNext()) {
  290                   Service s;
  291                   if (firstService != null) {
  292                       s = firstService;
  293                       firstService = null;
  294                   } else {
  295                       s = (Service)serviceIterator.next();
  296                   }
  297                   if (JceSecurity.canUseProvider(s.getProvider()) == false) {
  298                       continue;
  299                   }
  300                   try {
  301                       Object obj = s.newInstance(null);
  302                       if (obj instanceof KeyAgreementSpi == false) {
  303                           continue;
  304                       }
  305                       spi = (KeyAgreementSpi)obj;
  306                       provider = s.getProvider();
  307                       // not needed any more
  308                       firstService = null;
  309                       serviceIterator = null;
  310                       return;
  311                   } catch (Exception e) {
  312                       lastException = e;
  313                   }
  314               }
  315               ProviderException e = new ProviderException
  316                       ("Could not construct KeyAgreementSpi instance");
  317               if (lastException != null) {
  318                   e.initCause(lastException);
  319               }
  320               throw e;
  321           }
  322       }
  323   
  324       private final static int I_NO_PARAMS = 1;
  325       private final static int I_PARAMS    = 2;
  326   
  327       private void implInit(KeyAgreementSpi spi, int type, Key key,
  328               AlgorithmParameterSpec params, SecureRandom random)
  329               throws InvalidKeyException, InvalidAlgorithmParameterException {
  330           if (type == I_NO_PARAMS) {
  331               spi.engineInit(key, random);
  332           } else { // I_PARAMS
  333               spi.engineInit(key, params, random);
  334           }
  335       }
  336   
  337       private void chooseProvider(int initType, Key key,
  338               AlgorithmParameterSpec params, SecureRandom random)
  339               throws InvalidKeyException, InvalidAlgorithmParameterException {
  340           synchronized (lock) {
  341               if (spi != null) {
  342                   implInit(spi, initType, key, params, random);
  343                   return;
  344               }
  345               Exception lastException = null;
  346               while ((firstService != null) || serviceIterator.hasNext()) {
  347                   Service s;
  348                   if (firstService != null) {
  349                       s = firstService;
  350                       firstService = null;
  351                   } else {
  352                       s = (Service)serviceIterator.next();
  353                   }
  354                   // if provider says it does not support this key, ignore it
  355                   if (s.supportsParameter(key) == false) {
  356                       continue;
  357                   }
  358                   if (JceSecurity.canUseProvider(s.getProvider()) == false) {
  359                       continue;
  360                   }
  361                   try {
  362                       KeyAgreementSpi spi = (KeyAgreementSpi)s.newInstance(null);
  363                       implInit(spi, initType, key, params, random);
  364                       provider = s.getProvider();
  365                       this.spi = spi;
  366                       firstService = null;
  367                       serviceIterator = null;
  368                       return;
  369                   } catch (Exception e) {
  370                       // NoSuchAlgorithmException from newInstance()
  371                       // InvalidKeyException from init()
  372                       // RuntimeException (ProviderException) from init()
  373                       if (lastException == null) {
  374                           lastException = e;
  375                       }
  376                   }
  377               }
  378               // no working provider found, fail
  379               if (lastException instanceof InvalidKeyException) {
  380                   throw (InvalidKeyException)lastException;
  381               }
  382               if (lastException instanceof InvalidAlgorithmParameterException) {
  383                   throw (InvalidAlgorithmParameterException)lastException;
  384               }
  385               if (lastException instanceof RuntimeException) {
  386                   throw (RuntimeException)lastException;
  387               }
  388               String kName = (key != null) ? key.getClass().getName() : "(null)";
  389               throw new InvalidKeyException
  390                   ("No installed provider supports this key: "
  391                   + kName, lastException);
  392           }
  393       }
  394   
  395       /**
  396        * Returns the provider of this <code>KeyAgreement</code> object.
  397        *
  398        * @return the provider of this <code>KeyAgreement</code> object
  399        */
  400       public final Provider getProvider() {
  401           chooseFirstProvider();
  402           return this.provider;
  403       }
  404   
  405       /**
  406        * Initializes this key agreement with the given key, which is required to
  407        * contain all the algorithm parameters required for this key agreement.
  408        *
  409        * <p> If this key agreement requires any random bytes, it will get
  410        * them using the
  411        * {@link SecureRandom <code>SecureRandom</code>}
  412        * implementation of the highest-priority
  413        * installed provider as the source of randomness.
  414        * (If none of the installed providers supply an implementation of
  415        * SecureRandom, a system-provided source of randomness will be used.)
  416        *
  417        * @param key the party's private information. For example, in the case
  418        * of the Diffie-Hellman key agreement, this would be the party's own
  419        * Diffie-Hellman private key.
  420        *
  421        * @exception InvalidKeyException if the given key is
  422        * inappropriate for this key agreement, e.g., is of the wrong type or
  423        * has an incompatible algorithm type.
  424        */
  425       public final void init(Key key) throws InvalidKeyException {
  426           init(key, JceSecurity.RANDOM);
  427       }
  428   
  429       /**
  430        * Initializes this key agreement with the given key and source of
  431        * randomness. The given key is required to contain all the algorithm
  432        * parameters required for this key agreement.
  433        *
  434        * <p> If the key agreement algorithm requires random bytes, it gets them
  435        * from the given source of randomness, <code>random</code>.
  436        * However, if the underlying
  437        * algorithm implementation does not require any random bytes,
  438        * <code>random</code> is ignored.
  439        *
  440        * @param key the party's private information. For example, in the case
  441        * of the Diffie-Hellman key agreement, this would be the party's own
  442        * Diffie-Hellman private key.
  443        * @param random the source of randomness
  444        *
  445        * @exception InvalidKeyException if the given key is
  446        * inappropriate for this key agreement, e.g., is of the wrong type or
  447        * has an incompatible algorithm type.
  448        */
  449       public final void init(Key key, SecureRandom random)
  450               throws InvalidKeyException {
  451           if (spi != null) {
  452               spi.engineInit(key, random);
  453           } else {
  454               try {
  455                   chooseProvider(I_NO_PARAMS, key, null, random);
  456               } catch (InvalidAlgorithmParameterException e) {
  457                   // should never occur
  458                   throw new InvalidKeyException(e);
  459               }
  460           }
  461       }
  462   
  463       /**
  464        * Initializes this key agreement with the given key and set of
  465        * algorithm parameters.
  466        *
  467        * <p> If this key agreement requires any random bytes, it will get
  468        * them using the
  469        * {@link SecureRandom <code>SecureRandom</code>}
  470        * implementation of the highest-priority
  471        * installed provider as the source of randomness.
  472        * (If none of the installed providers supply an implementation of
  473        * SecureRandom, a system-provided source of randomness will be used.)
  474        *
  475        * @param key the party's private information. For example, in the case
  476        * of the Diffie-Hellman key agreement, this would be the party's own
  477        * Diffie-Hellman private key.
  478        * @param params the key agreement parameters
  479        *
  480        * @exception InvalidKeyException if the given key is
  481        * inappropriate for this key agreement, e.g., is of the wrong type or
  482        * has an incompatible algorithm type.
  483        * @exception InvalidAlgorithmParameterException if the given parameters
  484        * are inappropriate for this key agreement.
  485        */
  486       public final void init(Key key, AlgorithmParameterSpec params)
  487           throws InvalidKeyException, InvalidAlgorithmParameterException
  488       {
  489           init(key, params, JceSecurity.RANDOM);
  490       }
  491   
  492       /**
  493        * Initializes this key agreement with the given key, set of
  494        * algorithm parameters, and source of randomness.
  495        *
  496        * @param key the party's private information. For example, in the case
  497        * of the Diffie-Hellman key agreement, this would be the party's own
  498        * Diffie-Hellman private key.
  499        * @param params the key agreement parameters
  500        * @param random the source of randomness
  501        *
  502        * @exception InvalidKeyException if the given key is
  503        * inappropriate for this key agreement, e.g., is of the wrong type or
  504        * has an incompatible algorithm type.
  505        * @exception InvalidAlgorithmParameterException if the given parameters
  506        * are inappropriate for this key agreement.
  507        */
  508       public final void init(Key key, AlgorithmParameterSpec params,
  509                              SecureRandom random)
  510           throws InvalidKeyException, InvalidAlgorithmParameterException
  511       {
  512           if (spi != null) {
  513               spi.engineInit(key, params, random);
  514           } else {
  515               chooseProvider(I_PARAMS, key, params, random);
  516           }
  517       }
  518   
  519       /**
  520        * Executes the next phase of this key agreement with the given
  521        * key that was received from one of the other parties involved in this key
  522        * agreement.
  523        *
  524        * @param key the key for this phase. For example, in the case of
  525        * Diffie-Hellman between 2 parties, this would be the other party's
  526        * Diffie-Hellman public key.
  527        * @param lastPhase flag which indicates whether or not this is the last
  528        * phase of this key agreement.
  529        *
  530        * @return the (intermediate) key resulting from this phase, or null
  531        * if this phase does not yield a key
  532        *
  533        * @exception InvalidKeyException if the given key is inappropriate for
  534        * this phase.
  535        * @exception IllegalStateException if this key agreement has not been
  536        * initialized.
  537        */
  538       public final Key doPhase(Key key, boolean lastPhase)
  539           throws InvalidKeyException, IllegalStateException
  540       {
  541           chooseFirstProvider();
  542           return spi.engineDoPhase(key, lastPhase);
  543       }
  544   
  545       /**
  546        * Generates the shared secret and returns it in a new buffer.
  547        *
  548        * <p>This method resets this <code>KeyAgreement</code> object, so that it
  549        * can be reused for further key agreements. Unless this key agreement is
  550        * reinitialized with one of the <code>init</code> methods, the same
  551        * private information and algorithm parameters will be used for
  552        * subsequent key agreements.
  553        *
  554        * @return the new buffer with the shared secret
  555        *
  556        * @exception IllegalStateException if this key agreement has not been
  557        * completed yet
  558        */
  559       public final byte[] generateSecret() throws IllegalStateException {
  560           chooseFirstProvider();
  561           return spi.engineGenerateSecret();
  562       }
  563   
  564       /**
  565        * Generates the shared secret, and places it into the buffer
  566        * <code>sharedSecret</code>, beginning at <code>offset</code> inclusive.
  567        *
  568        * <p>If the <code>sharedSecret</code> buffer is too small to hold the
  569        * result, a <code>ShortBufferException</code> is thrown.
  570        * In this case, this call should be repeated with a larger output buffer.
  571        *
  572        * <p>This method resets this <code>KeyAgreement</code> object, so that it
  573        * can be reused for further key agreements. Unless this key agreement is
  574        * reinitialized with one of the <code>init</code> methods, the same
  575        * private information and algorithm parameters will be used for
  576        * subsequent key agreements.
  577        *
  578        * @param sharedSecret the buffer for the shared secret
  579        * @param offset the offset in <code>sharedSecret</code> where the
  580        * shared secret will be stored
  581        *
  582        * @return the number of bytes placed into <code>sharedSecret</code>
  583        *
  584        * @exception IllegalStateException if this key agreement has not been
  585        * completed yet
  586        * @exception ShortBufferException if the given output buffer is too small
  587        * to hold the secret
  588        */
  589       public final int generateSecret(byte[] sharedSecret, int offset)
  590           throws IllegalStateException, ShortBufferException
  591       {
  592           chooseFirstProvider();
  593           return spi.engineGenerateSecret(sharedSecret, offset);
  594       }
  595   
  596       /**
  597        * Creates the shared secret and returns it as a <code>SecretKey</code>
  598        * object of the specified algorithm.
  599        *
  600        * <p>This method resets this <code>KeyAgreement</code> object, so that it
  601        * can be reused for further key agreements. Unless this key agreement is
  602        * reinitialized with one of the <code>init</code> methods, the same
  603        * private information and algorithm parameters will be used for
  604        * subsequent key agreements.
  605        *
  606        * @param algorithm the requested secret-key algorithm
  607        *
  608        * @return the shared secret key
  609        *
  610        * @exception IllegalStateException if this key agreement has not been
  611        * completed yet
  612        * @exception NoSuchAlgorithmException if the specified secret-key
  613        * algorithm is not available
  614        * @exception InvalidKeyException if the shared secret-key material cannot
  615        * be used to generate a secret key of the specified algorithm (e.g.,
  616        * the key material is too short)
  617        */
  618       public final SecretKey generateSecret(String algorithm)
  619           throws IllegalStateException, NoSuchAlgorithmException,
  620               InvalidKeyException
  621       {
  622           chooseFirstProvider();
  623           return spi.engineGenerateSecret(algorithm);
  624       }
  625   }

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