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