Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/util/KeyUtil.java
41159 views
1
/*
2
* Copyright (c) 2012, 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 sun.security.util;
27
28
import java.security.AlgorithmParameters;
29
import java.security.Key;
30
import java.security.InvalidKeyException;
31
import java.security.interfaces.ECKey;
32
import java.security.interfaces.EdECKey;
33
import java.security.interfaces.EdECPublicKey;
34
import java.security.interfaces.RSAKey;
35
import java.security.interfaces.DSAKey;
36
import java.security.interfaces.DSAParams;
37
import java.security.interfaces.XECKey;
38
import java.security.SecureRandom;
39
import java.security.spec.AlgorithmParameterSpec;
40
import java.security.spec.KeySpec;
41
import java.security.spec.ECParameterSpec;
42
import java.security.spec.InvalidParameterSpecException;
43
import javax.crypto.SecretKey;
44
import javax.crypto.interfaces.DHKey;
45
import javax.crypto.interfaces.DHPublicKey;
46
import javax.crypto.spec.DHParameterSpec;
47
import javax.crypto.spec.DHPublicKeySpec;
48
import java.math.BigInteger;
49
import java.security.spec.NamedParameterSpec;
50
import java.util.Arrays;
51
52
import sun.security.jca.JCAUtil;
53
54
/**
55
* A utility class to get key length, valiate keys, etc.
56
*/
57
public final class KeyUtil {
58
59
/**
60
* Returns the key size of the given key object in bits.
61
*
62
* @param key the key object, cannot be null
63
* @return the key size of the given key object in bits, or -1 if the
64
* key size is not accessible
65
*/
66
public static final int getKeySize(Key key) {
67
int size = -1;
68
69
if (key instanceof Length) {
70
try {
71
Length ruler = (Length)key;
72
size = ruler.length();
73
} catch (UnsupportedOperationException usoe) {
74
// ignore the exception
75
}
76
77
if (size >= 0) {
78
return size;
79
}
80
}
81
82
// try to parse the length from key specification
83
if (key instanceof SecretKey) {
84
SecretKey sk = (SecretKey)key;
85
String format = sk.getFormat();
86
if ("RAW".equals(format)) {
87
byte[] encoded = sk.getEncoded();
88
if (encoded != null) {
89
size = (encoded.length * 8);
90
Arrays.fill(encoded, (byte)0);
91
}
92
} // Otherwise, it may be a unextractable key of PKCS#11, or
93
// a key we are not able to handle.
94
} else if (key instanceof RSAKey) {
95
RSAKey pubk = (RSAKey)key;
96
size = pubk.getModulus().bitLength();
97
} else if (key instanceof ECKey) {
98
ECKey pubk = (ECKey)key;
99
size = pubk.getParams().getOrder().bitLength();
100
} else if (key instanceof DSAKey) {
101
DSAKey pubk = (DSAKey)key;
102
DSAParams params = pubk.getParams(); // params can be null
103
size = (params != null) ? params.getP().bitLength() : -1;
104
} else if (key instanceof DHKey) {
105
DHKey pubk = (DHKey)key;
106
size = pubk.getParams().getP().bitLength();
107
} else if (key instanceof XECKey) {
108
XECKey pubk = (XECKey)key;
109
AlgorithmParameterSpec params = pubk.getParams();
110
if (params instanceof NamedParameterSpec) {
111
String name = ((NamedParameterSpec) params).getName();
112
if (name.equalsIgnoreCase(NamedParameterSpec.X25519.getName())) {
113
size = 255;
114
} else if (name.equalsIgnoreCase(NamedParameterSpec.X448.getName())) {
115
size = 448;
116
} else {
117
size = -1;
118
}
119
} else {
120
size = -1;
121
}
122
} else if (key instanceof EdECKey) {
123
String nc = ((EdECKey) key).getParams().getName();
124
if (nc.equalsIgnoreCase(NamedParameterSpec.ED25519.getName())) {
125
size = 255;
126
} else if (nc.equalsIgnoreCase(
127
NamedParameterSpec.ED448.getName())) {
128
size = 448;
129
} else {
130
size = -1;
131
}
132
} // Otherwise, it may be a unextractable key of PKCS#11, or
133
// a key we are not able to handle.
134
135
return size;
136
}
137
138
/**
139
* Returns the key size of the given cryptographic parameters in bits.
140
*
141
* @param parameters the cryptographic parameters, cannot be null
142
* @return the key size of the given cryptographic parameters in bits,
143
* or -1 if the key size is not accessible
144
*/
145
public static final int getKeySize(AlgorithmParameters parameters) {
146
147
String algorithm = parameters.getAlgorithm();
148
switch (algorithm) {
149
case "EC":
150
try {
151
ECKeySizeParameterSpec ps = parameters.getParameterSpec(
152
ECKeySizeParameterSpec.class);
153
if (ps != null) {
154
return ps.getKeySize();
155
}
156
} catch (InvalidParameterSpecException ipse) {
157
// ignore
158
}
159
160
try {
161
ECParameterSpec ps = parameters.getParameterSpec(
162
ECParameterSpec.class);
163
if (ps != null) {
164
return ps.getOrder().bitLength();
165
}
166
} catch (InvalidParameterSpecException ipse) {
167
// ignore
168
}
169
170
// Note: the ECGenParameterSpec case should be covered by the
171
// ECParameterSpec case above.
172
// See ECUtil.getECParameterSpec(Provider, String).
173
174
break;
175
case "DiffieHellman":
176
try {
177
DHParameterSpec ps = parameters.getParameterSpec(
178
DHParameterSpec.class);
179
if (ps != null) {
180
return ps.getP().bitLength();
181
}
182
} catch (InvalidParameterSpecException ipse) {
183
// ignore
184
}
185
break;
186
187
// May support more AlgorithmParameters algorithms in the future.
188
}
189
190
return -1;
191
}
192
193
/**
194
* Returns whether the key is valid or not.
195
* <P>
196
* Note that this method is only apply to DHPublicKey at present.
197
*
198
* @param key the key object, cannot be null
199
*
200
* @throws NullPointerException if {@code key} is null
201
* @throws InvalidKeyException if {@code key} is invalid
202
*/
203
public static final void validate(Key key)
204
throws InvalidKeyException {
205
if (key == null) {
206
throw new NullPointerException(
207
"The key to be validated cannot be null");
208
}
209
210
if (key instanceof DHPublicKey) {
211
validateDHPublicKey((DHPublicKey)key);
212
}
213
}
214
215
216
/**
217
* Returns whether the key spec is valid or not.
218
* <P>
219
* Note that this method is only apply to DHPublicKeySpec at present.
220
*
221
* @param keySpec
222
* the key spec object, cannot be null
223
*
224
* @throws NullPointerException if {@code keySpec} is null
225
* @throws InvalidKeyException if {@code keySpec} is invalid
226
*/
227
public static final void validate(KeySpec keySpec)
228
throws InvalidKeyException {
229
if (keySpec == null) {
230
throw new NullPointerException(
231
"The key spec to be validated cannot be null");
232
}
233
234
if (keySpec instanceof DHPublicKeySpec) {
235
validateDHPublicKey((DHPublicKeySpec)keySpec);
236
}
237
}
238
239
/**
240
* Returns whether the specified provider is Oracle provider or not.
241
*
242
* @param providerName
243
* the provider name
244
* @return true if, and only if, the provider of the specified
245
* {@code providerName} is Oracle provider
246
*/
247
public static final boolean isOracleJCEProvider(String providerName) {
248
return providerName != null &&
249
(providerName.equals("SunJCE") ||
250
providerName.equals("SunMSCAPI") ||
251
providerName.startsWith("SunPKCS11"));
252
}
253
254
/**
255
* Check the format of TLS PreMasterSecret.
256
* <P>
257
* To avoid vulnerabilities described by section 7.4.7.1, RFC 5246,
258
* treating incorrectly formatted message blocks and/or mismatched
259
* version numbers in a manner indistinguishable from correctly
260
* formatted RSA blocks.
261
*
262
* RFC 5246 describes the approach as:
263
* <pre>{@literal
264
*
265
* 1. Generate a string R of 48 random bytes
266
*
267
* 2. Decrypt the message to recover the plaintext M
268
*
269
* 3. If the PKCS#1 padding is not correct, or the length of message
270
* M is not exactly 48 bytes:
271
* pre_master_secret = R
272
* else If ClientHello.client_version <= TLS 1.0, and version
273
* number check is explicitly disabled:
274
* premaster secret = M
275
* else If M[0..1] != ClientHello.client_version:
276
* premaster secret = R
277
* else:
278
* premaster secret = M
279
*
280
* Note that #2 should have completed before the call to this method.
281
* }</pre>
282
*
283
* @param clientVersion the version of the TLS protocol by which the
284
* client wishes to communicate during this session
285
* @param serverVersion the negotiated version of the TLS protocol which
286
* contains the lower of that suggested by the client in the client
287
* hello and the highest supported by the server.
288
* @param encoded the encoded key in its "RAW" encoding format
289
* @param isFailOver whether or not the previous decryption of the
290
* encrypted PreMasterSecret message run into problem
291
* @return the polished PreMasterSecret key in its "RAW" encoding format
292
*/
293
public static byte[] checkTlsPreMasterSecretKey(
294
int clientVersion, int serverVersion, SecureRandom random,
295
byte[] encoded, boolean isFailOver) {
296
297
if (random == null) {
298
random = JCAUtil.getSecureRandom();
299
}
300
byte[] replacer = new byte[48];
301
random.nextBytes(replacer);
302
303
if (!isFailOver && (encoded != null)) {
304
// check the length
305
if (encoded.length != 48) {
306
// private, don't need to clone the byte array.
307
return replacer;
308
}
309
310
int encodedVersion =
311
((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF);
312
if (clientVersion != encodedVersion) {
313
if (clientVersion > 0x0301 || // 0x0301: TLSv1
314
serverVersion != encodedVersion) {
315
encoded = replacer;
316
} // Otherwise, For compatibility, we maintain the behavior
317
// that the version in pre_master_secret can be the
318
// negotiated version for TLS v1.0 and SSL v3.0.
319
}
320
321
// private, don't need to clone the byte array.
322
return encoded;
323
}
324
325
// private, don't need to clone the byte array.
326
return replacer;
327
}
328
329
/**
330
* Returns whether the Diffie-Hellman public key is valid or not.
331
*
332
* Per RFC 2631 and NIST SP800-56A, the following algorithm is used to
333
* validate Diffie-Hellman public keys:
334
* 1. Verify that y lies within the interval [2,p-1]. If it does not,
335
* the key is invalid.
336
* 2. Compute y^q mod p. If the result == 1, the key is valid.
337
* Otherwise the key is invalid.
338
*/
339
private static void validateDHPublicKey(DHPublicKey publicKey)
340
throws InvalidKeyException {
341
DHParameterSpec paramSpec = publicKey.getParams();
342
343
BigInteger p = paramSpec.getP();
344
BigInteger g = paramSpec.getG();
345
BigInteger y = publicKey.getY();
346
347
validateDHPublicKey(p, g, y);
348
}
349
350
private static void validateDHPublicKey(DHPublicKeySpec publicKeySpec)
351
throws InvalidKeyException {
352
validateDHPublicKey(publicKeySpec.getP(),
353
publicKeySpec.getG(), publicKeySpec.getY());
354
}
355
356
private static void validateDHPublicKey(BigInteger p,
357
BigInteger g, BigInteger y) throws InvalidKeyException {
358
359
// For better interoperability, the interval is limited to [2, p-2].
360
BigInteger leftOpen = BigInteger.ONE;
361
BigInteger rightOpen = p.subtract(BigInteger.ONE);
362
if (y.compareTo(leftOpen) <= 0) {
363
throw new InvalidKeyException(
364
"Diffie-Hellman public key is too small");
365
}
366
if (y.compareTo(rightOpen) >= 0) {
367
throw new InvalidKeyException(
368
"Diffie-Hellman public key is too large");
369
}
370
371
// y^q mod p == 1?
372
// Unable to perform this check as q is unknown in this circumstance.
373
374
// p is expected to be prime. However, it is too expensive to check
375
// that p is prime. Instead, in order to mitigate the impact of
376
// non-prime values, we check that y is not a factor of p.
377
BigInteger r = p.remainder(y);
378
if (r.equals(BigInteger.ZERO)) {
379
throw new InvalidKeyException("Invalid Diffie-Hellman parameters");
380
}
381
}
382
383
/**
384
* Trim leading (most significant) zeroes from the result.
385
*
386
* @throws NullPointerException if {@code b} is null
387
*/
388
public static byte[] trimZeroes(byte[] b) {
389
int i = 0;
390
while ((i < b.length - 1) && (b[i] == 0)) {
391
i++;
392
}
393
if (i == 0) {
394
return b;
395
}
396
byte[] t = new byte[b.length - i];
397
System.arraycopy(b, i, t, 0, t.length);
398
return t;
399
}
400
401
}
402
403
404