Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java
41159 views
1
/*
2
* Copyright (c) 2000, 2019, 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
/*
27
*
28
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
29
* Copyright 1997 The Open Group Research Institute. All rights reserved.
30
*/
31
32
package sun.security.krb5;
33
34
import sun.security.util.*;
35
import sun.security.krb5.internal.*;
36
import sun.security.krb5.internal.crypto.*;
37
import java.io.IOException;
38
import java.security.GeneralSecurityException;
39
import java.util.Arrays;
40
import sun.security.krb5.internal.ktab.KeyTab;
41
import sun.security.krb5.internal.ccache.CCacheOutputStream;
42
import javax.crypto.spec.DESKeySpec;
43
import javax.crypto.spec.DESedeKeySpec;
44
45
/**
46
* This class encapsulates the concept of an EncryptionKey. An encryption
47
* key is defined in RFC 4120 as:
48
*
49
* EncryptionKey ::= SEQUENCE {
50
* keytype [0] Int32 -- actually encryption type --,
51
* keyvalue [1] OCTET STRING
52
* }
53
*
54
* keytype
55
* This field specifies the encryption type of the encryption key
56
* that follows in the keyvalue field. Although its name is
57
* "keytype", it actually specifies an encryption type. Previously,
58
* multiple cryptosystems that performed encryption differently but
59
* were capable of using keys with the same characteristics were
60
* permitted to share an assigned number to designate the type of
61
* key; this usage is now deprecated.
62
*
63
* keyvalue
64
* This field contains the key itself, encoded as an octet string.
65
*/
66
67
public class EncryptionKey
68
implements Cloneable {
69
70
public static final EncryptionKey NULL_KEY =
71
new EncryptionKey(new byte[] {}, EncryptedData.ETYPE_NULL, null);
72
73
private int keyType;
74
private byte[] keyValue;
75
private Integer kvno; // not part of ASN1 encoding;
76
77
private static final boolean DEBUG = Krb5.DEBUG;
78
79
public synchronized int getEType() {
80
return keyType;
81
}
82
83
public final Integer getKeyVersionNumber() {
84
return kvno;
85
}
86
87
/**
88
* Returns the raw key bytes, not in any ASN.1 encoding.
89
*/
90
public final byte[] getBytes() {
91
// This method cannot be called outside sun.security, hence no
92
// cloning. getEncoded() calls this method.
93
return keyValue;
94
}
95
96
public synchronized Object clone() {
97
return new EncryptionKey(keyValue, keyType, kvno);
98
}
99
100
/**
101
* Obtains all versions of the secret key of the principal from a
102
* keytab.
103
*
104
* @param princ the principal whose secret key is desired
105
* @param keytab the path to the keytab file. A value of null
106
* will be accepted to indicate that the default path should be
107
* searched.
108
* @return an array of secret keys or null if none were found.
109
*/
110
public static EncryptionKey[] acquireSecretKeys(PrincipalName princ,
111
String keytab) {
112
113
if (princ == null)
114
throw new IllegalArgumentException(
115
"Cannot have null pricipal name to look in keytab.");
116
117
// KeyTab getInstance(keytab) will call KeyTab.getInstance()
118
// if keytab is null
119
KeyTab ktab = KeyTab.getInstance(keytab);
120
return ktab.readServiceKeys(princ);
121
}
122
123
/**
124
* Obtains a key for a given etype of a principal with possible new salt
125
* and s2kparams
126
* @param cname NOT null
127
* @param password NOT null
128
* @param etype
129
* @param snp can be NULL
130
* @return never null
131
*/
132
public static EncryptionKey acquireSecretKey(PrincipalName cname,
133
char[] password, int etype, PAData.SaltAndParams snp)
134
throws KrbException {
135
String salt;
136
byte[] s2kparams;
137
if (snp != null) {
138
salt = snp.salt != null ? snp.salt : cname.getSalt();
139
s2kparams = snp.params;
140
} else {
141
salt = cname.getSalt();
142
s2kparams = null;
143
}
144
return acquireSecretKey(password, salt, etype, s2kparams);
145
}
146
147
/**
148
* Obtains a key for a given etype with salt and optional s2kparams
149
* @param password NOT null
150
* @param salt NOT null
151
* @param etype
152
* @param s2kparams can be NULL
153
* @return never null
154
*/
155
public static EncryptionKey acquireSecretKey(char[] password,
156
String salt, int etype, byte[] s2kparams)
157
throws KrbException {
158
159
return new EncryptionKey(
160
stringToKey(password, salt, s2kparams, etype),
161
etype, null);
162
}
163
164
/**
165
* Generate a list of keys using the given principal and password.
166
* Construct a key for each configured etype.
167
* Caller is responsible for clearing password.
168
*/
169
/*
170
* Usually, when keyType is decoded from ASN.1 it will contain a
171
* value indicating what the algorithm to be used is. However, when
172
* converting from a password to a key for the AS-EXCHANGE, this
173
* keyType will not be available. Use builtin list of default etypes
174
* as the default in that case. If default_tkt_enctypes was set in
175
* the libdefaults of krb5.conf, then use that sequence.
176
*/
177
public static EncryptionKey[] acquireSecretKeys(char[] password,
178
String salt) throws KrbException {
179
180
int[] etypes = EType.getDefaults("default_tkt_enctypes");
181
182
EncryptionKey[] encKeys = new EncryptionKey[etypes.length];
183
for (int i = 0; i < etypes.length; i++) {
184
if (EType.isSupported(etypes[i])) {
185
encKeys[i] = new EncryptionKey(
186
stringToKey(password, salt, null, etypes[i]),
187
etypes[i], null);
188
} else {
189
if (DEBUG) {
190
System.out.println("Encryption Type " +
191
EType.toString(etypes[i]) +
192
" is not supported/enabled");
193
}
194
}
195
}
196
return encKeys;
197
}
198
199
// Used in Krb5AcceptCredential, self
200
public EncryptionKey(byte[] keyValue,
201
int keyType,
202
Integer kvno) {
203
204
if (keyValue != null) {
205
this.keyValue = new byte[keyValue.length];
206
System.arraycopy(keyValue, 0, this.keyValue, 0, keyValue.length);
207
} else {
208
throw new IllegalArgumentException("EncryptionKey: " +
209
"Key bytes cannot be null!");
210
}
211
this.keyType = keyType;
212
this.kvno = kvno;
213
}
214
215
/**
216
* Constructs an EncryptionKey by using the specified key type and key
217
* value. It is used to recover the key when retrieving data from
218
* credential cache file.
219
*
220
*/
221
// Used in Credentials, and javax.security.auth.kerberos.KeyImpl
222
// Warning: called by NativeCreds.c and nativeccache.c
223
public EncryptionKey(int keyType,
224
byte[] keyValue) {
225
this(keyValue, keyType, null);
226
}
227
228
private static byte[] stringToKey(char[] password, String salt,
229
byte[] s2kparams, int keyType) throws KrbCryptoException {
230
231
char[] slt = salt.toCharArray();
232
char[] pwsalt = new char[password.length + slt.length];
233
System.arraycopy(password, 0, pwsalt, 0, password.length);
234
System.arraycopy(slt, 0, pwsalt, password.length, slt.length);
235
Arrays.fill(slt, '0');
236
237
try {
238
switch (keyType) {
239
case EncryptedData.ETYPE_DES_CBC_CRC:
240
case EncryptedData.ETYPE_DES_CBC_MD5:
241
return Des.string_to_key_bytes(pwsalt);
242
243
case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:
244
return Des3.stringToKey(pwsalt);
245
246
case EncryptedData.ETYPE_ARCFOUR_HMAC:
247
return ArcFourHmac.stringToKey(password);
248
249
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
250
return Aes128.stringToKey(password, salt, s2kparams);
251
252
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
253
return Aes256.stringToKey(password, salt, s2kparams);
254
255
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
256
return Aes128Sha2.stringToKey(password, salt, s2kparams);
257
258
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
259
return Aes256Sha2.stringToKey(password, salt, s2kparams);
260
261
default:
262
throw new IllegalArgumentException("encryption type " +
263
EType.toString(keyType) + " not supported");
264
}
265
266
} catch (GeneralSecurityException e) {
267
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
268
ke.initCause(e);
269
throw ke;
270
} finally {
271
Arrays.fill(pwsalt, '0');
272
}
273
}
274
275
// Used in javax.security.auth.kerberos.KeyImpl
276
public EncryptionKey(char[] password,
277
String salt,
278
String algorithm) throws KrbCryptoException {
279
280
if (algorithm == null || algorithm.equalsIgnoreCase("DES")
281
|| algorithm.equalsIgnoreCase("des-cbc-md5")) {
282
keyType = EncryptedData.ETYPE_DES_CBC_MD5;
283
} else if (algorithm.equalsIgnoreCase("des-cbc-crc")) {
284
keyType = EncryptedData.ETYPE_DES_CBC_CRC;
285
} else if (algorithm.equalsIgnoreCase("DESede")
286
|| algorithm.equalsIgnoreCase("des3-cbc-sha1-kd")) {
287
keyType = EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD;
288
} else if (algorithm.equalsIgnoreCase("AES128")
289
|| algorithm.equalsIgnoreCase("aes128-cts-hmac-sha1-96")) {
290
keyType = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96;
291
} else if (algorithm.equalsIgnoreCase("ArcFourHmac")
292
|| algorithm.equalsIgnoreCase("rc4-hmac")) {
293
keyType = EncryptedData.ETYPE_ARCFOUR_HMAC;
294
} else if (algorithm.equalsIgnoreCase("AES256")
295
|| algorithm.equalsIgnoreCase("aes256-cts-hmac-sha1-96")) {
296
keyType = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96;
297
// validate if AES256 is enabled
298
if (!EType.isSupported(keyType)) {
299
throw new IllegalArgumentException("Algorithm " + algorithm +
300
" not enabled");
301
}
302
} else if (algorithm.equalsIgnoreCase("aes128-cts-hmac-sha256-128")) {
303
keyType = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128;
304
} else if (algorithm.equalsIgnoreCase("aes256-cts-hmac-sha384-192")) {
305
keyType = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192;
306
// validate if AES256 is enabled
307
if (!EType.isSupported(keyType)) {
308
throw new IllegalArgumentException("Algorithm " + algorithm +
309
" not enabled");
310
}
311
} else {
312
throw new IllegalArgumentException("Algorithm " + algorithm +
313
" not supported");
314
}
315
316
keyValue = stringToKey(password, salt, null, keyType);
317
kvno = null;
318
}
319
320
/**
321
* Generates a sub-sessionkey from a given session key.
322
*
323
* Used in AcceptSecContextToken and KrbApReq by acceptor- and initiator-
324
* side respectively.
325
*/
326
public EncryptionKey(EncryptionKey key) throws KrbCryptoException {
327
// generate random sub-session key
328
keyValue = Confounder.bytes(key.keyValue.length);
329
for (int i = 0; i < keyValue.length; i++) {
330
keyValue[i] ^= key.keyValue[i];
331
}
332
keyType = key.keyType;
333
334
// check for key parity and weak keys
335
try {
336
// check for DES key
337
if ((keyType == EncryptedData.ETYPE_DES_CBC_MD5) ||
338
(keyType == EncryptedData.ETYPE_DES_CBC_CRC)) {
339
// fix DES key parity
340
if (!DESKeySpec.isParityAdjusted(keyValue, 0)) {
341
keyValue = Des.set_parity(keyValue);
342
}
343
// check for weak key
344
if (DESKeySpec.isWeak(keyValue, 0)) {
345
keyValue[7] = (byte)(keyValue[7] ^ 0xF0);
346
}
347
}
348
// check for 3DES key
349
if (keyType == EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) {
350
// fix 3DES key parity
351
if (!DESedeKeySpec.isParityAdjusted(keyValue, 0)) {
352
keyValue = Des3.parityFix(keyValue);
353
}
354
// check for weak keys
355
byte[] oneKey = new byte[8];
356
for (int i=0; i<keyValue.length; i+=8) {
357
System.arraycopy(keyValue, i, oneKey, 0, 8);
358
if (DESKeySpec.isWeak(oneKey, 0)) {
359
keyValue[i+7] = (byte)(keyValue[i+7] ^ 0xF0);
360
}
361
}
362
}
363
} catch (GeneralSecurityException e) {
364
KrbCryptoException ke = new KrbCryptoException(e.getMessage());
365
ke.initCause(e);
366
throw ke;
367
}
368
}
369
370
/**
371
* Constructs an instance of EncryptionKey type.
372
* @param encoding a single DER-encoded value.
373
* @exception Asn1Exception if an error occurs while decoding an ASN1
374
* encoded data.
375
* @exception IOException if an I/O error occurs while reading encoded
376
* data.
377
*
378
*
379
*/
380
// Used in javax.security.auth.kerberos.KeyImpl
381
public EncryptionKey(DerValue encoding) throws Asn1Exception, IOException {
382
DerValue der;
383
if (encoding.getTag() != DerValue.tag_Sequence) {
384
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
385
}
386
der = encoding.getData().getDerValue();
387
if ((der.getTag() & (byte)0x1F) == (byte)0x00) {
388
keyType = der.getData().getBigInteger().intValue();
389
}
390
else
391
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
392
der = encoding.getData().getDerValue();
393
if ((der.getTag() & (byte)0x1F) == (byte)0x01) {
394
keyValue = der.getData().getOctetString();
395
}
396
else
397
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
398
if (der.getData().available() > 0) {
399
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
400
}
401
}
402
403
/**
404
* Returns the ASN.1 encoding of this EncryptionKey.
405
*
406
* <pre>{@code
407
* EncryptionKey ::= SEQUENCE {
408
* keytype[0] INTEGER,
409
* keyvalue[1] OCTET STRING }
410
* }</pre>
411
*
412
* <p>
413
* This definition reflects the Network Working Group RFC 4120
414
* specification available at
415
* <a href="http://www.ietf.org/rfc/rfc4120.txt">
416
* http://www.ietf.org/rfc/rfc4120.txt</a>.
417
*
418
* @return byte array of encoded EncryptionKey object.
419
* @exception Asn1Exception if an error occurs while decoding an ASN1
420
* encoded data.
421
* @exception IOException if an I/O error occurs while reading encoded
422
* data.
423
*
424
*/
425
public synchronized byte[] asn1Encode() throws Asn1Exception, IOException {
426
DerOutputStream bytes = new DerOutputStream();
427
DerOutputStream temp = new DerOutputStream();
428
temp.putInteger(keyType);
429
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
430
(byte)0x00), temp);
431
temp = new DerOutputStream();
432
temp.putOctetString(keyValue);
433
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
434
(byte)0x01), temp);
435
temp = new DerOutputStream();
436
temp.write(DerValue.tag_Sequence, bytes);
437
return temp.toByteArray();
438
}
439
440
public synchronized void destroy() {
441
if (keyValue != null)
442
for (int i = 0; i < keyValue.length; i++)
443
keyValue[i] = 0;
444
}
445
446
447
/**
448
* Parse (unmarshal) an Encryption key from a DER input stream. This form
449
* parsing might be used when expanding a value which is part of
450
* a constructed sequence and uses explicitly tagged type.
451
*
452
* @param data the Der input stream value, which contains one or more
453
* marshaled value.
454
* @param explicitTag tag number.
455
* @param optional indicate if this data field is optional
456
* @exception Asn1Exception if an error occurs while decoding an ASN1
457
* encoded data.
458
* @exception IOException if an I/O error occurs while reading encoded
459
* data.
460
* @return an instance of EncryptionKey.
461
*
462
*/
463
public static EncryptionKey parse(DerInputStream data, byte
464
explicitTag, boolean optional) throws
465
Asn1Exception, IOException {
466
if ((optional) && (((byte)data.peekByte() & (byte)0x1F) !=
467
explicitTag)) {
468
return null;
469
}
470
DerValue der = data.getDerValue();
471
if (explicitTag != (der.getTag() & (byte)0x1F)) {
472
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
473
} else {
474
DerValue subDer = der.getData().getDerValue();
475
return new EncryptionKey(subDer);
476
}
477
}
478
479
/**
480
* Writes key value in FCC format to a <code>CCacheOutputStream</code>.
481
*
482
* @param cos a <code>CCacheOutputStream</code> to be written to.
483
* @exception IOException if an I/O exception occurs.
484
* @see sun.security.krb5.internal.ccache.CCacheOutputStream
485
*
486
*/
487
public synchronized void writeKey(CCacheOutputStream cos)
488
throws IOException {
489
490
cos.write16(keyType);
491
// we use KRB5_FCC_FVNO_3
492
cos.write16(keyType); // key type is recorded twice.
493
cos.write32(keyValue.length);
494
for (int i = 0; i < keyValue.length; i++) {
495
cos.write8(keyValue[i]);
496
}
497
}
498
499
public String toString() {
500
return new String("EncryptionKey: keyType=" + keyType
501
+ " kvno=" + kvno
502
+ " keyValue (hex dump)="
503
+ (keyValue == null || keyValue.length == 0 ?
504
" Empty Key" : '\n'
505
+ Krb5.hexDumper.encodeBuffer(keyValue)
506
+ '\n'));
507
}
508
509
/**
510
* Find a key with given etype
511
*/
512
public static EncryptionKey findKey(int etype, EncryptionKey[] keys)
513
throws KrbException {
514
return findKey(etype, null, keys);
515
}
516
517
/**
518
* Determines if a kvno matches another kvno. Used in the method
519
* findKey(type, kvno, keys). Always returns true if either input
520
* is null or zero, in case any side does not have kvno info available.
521
*
522
* Note: zero is included because N/A is not a legal value for kvno
523
* in javax.security.auth.kerberos.KerberosKey. Therefore, the info
524
* that the kvno is N/A might be lost when converting between this
525
* class and KerberosKey.
526
*/
527
private static boolean versionMatches(Integer v1, Integer v2) {
528
if (v1 == null || v1 == 0 || v2 == null || v2 == 0) {
529
return true;
530
}
531
return v1.equals(v2);
532
}
533
534
/**
535
* Find a key with given etype and kvno
536
* @param kvno if null, return any (first?) key
537
*/
538
public static EncryptionKey findKey(int etype, Integer kvno, EncryptionKey[] keys)
539
throws KrbException {
540
541
// check if encryption type is supported
542
if (!EType.isSupported(etype)) {
543
throw new KrbException("Encryption type " +
544
EType.toString(etype) + " is not supported/enabled");
545
}
546
547
int ktype;
548
boolean etypeFound = false;
549
550
// When no matched kvno is found, returns tke key of the same
551
// etype with the highest kvno
552
int kvno_found = 0;
553
EncryptionKey key_found = null;
554
555
for (int i = 0; i < keys.length; i++) {
556
ktype = keys[i].getEType();
557
if (EType.isSupported(ktype)) {
558
Integer kv = keys[i].getKeyVersionNumber();
559
if (etype == ktype) {
560
etypeFound = true;
561
if (versionMatches(kvno, kv)) {
562
return keys[i];
563
} else if (kv > kvno_found) {
564
// kv is not null
565
key_found = keys[i];
566
kvno_found = kv;
567
}
568
}
569
}
570
}
571
572
// Key not found.
573
// allow DES key to be used for the DES etypes
574
if ((etype == EncryptedData.ETYPE_DES_CBC_CRC ||
575
etype == EncryptedData.ETYPE_DES_CBC_MD5)) {
576
for (int i = 0; i < keys.length; i++) {
577
ktype = keys[i].getEType();
578
if (ktype == EncryptedData.ETYPE_DES_CBC_CRC ||
579
ktype == EncryptedData.ETYPE_DES_CBC_MD5) {
580
Integer kv = keys[i].getKeyVersionNumber();
581
etypeFound = true;
582
if (versionMatches(kvno, kv)) {
583
return new EncryptionKey(etype, keys[i].getBytes());
584
} else if (kv > kvno_found) {
585
key_found = new EncryptionKey(etype, keys[i].getBytes());
586
kvno_found = kv;
587
}
588
}
589
}
590
}
591
if (etypeFound) {
592
return key_found;
593
// For compatibility, will not fail here.
594
//throw new KrbException(Krb5.KRB_AP_ERR_BADKEYVER);
595
}
596
return null;
597
}
598
}
599
600