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