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 }