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