gt:                 throw new InvalidKeyException(e);
context: /*
   * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  
  package javax.crypto;
  
  import java.util.*;
  
  import java.security.*;
  import java.security.Provider.Service;
  import java.security.spec.*;
  
  import sun.security.util.Debug;
  import sun.security.jca.*;
  import sun.security.jca.GetInstance.Instance;
  
  /**
   * This class provides the functionality of a key agreement (or key
   * exchange) protocol.
   * <p>
   * The keys involved in establishing a shared secret are created by one of the
   * key generators ({@code KeyPairGenerator} or
   * {@code KeyGenerator}), a {@code KeyFactory}, or as a result from
   * an intermediate phase of the key agreement protocol.
   *
   * <p> For each of the correspondents in the key exchange, {@code doPhase}
   * needs to be called. For example, if this key exchange is with one other
   * party, {@code doPhase} needs to be called once, with the
   * {@code lastPhase} flag set to {@code true}.
   * If this key exchange is
   * with two other parties, {@code doPhase} needs to be called twice,
   * the first time setting the {@code lastPhase} flag to
   * {@code false}, and the second time setting it to {@code true}.
   * There may be any number of parties involved in a key exchange.
   *
   * <p> Every implementation of the Java platform is required to support the
   * following standard {@code KeyAgreement} algorithm:
   * <ul>
   * <li>{@code DiffieHellman}</li>
   * </ul>
   * This algorithm is described in the <a href=
   * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
   * KeyAgreement section</a> of the
   * Java Cryptography Architecture Standard Algorithm Name Documentation.
   * Consult the release documentation for your implementation to see if any
   * other algorithms are supported.
   *
   * @author Jan Luehe
   *
   * @see KeyGenerator
   * @see SecretKey
   * @since 1.4
   */
  
  public class KeyAgreement {
  
      private static final Debug debug =
                          Debug.getInstance("jca", "KeyAgreement");
  
      private static final Debug pdebug =
                          Debug.getInstance("provider", "Provider");
      private static final boolean skipDebug =
          Debug.isOn("engine=") && !Debug.isOn("keyagreement");
  
      // The provider
      private Provider provider;
  
      // The provider implementation (delegate)
      private KeyAgreementSpi spi;
  
      // The name of the key agreement algorithm.
      private final String algorithm;
  
      // next service to try in provider selection
      // null once provider is selected
      private Service firstService;
  
      // remaining services to try in provider selection
      // null once provider is selected
      private Iterator<Service> serviceIterator;
  
      private final Object lock;
  
      /**
       * Creates a KeyAgreement object.
       *
       * @param keyAgreeSpi the delegate
       * @param provider the provider
       * @param algorithm the algorithm
       */
      protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider,
                             String algorithm) {
          this.spi = keyAgreeSpi;
          this.provider = provider;
          this.algorithm = algorithm;
          lock = null;
      }
  
      private KeyAgreement(Service s, Iterator<Service> t, String algorithm) {
          firstService = s;
          serviceIterator = t;
          this.algorithm = algorithm;
          lock = new Object();
      }
  
      /**
       * Returns the algorithm name of this {@code KeyAgreement} object.
       *
       * <p>This is the same name that was specified in one of the
       * {@code getInstance} calls that created this
       * {@code KeyAgreement} object.
       *
       * @return the algorithm name of this {@code KeyAgreement} object.
       */
      public final String getAlgorithm() {
          return this.algorithm;
      }
  
      /**
       * Returns a {@code KeyAgreement} object that implements the
       * specified key agreement algorithm.
       *
       * <p> This method traverses the list of registered security Providers,
       * starting with the most preferred Provider.
       * A new KeyAgreement object encapsulating the
       * KeyAgreementSpi implementation from the first
       * Provider that supports the specified algorithm is returned.
       *
       * <p> Note that the list of registered providers may be retrieved via
       * the {@link Security#getProviders() Security.getProviders()} method.
       *
       * @param algorithm the standard name of the requested key agreement
       * algorithm.
       * See the KeyAgreement section in the <a href=
       * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
       * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
       * for information about standard algorithm names.
       *
       * @return the new {@code KeyAgreement} object.
       *
       * @exception NullPointerException if the specified algorithm
       *          is null.
       *
       * @exception NoSuchAlgorithmException if no Provider supports a
       *          KeyAgreementSpi implementation for the
       *          specified algorithm.
       *
       * @see java.security.Provider
       */
      public static final KeyAgreement getInstance(String algorithm)
              throws NoSuchAlgorithmException {
          List<Service> services =
                  GetInstance.getServices("KeyAgreement", algorithm);
          // make sure there is at least one service from a signed provider
          Iterator<Service> t = services.iterator();
          while (t.hasNext()) {
              Service s = t.next();
              if (JceSecurity.canUseProvider(s.getProvider()) == false) {
                  continue;
              }
              return new KeyAgreement(s, t, algorithm);
          }
          throw new NoSuchAlgorithmException
                                  ("Algorithm " + algorithm + " not available");
      }
  
      /**
       * Returns a {@code KeyAgreement} object that implements the
       * specified key agreement algorithm.
       *
       * <p> A new KeyAgreement object encapsulating the
       * KeyAgreementSpi implementation from the specified provider
       * is returned.  The specified provider must be registered
       * in the security provider list.
       *
       * <p> Note that the list of registered providers may be retrieved via
       * the {@link Security#getProviders() Security.getProviders()} method.
       *
       * @param algorithm the standard name of the requested key agreement
       * algorithm.
       * See the KeyAgreement section in the <a href=
       * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
       * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
       * for information about standard algorithm names.
       *
       * @param provider the name of the provider.
       *
       * @return the new {@code KeyAgreement} object.
       *
       * @exception NullPointerException if the specified algorithm
       *          is null.
       *
       * @exception NoSuchAlgorithmException if a KeyAgreementSpi
       *          implementation for the specified algorithm is not
       *          available from the specified provider.
       *
       * @exception NoSuchProviderException if the specified provider is not
       *          registered in the security provider list.
       *
       * @exception IllegalArgumentException if the {@code provider}
       *          is null or empty.
       *
       * @see java.security.Provider
       */
      public static final KeyAgreement getInstance(String algorithm,
              String provider) throws NoSuchAlgorithmException,
              NoSuchProviderException {
          Instance instance = JceSecurity.getInstance
                  ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
          return new KeyAgreement((KeyAgreementSpi)instance.impl,
                  instance.provider, algorithm);
      }
  
      /**
       * Returns a {@code KeyAgreement} object that implements the
       * specified key agreement algorithm.
       *
       * <p> A new KeyAgreement object encapsulating the
       * KeyAgreementSpi implementation from the specified Provider
       * object is returned.  Note that the specified Provider object
       * does not have to be registered in the provider list.
       *
       * @param algorithm the standard name of the requested key agreement
       * algorithm.
       * See the KeyAgreement section in the <a href=
       * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
       * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
       * for information about standard algorithm names.
       *
       * @param provider the provider.
       *
       * @return the new {@code KeyAgreement} object.
       *
       * @exception NullPointerException if the specified algorithm
       *          is null.
       *
       * @exception NoSuchAlgorithmException if a KeyAgreementSpi
       *          implementation for the specified algorithm is not available
       *          from the specified Provider object.
       *
       * @exception IllegalArgumentException if the {@code provider}
       *          is null.
       *
       * @see java.security.Provider
       */
      public static final KeyAgreement getInstance(String algorithm,
              Provider provider) throws NoSuchAlgorithmException {
          Instance instance = JceSecurity.getInstance
                  ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
          return new KeyAgreement((KeyAgreementSpi)instance.impl,
                  instance.provider, algorithm);
      }
  
      // max number of debug warnings to print from chooseFirstProvider()
      private static int warnCount = 10;
  
      /**
       * Choose the Spi from the first provider available. Used if
       * delayed provider selection is not possible because init()
       * is not the first method called.
       */
      void chooseFirstProvider() {
          if (spi != null) {
              return;
          }
          synchronized (lock) {
              if (spi != null) {
                  return;
              }
              if (debug != null) {
                  int w = --warnCount;
                  if (w >= 0) {
                      debug.println("KeyAgreement.init() not first method "
                          + "called, disabling delayed provider selection");
                      if (w == 0) {
                          debug.println("Further warnings of this type will "
                              + "be suppressed");
                      }
                      new Exception("Call trace").printStackTrace();
                  }
              }
              Exception lastException = null;
              while ((firstService != null) || serviceIterator.hasNext()) {
                  Service s;
                  if (firstService != null) {
                      s = firstService;
                      firstService = null;
                  } else {
                      s = serviceIterator.next();
                  }
                  if (JceSecurity.canUseProvider(s.getProvider()) == false) {
                      continue;
                  }
                  try {
                      Object obj = s.newInstance(null);
                      if (obj instanceof KeyAgreementSpi == false) {
                          continue;
                      }
                      spi = (KeyAgreementSpi)obj;
                      provider = s.getProvider();
                      // not needed any more
                      firstService = null;
                      serviceIterator = null;
                      return;
                  } catch (Exception e) {
                      lastException = e;
                  }
              }
              ProviderException e = new ProviderException
                      ("Could not construct KeyAgreementSpi instance");
              if (lastException != null) {
                  e.initCause(lastException);
              }
              throw e;
          }
      }
  
      private final static int I_NO_PARAMS = 1;
      private final static int I_PARAMS    = 2;
  
      private void implInit(KeyAgreementSpi spi, int type, Key key,
              AlgorithmParameterSpec params, SecureRandom random)
              throws InvalidKeyException, InvalidAlgorithmParameterException {
          if (type == I_NO_PARAMS) {
              spi.engineInit(key, random);
          } else { // I_PARAMS
              spi.engineInit(key, params, random);
          }
      }
  
      private void chooseProvider(int initType, Key key,
              AlgorithmParameterSpec params, SecureRandom random)
              throws InvalidKeyException, InvalidAlgorithmParameterException {
          synchronized (lock) {
              if (spi != null) {
                  implInit(spi, initType, key, params, random);
                  return;
              }
              Exception lastException = null;
              while ((firstService != null) || serviceIterator.hasNext()) {
                  Service s;
                  if (firstService != null) {
                      s = firstService;
                      firstService = null;
                  } else {
                      s = serviceIterator.next();
                  }
                  // if provider says it does not support this key, ignore it
                  if (s.supportsParameter(key) == false) {
                      continue;
                  }
                  if (JceSecurity.canUseProvider(s.getProvider()) == false) {
                      continue;
                  }
                  try {
                      KeyAgreementSpi spi = (KeyAgreementSpi)s.newInstance(null);
                      implInit(spi, initType, key, params, random);
                      provider = s.getProvider();
                      this.spi = spi;
                      firstService = null;
                      serviceIterator = null;
                      return;
                  } catch (Exception e) {
                      // NoSuchAlgorithmException from newInstance()
                      // InvalidKeyException from init()
                      // RuntimeException (ProviderException) from init()
                      if (lastException == null) {
                          lastException = e;
                      }
                  }
              }
              // no working provider found, fail
              if (lastException instanceof InvalidKeyException) {
                  throw (InvalidKeyException)lastException;
              }
              if (lastException instanceof InvalidAlgorithmParameterException) {
                  throw (InvalidAlgorithmParameterException)lastException;
              }
              if (lastException instanceof RuntimeException) {
                  throw (RuntimeException)lastException;
              }
              String kName = (key != null) ? key.getClass().getName() : "(null)";
              throw new InvalidKeyException
                  ("No installed provider supports this key: "
                  + kName, lastException);
          }
      }
  
      /**
       * Returns the provider of this {@code KeyAgreement} object.
       *
       * @return the provider of this {@code KeyAgreement} object
       */
      public final Provider getProvider() {
          chooseFirstProvider();
          return this.provider;
      }
  
      /**
       * Initializes this key agreement with the given key, which is required to
       * contain all the algorithm parameters required for this key agreement.
       *
       * <p> If this key agreement requires any random bytes, it will get
       * them using the
       * {@link java.security.SecureRandom}
       * implementation of the highest-priority
       * installed provider as the source of randomness.
       * (If none of the installed providers supply an implementation of
       * SecureRandom, a system-provided source of randomness will be used.)
       *
       * @param key the party's private information. For example, in the case
       * of the Diffie-Hellman key agreement, this would be the party's own
       * Diffie-Hellman private key.
       *
       * @exception InvalidKeyException if the given key is
       * inappropriate for this key agreement, e.g., is of the wrong type or
       * has an incompatible algorithm type.
       */
      public final void init(Key key) throws InvalidKeyException {
          init(key, JceSecurity.RANDOM);
      }
  
      /**
       * Initializes this key agreement with the given key and source of
       * randomness. The given key is required to contain all the algorithm
       * parameters required for this key agreement.
       *
       * <p> If the key agreement algorithm requires random bytes, it gets them
       * from the given source of randomness, {@code random}.
       * However, if the underlying
       * algorithm implementation does not require any random bytes,
       * {@code random} is ignored.
       *
       * @param key the party's private information. For example, in the case
       * of the Diffie-Hellman key agreement, this would be the party's own
       * Diffie-Hellman private key.
       * @param random the source of randomness
       *
       * @exception InvalidKeyException if the given key is
       * inappropriate for this key agreement, e.g., is of the wrong type or
       * has an incompatible algorithm type.
       */
      public final void init(Key key, SecureRandom random)
              throws InvalidKeyException {
          if (spi != null) {
              spi.engineInit(key, random);
          } else {
              try {
                  chooseProvider(I_NO_PARAMS, key, null, random);
              } catch (InvalidAlgorithmParameterException e) {
                  // should never occur
  