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