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