Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java
41161 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 com.sun.crypto.provider;
27
28
import java.util.*;
29
import java.lang.*;
30
import java.math.BigInteger;
31
import java.security.AccessController;
32
import java.security.InvalidAlgorithmParameterException;
33
import java.security.InvalidKeyException;
34
import java.security.Key;
35
import java.security.NoSuchAlgorithmException;
36
import java.security.SecureRandom;
37
import java.security.PrivilegedAction;
38
import java.security.ProviderException;
39
import java.security.spec.AlgorithmParameterSpec;
40
import java.security.spec.InvalidKeySpecException;
41
import javax.crypto.KeyAgreementSpi;
42
import javax.crypto.ShortBufferException;
43
import javax.crypto.SecretKey;
44
import javax.crypto.spec.*;
45
46
import sun.security.util.KeyUtil;
47
48
/**
49
* This class implements the Diffie-Hellman key agreement protocol between
50
* any number of parties.
51
*
52
* @author Jan Luehe
53
*
54
*/
55
56
public final class DHKeyAgreement
57
extends KeyAgreementSpi {
58
59
private boolean generateSecret = false;
60
private BigInteger init_p = null;
61
private BigInteger init_g = null;
62
private BigInteger x = BigInteger.ZERO; // the private value
63
private BigInteger y = BigInteger.ZERO;
64
65
private static class AllowKDF {
66
67
private static final boolean VALUE = getValue();
68
69
@SuppressWarnings("removal")
70
private static boolean getValue() {
71
return AccessController.doPrivileged(
72
(PrivilegedAction<Boolean>)
73
() -> Boolean.getBoolean("jdk.crypto.KeyAgreement.legacyKDF"));
74
}
75
}
76
77
/**
78
* Empty constructor
79
*/
80
public DHKeyAgreement() {
81
}
82
83
/**
84
* Initializes this key agreement with the given key and source of
85
* randomness. The given key is required to contain all the algorithm
86
* parameters required for this key agreement.
87
*
88
* <p> If the key agreement algorithm requires random bytes, it gets them
89
* from the given source of randomness, <code>random</code>.
90
* However, if the underlying
91
* algorithm implementation does not require any random bytes,
92
* <code>random</code> is ignored.
93
*
94
* @param key the party's private information. For example, in the case
95
* of the Diffie-Hellman key agreement, this would be the party's own
96
* Diffie-Hellman private key.
97
* @param random the source of randomness
98
*
99
* @exception InvalidKeyException if the given key is
100
* inappropriate for this key agreement, e.g., is of the wrong type or
101
* has an incompatible algorithm type.
102
*/
103
protected void engineInit(Key key, SecureRandom random)
104
throws InvalidKeyException
105
{
106
try {
107
engineInit(key, null, random);
108
} catch (InvalidAlgorithmParameterException e) {
109
// never happens, because we did not pass any parameters
110
}
111
}
112
113
/**
114
* Initializes this key agreement with the given key, set of
115
* algorithm parameters, and source of randomness.
116
*
117
* @param key the party's private information. For example, in the case
118
* of the Diffie-Hellman key agreement, this would be the party's own
119
* Diffie-Hellman private key.
120
* @param params the key agreement parameters
121
* @param random the source of randomness
122
*
123
* @exception InvalidKeyException if the given key is
124
* inappropriate for this key agreement, e.g., is of the wrong type or
125
* has an incompatible algorithm type.
126
* @exception InvalidAlgorithmParameterException if the given parameters
127
* are inappropriate for this key agreement.
128
*/
129
protected void engineInit(Key key, AlgorithmParameterSpec params,
130
SecureRandom random)
131
throws InvalidKeyException, InvalidAlgorithmParameterException
132
{
133
// ignore "random" parameter, because our implementation does not
134
// require any source of randomness
135
generateSecret = false;
136
init_p = null;
137
init_g = null;
138
139
if ((params != null) && !(params instanceof DHParameterSpec)) {
140
throw new InvalidAlgorithmParameterException
141
("Diffie-Hellman parameters expected");
142
}
143
if (!(key instanceof javax.crypto.interfaces.DHPrivateKey)) {
144
throw new InvalidKeyException("Diffie-Hellman private key "
145
+ "expected");
146
}
147
javax.crypto.interfaces.DHPrivateKey dhPrivKey;
148
dhPrivKey = (javax.crypto.interfaces.DHPrivateKey)key;
149
150
// check if private key parameters are compatible with
151
// initialized ones
152
if (params != null) {
153
init_p = ((DHParameterSpec)params).getP();
154
init_g = ((DHParameterSpec)params).getG();
155
}
156
BigInteger priv_p = dhPrivKey.getParams().getP();
157
BigInteger priv_g = dhPrivKey.getParams().getG();
158
if (init_p != null && priv_p != null && !(init_p.equals(priv_p))) {
159
throw new InvalidKeyException("Incompatible parameters");
160
}
161
if (init_g != null && priv_g != null && !(init_g.equals(priv_g))) {
162
throw new InvalidKeyException("Incompatible parameters");
163
}
164
if ((init_p == null && priv_p == null)
165
|| (init_g == null && priv_g == null)) {
166
throw new InvalidKeyException("Missing parameters");
167
}
168
init_p = priv_p;
169
init_g = priv_g;
170
171
// store the x value
172
this.x = dhPrivKey.getX();
173
}
174
175
/**
176
* Executes the next phase of this key agreement with the given
177
* key that was received from one of the other parties involved in this key
178
* agreement.
179
*
180
* @param key the key for this phase. For example, in the case of
181
* Diffie-Hellman between 2 parties, this would be the other party's
182
* Diffie-Hellman public key.
183
* @param lastPhase flag which indicates whether or not this is the last
184
* phase of this key agreement.
185
*
186
* @return the (intermediate) key resulting from this phase, or null if
187
* this phase does not yield a key
188
*
189
* @exception InvalidKeyException if the given key is inappropriate for
190
* this phase.
191
* @exception IllegalStateException if this key agreement has not been
192
* initialized.
193
*/
194
protected Key engineDoPhase(Key key, boolean lastPhase)
195
throws InvalidKeyException, IllegalStateException
196
{
197
if (!(key instanceof javax.crypto.interfaces.DHPublicKey)) {
198
throw new InvalidKeyException("Diffie-Hellman public key "
199
+ "expected");
200
}
201
javax.crypto.interfaces.DHPublicKey dhPubKey;
202
dhPubKey = (javax.crypto.interfaces.DHPublicKey)key;
203
204
if (init_p == null || init_g == null) {
205
throw new IllegalStateException("Not initialized");
206
}
207
208
// check if public key parameters are compatible with
209
// initialized ones
210
BigInteger pub_p = dhPubKey.getParams().getP();
211
BigInteger pub_g = dhPubKey.getParams().getG();
212
if (pub_p != null && !(init_p.equals(pub_p))) {
213
throw new InvalidKeyException("Incompatible parameters");
214
}
215
if (pub_g != null && !(init_g.equals(pub_g))) {
216
throw new InvalidKeyException("Incompatible parameters");
217
}
218
219
// validate the Diffie-Hellman public key
220
KeyUtil.validate(dhPubKey);
221
222
// store the y value
223
this.y = dhPubKey.getY();
224
225
// we've received a public key (from one of the other parties),
226
// so we are ready to create the secret, which may be an
227
// intermediate secret, in which case we wrap it into a
228
// Diffie-Hellman public key object and return it.
229
generateSecret = true;
230
if (lastPhase == false) {
231
byte[] intermediate = engineGenerateSecret();
232
return new DHPublicKey(new BigInteger(1, intermediate),
233
init_p, init_g);
234
} else {
235
return null;
236
}
237
}
238
239
/**
240
* Generates the shared secret and returns it in a new buffer.
241
*
242
* <p>This method resets this <code>KeyAgreementSpi</code> object,
243
* so that it
244
* can be reused for further key agreements. Unless this key agreement is
245
* reinitialized with one of the <code>engineInit</code> methods, the same
246
* private information and algorithm parameters will be used for
247
* subsequent key agreements.
248
*
249
* @return the new buffer with the shared secret
250
*
251
* @exception IllegalStateException if this key agreement has not been
252
* completed yet
253
*/
254
protected byte[] engineGenerateSecret()
255
throws IllegalStateException
256
{
257
int expectedLen = (init_p.bitLength() + 7) >>> 3;
258
byte[] result = new byte[expectedLen];
259
try {
260
engineGenerateSecret(result, 0);
261
} catch (ShortBufferException sbe) {
262
// should never happen since length are identical
263
}
264
return result;
265
}
266
267
/**
268
* Generates the shared secret, and places it into the buffer
269
* <code>sharedSecret</code>, beginning at <code>offset</code>.
270
*
271
* <p>If the <code>sharedSecret</code> buffer is too small to hold the
272
* result, a <code>ShortBufferException</code> is thrown.
273
* In this case, this call should be repeated with a larger output buffer.
274
*
275
* <p>This method resets this <code>KeyAgreementSpi</code> object,
276
* so that it
277
* can be reused for further key agreements. Unless this key agreement is
278
* reinitialized with one of the <code>engineInit</code> methods, the same
279
* private information and algorithm parameters will be used for
280
* subsequent key agreements.
281
*
282
* @param sharedSecret the buffer for the shared secret
283
* @param offset the offset in <code>sharedSecret</code> where the
284
* shared secret will be stored
285
*
286
* @return the number of bytes placed into <code>sharedSecret</code>
287
*
288
* @exception IllegalStateException if this key agreement has not been
289
* completed yet
290
* @exception ShortBufferException if the given output buffer is too small
291
* to hold the secret
292
*/
293
protected int engineGenerateSecret(byte[] sharedSecret, int offset)
294
throws IllegalStateException, ShortBufferException
295
{
296
if (generateSecret == false) {
297
throw new IllegalStateException
298
("Key agreement has not been completed yet");
299
}
300
301
if (sharedSecret == null) {
302
throw new ShortBufferException
303
("No buffer provided for shared secret");
304
}
305
306
BigInteger modulus = init_p;
307
int expectedLen = (modulus.bitLength() + 7) >>> 3;
308
if ((sharedSecret.length - offset) < expectedLen) {
309
throw new ShortBufferException
310
("Buffer too short for shared secret");
311
}
312
313
// Reset the key agreement after checking for ShortBufferException
314
// above, so user can recover w/o losing internal state
315
generateSecret = false;
316
317
// No further process if z <= 1 or z == (p - 1) (See section 5.7.1,
318
// NIST SP 800-56A Rev 3).
319
BigInteger z = this.y.modPow(this.x, modulus);
320
if ((z.compareTo(BigInteger.ONE) <= 0) ||
321
z.equals(modulus.subtract(BigInteger.ONE))) {
322
throw new ProviderException(
323
"Generated secret is out-of-range of (1, p -1)");
324
}
325
326
/*
327
* NOTE: BigInteger.toByteArray() returns a byte array containing
328
* the two's-complement representation of this BigInteger with
329
* the most significant byte is in the zeroth element. This
330
* contains the minimum number of bytes required to represent
331
* this BigInteger, including at least one sign bit whose value
332
* is always 0.
333
*
334
* Keys are always positive, and the above sign bit isn't
335
* actually used when representing keys. (i.e. key = new
336
* BigInteger(1, byteArray)) To obtain an array containing
337
* exactly expectedLen bytes of magnitude, we strip any extra
338
* leading 0's, or pad with 0's in case of a "short" secret.
339
*/
340
byte[] secret = z.toByteArray();
341
if (secret.length == expectedLen) {
342
System.arraycopy(secret, 0, sharedSecret, offset,
343
secret.length);
344
} else {
345
// Array too short, pad it w/ leading 0s
346
if (secret.length < expectedLen) {
347
System.arraycopy(secret, 0, sharedSecret,
348
offset + (expectedLen - secret.length),
349
secret.length);
350
} else {
351
// Array too long, check and trim off the excess
352
if ((secret.length == (expectedLen+1)) && secret[0] == 0) {
353
// ignore the leading sign byte
354
System.arraycopy(secret, 1, sharedSecret, offset, expectedLen);
355
} else {
356
throw new ProviderException("Generated secret is out-of-range");
357
}
358
}
359
}
360
return expectedLen;
361
}
362
363
/**
364
* Creates the shared secret and returns it as a secret key object
365
* of the requested algorithm type.
366
*
367
* <p>This method resets this <code>KeyAgreementSpi</code> object,
368
* so that it
369
* can be reused for further key agreements. Unless this key agreement is
370
* reinitialized with one of the <code>engineInit</code> methods, the same
371
* private information and algorithm parameters will be used for
372
* subsequent key agreements.
373
*
374
* @param algorithm the requested secret key algorithm
375
*
376
* @return the shared secret key
377
*
378
* @exception IllegalStateException if this key agreement has not been
379
* completed yet
380
* @exception NoSuchAlgorithmException if the requested secret key
381
* algorithm is not available
382
* @exception InvalidKeyException if the shared secret key material cannot
383
* be used to generate a secret key of the requested algorithm type (e.g.,
384
* the key material is too short)
385
*/
386
protected SecretKey engineGenerateSecret(String algorithm)
387
throws IllegalStateException, NoSuchAlgorithmException,
388
InvalidKeyException
389
{
390
if (algorithm == null) {
391
throw new NoSuchAlgorithmException("null algorithm");
392
}
393
394
if (!algorithm.equalsIgnoreCase("TlsPremasterSecret") &&
395
!AllowKDF.VALUE) {
396
397
throw new NoSuchAlgorithmException("Unsupported secret key "
398
+ "algorithm: " + algorithm);
399
}
400
401
byte[] secret = engineGenerateSecret();
402
if (algorithm.equalsIgnoreCase("DES")) {
403
// DES
404
return new DESKey(secret);
405
} else if (algorithm.equalsIgnoreCase("DESede")
406
|| algorithm.equalsIgnoreCase("TripleDES")) {
407
// Triple DES
408
return new DESedeKey(secret);
409
} else if (algorithm.equalsIgnoreCase("Blowfish")) {
410
// Blowfish
411
int keysize = secret.length;
412
if (keysize >= BlowfishConstants.BLOWFISH_MAX_KEYSIZE)
413
keysize = BlowfishConstants.BLOWFISH_MAX_KEYSIZE;
414
SecretKeySpec skey = new SecretKeySpec(secret, 0, keysize,
415
"Blowfish");
416
return skey;
417
} else if (algorithm.equalsIgnoreCase("AES")) {
418
// AES
419
int keysize = secret.length;
420
SecretKeySpec skey = null;
421
int idx = AESConstants.AES_KEYSIZES.length - 1;
422
while (skey == null && idx >= 0) {
423
// Generate the strongest key using the shared secret
424
// assuming the key sizes in AESConstants class are
425
// in ascending order
426
if (keysize >= AESConstants.AES_KEYSIZES[idx]) {
427
keysize = AESConstants.AES_KEYSIZES[idx];
428
skey = new SecretKeySpec(secret, 0, keysize, "AES");
429
}
430
idx--;
431
}
432
if (skey == null) {
433
throw new InvalidKeyException("Key material is too short");
434
}
435
return skey;
436
} else if (algorithm.equals("TlsPremasterSecret")) {
437
// remove leading zero bytes per RFC 5246 Section 8.1.2
438
return new SecretKeySpec(
439
KeyUtil.trimZeroes(secret), "TlsPremasterSecret");
440
} else {
441
throw new NoSuchAlgorithmException("Unsupported secret key "
442
+ "algorithm: "+ algorithm);
443
}
444
}
445
}
446
447