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