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