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/jgss/krb5/CipherHelper.java
41161 views
1
/*
2
* Copyright (c) 2004, 2017, 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.jgss.krb5;
27
28
import javax.crypto.Cipher;
29
import javax.crypto.SecretKey;
30
import javax.crypto.spec.IvParameterSpec;
31
import javax.crypto.spec.SecretKeySpec;
32
import javax.crypto.CipherInputStream;
33
import javax.crypto.CipherOutputStream;
34
import java.io.InputStream;
35
import java.io.OutputStream;
36
import java.io.IOException;
37
import org.ietf.jgss.*;
38
39
import java.security.MessageDigest;
40
import java.security.GeneralSecurityException;
41
import java.security.NoSuchAlgorithmException;
42
import sun.security.krb5.*;
43
import sun.security.krb5.internal.crypto.Aes128Sha2;
44
import sun.security.krb5.internal.crypto.Aes256Sha2;
45
import sun.security.krb5.internal.crypto.Des3;
46
import sun.security.krb5.internal.crypto.Aes128;
47
import sun.security.krb5.internal.crypto.Aes256;
48
import sun.security.krb5.internal.crypto.ArcFourHmac;
49
import sun.security.krb5.internal.crypto.EType;
50
51
class CipherHelper {
52
53
// From draft-raeburn-cat-gssapi-krb5-3des-00
54
// Key usage values when deriving keys
55
private static final int KG_USAGE_SEAL = 22;
56
private static final int KG_USAGE_SIGN = 23;
57
private static final int KG_USAGE_SEQ = 24;
58
59
private static final int DES_CHECKSUM_SIZE = 8;
60
private static final int DES_IV_SIZE = 8;
61
private static final int AES_IV_SIZE = 16;
62
63
// ARCFOUR-HMAC
64
// Save first 8 octets of HMAC Sgn_Cksum
65
private static final int HMAC_CHECKSUM_SIZE = 8;
66
// key usage for MIC tokens used by MS
67
private static final int KG_USAGE_SIGN_MS = 15;
68
69
// debug flag
70
private static final boolean DEBUG = Krb5Util.DEBUG;
71
72
/**
73
* A zero initial vector to be used for checksum calculation and for
74
* DesCbc application data encryption/decryption.
75
*/
76
private static final byte[] ZERO_IV = new byte[DES_IV_SIZE];
77
private static final byte[] ZERO_IV_AES = new byte[AES_IV_SIZE];
78
79
private int etype;
80
private int sgnAlg, sealAlg;
81
private byte[] keybytes;
82
83
CipherHelper(EncryptionKey key) throws GSSException {
84
etype = key.getEType();
85
keybytes = key.getBytes();
86
87
switch (etype) {
88
case EncryptedData.ETYPE_DES_CBC_CRC:
89
case EncryptedData.ETYPE_DES_CBC_MD5:
90
sgnAlg = MessageToken.SGN_ALG_DES_MAC_MD5;
91
sealAlg = MessageToken.SEAL_ALG_DES;
92
break;
93
94
case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:
95
sgnAlg = MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD;
96
sealAlg = MessageToken.SEAL_ALG_DES3_KD;
97
break;
98
99
case EncryptedData.ETYPE_ARCFOUR_HMAC:
100
sgnAlg = MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR;
101
sealAlg = MessageToken.SEAL_ALG_ARCFOUR_HMAC;
102
break;
103
104
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
105
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
106
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
107
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
108
sgnAlg = -1;
109
sealAlg = -1;
110
break;
111
112
default:
113
throw new GSSException(GSSException.FAILURE, -1,
114
"Unsupported encryption type: " + etype);
115
}
116
}
117
118
int getSgnAlg() {
119
return sgnAlg;
120
}
121
122
int getSealAlg() {
123
return sealAlg;
124
}
125
126
// new token format from draft-ietf-krb-wg-gssapi-cfx-07
127
// proto is used to determine new GSS token format for "newer" etypes
128
int getProto() {
129
return EType.isNewer(etype) ? 1 : 0;
130
}
131
132
int getEType() {
133
return etype;
134
}
135
136
boolean isArcFour() {
137
boolean flag = false;
138
if (etype == EncryptedData.ETYPE_ARCFOUR_HMAC) {
139
flag = true;
140
}
141
return flag;
142
}
143
144
@SuppressWarnings("fallthrough")
145
byte[] calculateChecksum(int alg, byte[] header, byte[] trailer,
146
byte[] data, int start, int len, int tokenId) throws GSSException {
147
148
switch (alg) {
149
case MessageToken.SGN_ALG_DES_MAC_MD5:
150
/*
151
* With this sign algorithm, first an MD5 hash is computed on the
152
* application data. The 16 byte hash is then DesCbc encrypted.
153
*/
154
try {
155
MessageDigest md5 = MessageDigest.getInstance("MD5");
156
157
// debug("\t\tdata=[");
158
159
// debug(getHexBytes(checksumDataHeader,
160
// checksumDataHeader.length) + " ");
161
md5.update(header);
162
163
// debug(getHexBytes(data, start, len));
164
md5.update(data, start, len);
165
166
if (trailer != null) {
167
// debug(" " +
168
// getHexBytes(trailer,
169
// optionalTrailer.length));
170
md5.update(trailer);
171
}
172
// debug("]\n");
173
174
data = md5.digest();
175
start = 0;
176
len = data.length;
177
// System.out.println("\tMD5 Checksum is [" +
178
// getHexBytes(data) + "]\n");
179
header = null;
180
trailer = null;
181
} catch (NoSuchAlgorithmException e) {
182
GSSException ge = new GSSException(GSSException.FAILURE, -1,
183
"Could not get MD5 Message Digest - " + e.getMessage());
184
ge.initCause(e);
185
throw ge;
186
}
187
// fall through to encrypt checksum
188
189
case MessageToken.SGN_ALG_DES_MAC:
190
return getDesCbcChecksum(keybytes, header, data, start, len);
191
192
case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:
193
byte[] buf;
194
int offset, total;
195
if (header == null && trailer == null) {
196
buf = data;
197
total = len;
198
offset = start;
199
} else {
200
total = ((header != null ? header.length : 0) + len +
201
(trailer != null ? trailer.length : 0));
202
203
buf = new byte[total];
204
int pos = 0;
205
if (header != null) {
206
System.arraycopy(header, 0, buf, 0, header.length);
207
pos = header.length;
208
}
209
System.arraycopy(data, start, buf, pos, len);
210
pos += len;
211
if (trailer != null) {
212
System.arraycopy(trailer, 0, buf, pos, trailer.length);
213
}
214
215
offset = 0;
216
}
217
218
try {
219
220
/*
221
Krb5Token.debug("\nkeybytes: " +
222
Krb5Token.getHexBytes(keybytes));
223
Krb5Token.debug("\nheader: " + (header == null ? "NONE" :
224
Krb5Token.getHexBytes(header)));
225
Krb5Token.debug("\ntrailer: " + (trailer == null ? "NONE" :
226
Krb5Token.getHexBytes(trailer)));
227
Krb5Token.debug("\ndata: " +
228
Krb5Token.getHexBytes(data, start, len));
229
Krb5Token.debug("\nbuf: " + Krb5Token.getHexBytes(buf, offset,
230
total));
231
*/
232
233
byte[] answer = Des3.calculateChecksum(keybytes,
234
KG_USAGE_SIGN, buf, offset, total);
235
// Krb5Token.debug("\nanswer: " +
236
// Krb5Token.getHexBytes(answer));
237
return answer;
238
} catch (GeneralSecurityException e) {
239
GSSException ge = new GSSException(GSSException.FAILURE, -1,
240
"Could not use HMAC-SHA1-DES3-KD signing algorithm - " +
241
e.getMessage());
242
ge.initCause(e);
243
throw ge;
244
}
245
246
case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:
247
byte[] buffer;
248
int off, tot;
249
if (header == null && trailer == null) {
250
buffer = data;
251
tot = len;
252
off = start;
253
} else {
254
tot = ((header != null ? header.length : 0) + len +
255
(trailer != null ? trailer.length : 0));
256
257
buffer = new byte[tot];
258
int pos = 0;
259
260
if (header != null) {
261
System.arraycopy(header, 0, buffer, 0, header.length);
262
pos = header.length;
263
}
264
System.arraycopy(data, start, buffer, pos, len);
265
pos += len;
266
if (trailer != null) {
267
System.arraycopy(trailer, 0, buffer, pos, trailer.length);
268
}
269
270
off = 0;
271
}
272
273
try {
274
275
/*
276
Krb5Token.debug("\nkeybytes: " +
277
Krb5Token.getHexBytes(keybytes));
278
Krb5Token.debug("\nheader: " + (header == null ? "NONE" :
279
Krb5Token.getHexBytes(header)));
280
Krb5Token.debug("\ntrailer: " + (trailer == null ? "NONE" :
281
Krb5Token.getHexBytes(trailer)));
282
Krb5Token.debug("\ndata: " +
283
Krb5Token.getHexBytes(data, start, len));
284
Krb5Token.debug("\nbuffer: " +
285
Krb5Token.getHexBytes(buffer, off, tot));
286
*/
287
288
// for MIC tokens, key derivation salt is 15
289
// NOTE: Required for interoperability. The RC4-HMAC spec
290
// defines key_usage of 23, however all Kerberos impl.
291
// MS/Solaris/MIT all use key_usage of 15 for MIC tokens
292
int key_usage = KG_USAGE_SIGN;
293
if (tokenId == Krb5Token.MIC_ID) {
294
key_usage = KG_USAGE_SIGN_MS;
295
}
296
byte[] answer = ArcFourHmac.calculateChecksum(keybytes,
297
key_usage, buffer, off, tot);
298
// Krb5Token.debug("\nanswer: " +
299
// Krb5Token.getHexBytes(answer));
300
301
// Save first 8 octets of HMAC Sgn_Cksum
302
byte[] output = new byte[getChecksumLength()];
303
System.arraycopy(answer, 0, output, 0, output.length);
304
// Krb5Token.debug("\nanswer (trimmed): " +
305
// Krb5Token.getHexBytes(output));
306
return output;
307
} catch (GeneralSecurityException e) {
308
GSSException ge = new GSSException(GSSException.FAILURE, -1,
309
"Could not use HMAC_MD5_ARCFOUR signing algorithm - " +
310
e.getMessage());
311
ge.initCause(e);
312
throw ge;
313
}
314
315
default:
316
throw new GSSException(GSSException.FAILURE, -1,
317
"Unsupported signing algorithm: " + sgnAlg);
318
}
319
}
320
321
// calculate Checksum for the new GSS tokens
322
byte[] calculateChecksum(byte[] header, byte[] data, int start, int len,
323
int key_usage) throws GSSException {
324
325
// total length
326
int total = ((header != null ? header.length : 0) + len);
327
328
// get_mic("plaintext-data" | "header")
329
byte[] buf = new byte[total];
330
331
// data
332
System.arraycopy(data, start, buf, 0, len);
333
334
// token header
335
if (header != null) {
336
System.arraycopy(header, 0, buf, len, header.length);
337
}
338
339
// Krb5Token.debug("\nAES calculate checksum on: " +
340
// Krb5Token.getHexBytes(buf));
341
switch (etype) {
342
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
343
try {
344
byte[] answer = Aes128.calculateChecksum(keybytes, key_usage,
345
buf, 0, total);
346
// Krb5Token.debug("\nAES128 checksum: " +
347
// Krb5Token.getHexBytes(answer));
348
return answer;
349
} catch (GeneralSecurityException e) {
350
GSSException ge = new GSSException(GSSException.FAILURE, -1,
351
"Could not use AES128 signing algorithm - " +
352
e.getMessage());
353
ge.initCause(e);
354
throw ge;
355
}
356
357
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
358
try {
359
byte[] answer = Aes256.calculateChecksum(keybytes, key_usage,
360
buf, 0, total);
361
// Krb5Token.debug("\nAES256 checksum: " +
362
// Krb5Token.getHexBytes(answer));
363
return answer;
364
} catch (GeneralSecurityException e) {
365
GSSException ge = new GSSException(GSSException.FAILURE, -1,
366
"Could not use AES256 signing algorithm - " +
367
e.getMessage());
368
ge.initCause(e);
369
throw ge;
370
}
371
372
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
373
try {
374
byte[] answer = Aes128Sha2.calculateChecksum(keybytes, key_usage,
375
buf, 0, total);
376
return answer;
377
} catch (GeneralSecurityException e) {
378
GSSException ge = new GSSException(GSSException.FAILURE, -1,
379
"Could not use AES128 signing algorithm - " +
380
e.getMessage());
381
ge.initCause(e);
382
throw ge;
383
}
384
385
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
386
try {
387
byte[] answer = Aes256Sha2.calculateChecksum(keybytes, key_usage,
388
buf, 0, total);
389
return answer;
390
} catch (GeneralSecurityException e) {
391
GSSException ge = new GSSException(GSSException.FAILURE, -1,
392
"Could not use AES256 signing algorithm - " +
393
e.getMessage());
394
ge.initCause(e);
395
throw ge;
396
}
397
398
399
default:
400
throw new GSSException(GSSException.FAILURE, -1,
401
"Unsupported encryption type: " + etype);
402
}
403
}
404
405
byte[] encryptSeq(byte[] ivec, byte[] plaintext, int start, int len)
406
throws GSSException {
407
408
switch (sgnAlg) {
409
case MessageToken.SGN_ALG_DES_MAC_MD5:
410
case MessageToken.SGN_ALG_DES_MAC:
411
try {
412
Cipher des = getInitializedDes(true, keybytes, ivec);
413
return des.doFinal(plaintext, start, len);
414
415
} catch (GeneralSecurityException e) {
416
GSSException ge = new GSSException(GSSException.FAILURE, -1,
417
"Could not encrypt sequence number using DES - " +
418
e.getMessage());
419
ge.initCause(e);
420
throw ge;
421
}
422
423
case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:
424
byte[] iv;
425
if (ivec.length == DES_IV_SIZE) {
426
iv = ivec;
427
} else {
428
iv = new byte[DES_IV_SIZE];
429
System.arraycopy(ivec, 0, iv, 0, DES_IV_SIZE);
430
}
431
try {
432
return Des3.encryptRaw(keybytes, KG_USAGE_SEQ, iv,
433
plaintext, start, len);
434
} catch (Exception e) {
435
// GeneralSecurityException, KrbCryptoException
436
GSSException ge = new GSSException(GSSException.FAILURE, -1,
437
"Could not encrypt sequence number using DES3-KD - " +
438
e.getMessage());
439
ge.initCause(e);
440
throw ge;
441
}
442
443
case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:
444
// ivec passed is the checksum
445
byte[] checksum;
446
if (ivec.length == HMAC_CHECKSUM_SIZE) {
447
checksum = ivec;
448
} else {
449
checksum = new byte[HMAC_CHECKSUM_SIZE];
450
System.arraycopy(ivec, 0, checksum, 0, HMAC_CHECKSUM_SIZE);
451
}
452
453
try {
454
return ArcFourHmac.encryptSeq(keybytes, KG_USAGE_SEQ, checksum,
455
plaintext, start, len);
456
} catch (Exception e) {
457
// GeneralSecurityException, KrbCryptoException
458
GSSException ge = new GSSException(GSSException.FAILURE, -1,
459
"Could not encrypt sequence number using RC4-HMAC - " +
460
e.getMessage());
461
ge.initCause(e);
462
throw ge;
463
}
464
465
default:
466
throw new GSSException(GSSException.FAILURE, -1,
467
"Unsupported signing algorithm: " + sgnAlg);
468
}
469
}
470
471
byte[] decryptSeq(byte[] ivec, byte[] ciphertext, int start, int len)
472
throws GSSException {
473
474
switch (sgnAlg) {
475
case MessageToken.SGN_ALG_DES_MAC_MD5:
476
case MessageToken.SGN_ALG_DES_MAC:
477
try {
478
Cipher des = getInitializedDes(false, keybytes, ivec);
479
return des.doFinal(ciphertext, start, len);
480
} catch (GeneralSecurityException e) {
481
GSSException ge = new GSSException(GSSException.FAILURE, -1,
482
"Could not decrypt sequence number using DES - " +
483
e.getMessage());
484
ge.initCause(e);
485
throw ge;
486
}
487
488
case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:
489
byte[] iv;
490
if (ivec.length == DES_IV_SIZE) {
491
iv = ivec;
492
} else {
493
iv = new byte[8];
494
System.arraycopy(ivec, 0, iv, 0, DES_IV_SIZE);
495
}
496
497
try {
498
return Des3.decryptRaw(keybytes, KG_USAGE_SEQ, iv,
499
ciphertext, start, len);
500
} catch (Exception e) {
501
// GeneralSecurityException, KrbCryptoException
502
GSSException ge = new GSSException(GSSException.FAILURE, -1,
503
"Could not decrypt sequence number using DES3-KD - " +
504
e.getMessage());
505
ge.initCause(e);
506
throw ge;
507
}
508
509
case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:
510
// ivec passed is the checksum
511
byte[] checksum;
512
if (ivec.length == HMAC_CHECKSUM_SIZE) {
513
checksum = ivec;
514
} else {
515
checksum = new byte[HMAC_CHECKSUM_SIZE];
516
System.arraycopy(ivec, 0, checksum, 0, HMAC_CHECKSUM_SIZE);
517
}
518
519
try {
520
return ArcFourHmac.decryptSeq(keybytes, KG_USAGE_SEQ, checksum,
521
ciphertext, start, len);
522
} catch (Exception e) {
523
// GeneralSecurityException, KrbCryptoException
524
GSSException ge = new GSSException(GSSException.FAILURE, -1,
525
"Could not decrypt sequence number using RC4-HMAC - " +
526
e.getMessage());
527
ge.initCause(e);
528
throw ge;
529
}
530
531
default:
532
throw new GSSException(GSSException.FAILURE, -1,
533
"Unsupported signing algorithm: " + sgnAlg);
534
}
535
}
536
537
int getChecksumLength() throws GSSException {
538
switch (etype) {
539
case EncryptedData.ETYPE_DES_CBC_CRC:
540
case EncryptedData.ETYPE_DES_CBC_MD5:
541
return DES_CHECKSUM_SIZE;
542
543
case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:
544
return Des3.getChecksumLength();
545
546
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
547
return Aes128.getChecksumLength();
548
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
549
return Aes256.getChecksumLength();
550
551
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
552
return Aes128Sha2.getChecksumLength();
553
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
554
return Aes256Sha2.getChecksumLength();
555
556
case EncryptedData.ETYPE_ARCFOUR_HMAC:
557
// only first 8 octets of HMAC Sgn_Cksum are used
558
return HMAC_CHECKSUM_SIZE;
559
560
default:
561
throw new GSSException(GSSException.FAILURE, -1,
562
"Unsupported encryption type: " + etype);
563
}
564
}
565
566
void decryptData(WrapToken token, byte[] ciphertext, int cStart, int cLen,
567
byte[] plaintext, int pStart) throws GSSException {
568
569
/*
570
Krb5Token.debug("decryptData : ciphertext = " +
571
Krb5Token.getHexBytes(ciphertext));
572
*/
573
574
switch (sealAlg) {
575
case MessageToken.SEAL_ALG_DES:
576
desCbcDecrypt(token, getDesEncryptionKey(keybytes),
577
ciphertext, cStart, cLen, plaintext, pStart);
578
break;
579
580
case MessageToken.SEAL_ALG_DES3_KD:
581
des3KdDecrypt(token, ciphertext, cStart, cLen, plaintext, pStart);
582
break;
583
584
case MessageToken.SEAL_ALG_ARCFOUR_HMAC:
585
arcFourDecrypt(token, ciphertext, cStart, cLen, plaintext, pStart);
586
break;
587
588
default:
589
throw new GSSException(GSSException.FAILURE, -1,
590
"Unsupported seal algorithm: " + sealAlg);
591
}
592
}
593
594
// decrypt data in the new GSS tokens
595
void decryptData(WrapToken_v2 token, byte[] ciphertext, int cStart,
596
int cLen, byte[] plaintext, int pStart, int key_usage)
597
throws GSSException {
598
599
/*
600
Krb5Token.debug("decryptData : ciphertext = " +
601
Krb5Token.getHexBytes(ciphertext));
602
*/
603
604
switch (etype) {
605
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
606
aes128Decrypt(token, ciphertext, cStart, cLen,
607
plaintext, pStart, key_usage);
608
break;
609
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
610
aes256Decrypt(token, ciphertext, cStart, cLen,
611
plaintext, pStart, key_usage);
612
break;
613
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
614
aes128Sha2Decrypt(token, ciphertext, cStart, cLen,
615
plaintext, pStart, key_usage);
616
break;
617
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
618
aes256Sha2Decrypt(token, ciphertext, cStart, cLen,
619
plaintext, pStart, key_usage);
620
break;
621
default:
622
throw new GSSException(GSSException.FAILURE, -1,
623
"Unsupported etype: " + etype);
624
}
625
}
626
627
void decryptData(WrapToken token, InputStream cipherStream, int cLen,
628
byte[] plaintext, int pStart)
629
throws GSSException, IOException {
630
631
switch (sealAlg) {
632
case MessageToken.SEAL_ALG_DES:
633
desCbcDecrypt(token, getDesEncryptionKey(keybytes),
634
cipherStream, cLen, plaintext, pStart);
635
break;
636
637
case MessageToken.SEAL_ALG_DES3_KD:
638
639
// Read encrypted data from stream
640
byte[] ciphertext = new byte[cLen];
641
try {
642
Krb5Token.readFully(cipherStream, ciphertext, 0, cLen);
643
} catch (IOException e) {
644
GSSException ge = new GSSException(
645
GSSException.DEFECTIVE_TOKEN, -1,
646
"Cannot read complete token");
647
ge.initCause(e);
648
throw ge;
649
}
650
651
des3KdDecrypt(token, ciphertext, 0, cLen, plaintext, pStart);
652
break;
653
654
case MessageToken.SEAL_ALG_ARCFOUR_HMAC:
655
656
// Read encrypted data from stream
657
byte[] ctext = new byte[cLen];
658
try {
659
Krb5Token.readFully(cipherStream, ctext, 0, cLen);
660
} catch (IOException e) {
661
GSSException ge = new GSSException(
662
GSSException.DEFECTIVE_TOKEN, -1,
663
"Cannot read complete token");
664
ge.initCause(e);
665
throw ge;
666
}
667
668
arcFourDecrypt(token, ctext, 0, cLen, plaintext, pStart);
669
break;
670
671
default:
672
throw new GSSException(GSSException.FAILURE, -1,
673
"Unsupported seal algorithm: " + sealAlg);
674
}
675
}
676
677
void decryptData(WrapToken_v2 token, InputStream cipherStream, int cLen,
678
byte[] plaintext, int pStart, int key_usage)
679
throws GSSException, IOException {
680
681
// Read encrypted data from stream
682
byte[] ciphertext = new byte[cLen];
683
try {
684
Krb5Token.readFully(cipherStream, ciphertext, 0, cLen);
685
} catch (IOException e) {
686
GSSException ge = new GSSException(
687
GSSException.DEFECTIVE_TOKEN, -1,
688
"Cannot read complete token");
689
ge.initCause(e);
690
throw ge;
691
}
692
switch (etype) {
693
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
694
aes128Decrypt(token, ciphertext, 0, cLen,
695
plaintext, pStart, key_usage);
696
break;
697
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
698
aes256Decrypt(token, ciphertext, 0, cLen,
699
plaintext, pStart, key_usage);
700
break;
701
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
702
aes128Sha2Decrypt(token, ciphertext, 0, cLen,
703
plaintext, pStart, key_usage);
704
break;
705
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
706
aes256Sha2Decrypt(token, ciphertext, 0, cLen,
707
plaintext, pStart, key_usage);
708
break;
709
default:
710
throw new GSSException(GSSException.FAILURE, -1,
711
"Unsupported etype: " + etype);
712
}
713
}
714
715
void encryptData(WrapToken token, byte[] confounder, byte[] plaintext,
716
int start, int len, byte[] padding, OutputStream os)
717
throws GSSException, IOException {
718
719
switch (sealAlg) {
720
case MessageToken.SEAL_ALG_DES:
721
// Encrypt on the fly and write
722
Cipher des = getInitializedDes(true, getDesEncryptionKey(keybytes),
723
ZERO_IV);
724
CipherOutputStream cos = new CipherOutputStream(os, des);
725
// debug(getHexBytes(confounder, confounder.length));
726
cos.write(confounder);
727
// debug(" " + getHexBytes(plaintext, start, len));
728
cos.write(plaintext, start, len);
729
// debug(" " + getHexBytes(padding, padding.length));
730
cos.write(padding);
731
break;
732
733
case MessageToken.SEAL_ALG_DES3_KD:
734
byte[] ctext = des3KdEncrypt(confounder, plaintext, start, len,
735
padding);
736
737
// Write to stream
738
os.write(ctext);
739
break;
740
741
case MessageToken.SEAL_ALG_ARCFOUR_HMAC:
742
byte[] ciphertext = arcFourEncrypt(token, confounder, plaintext,
743
start, len, padding);
744
745
// Write to stream
746
os.write(ciphertext);
747
break;
748
749
default:
750
throw new GSSException(GSSException.FAILURE, -1,
751
"Unsupported seal algorithm: " + sealAlg);
752
}
753
}
754
755
/*
756
* Encrypt data in the new GSS tokens
757
*
758
* Wrap Tokens (with confidentiality)
759
* { Encrypt(16-byte confounder | plaintext | 16-byte token_header) |
760
* 12-byte HMAC }
761
* where HMAC is on {16-byte confounder | plaintext | 16-byte token_header}
762
* HMAC is not encrypted; it is appended at the end.
763
*/
764
byte[] encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,
765
byte[] plaintext, int start, int len, int key_usage)
766
throws GSSException {
767
768
switch (etype) {
769
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
770
return aes128Encrypt(confounder, tokenHeader,
771
plaintext, start, len, key_usage);
772
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
773
return aes256Encrypt(confounder, tokenHeader,
774
plaintext, start, len, key_usage);
775
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
776
return aes128Sha2Encrypt(confounder, tokenHeader,
777
plaintext, start, len, key_usage);
778
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
779
return aes256Sha2Encrypt(confounder, tokenHeader,
780
plaintext, start, len, key_usage);
781
default:
782
throw new GSSException(GSSException.FAILURE, -1,
783
"Unsupported etype: " + etype);
784
}
785
}
786
787
void encryptData(WrapToken token, byte[] confounder, byte[] plaintext,
788
int pStart, int pLen, byte[] padding, byte[] ciphertext, int cStart)
789
throws GSSException {
790
791
switch (sealAlg) {
792
case MessageToken.SEAL_ALG_DES:
793
int pos = cStart;
794
// Encrypt and write
795
Cipher des = getInitializedDes(true, getDesEncryptionKey(keybytes),
796
ZERO_IV);
797
try {
798
// debug(getHexBytes(confounder, confounder.length));
799
pos += des.update(confounder, 0, confounder.length,
800
ciphertext, pos);
801
// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
802
pos += des.update(plaintext, pStart, pLen,
803
ciphertext, pos);
804
// debug(" " + getHexBytes(padding, padding.length));
805
des.update(padding, 0, padding.length,
806
ciphertext, pos);
807
des.doFinal();
808
} catch (GeneralSecurityException e) {
809
GSSException ge = new GSSException(GSSException.FAILURE, -1,
810
"Could not use DES Cipher - " + e.getMessage());
811
ge.initCause(e);
812
throw ge;
813
}
814
break;
815
816
case MessageToken.SEAL_ALG_DES3_KD:
817
byte[] ctext = des3KdEncrypt(confounder, plaintext, pStart, pLen,
818
padding);
819
System.arraycopy(ctext, 0, ciphertext, cStart, ctext.length);
820
break;
821
822
case MessageToken.SEAL_ALG_ARCFOUR_HMAC:
823
byte[] ctext2 = arcFourEncrypt(token, confounder, plaintext, pStart,
824
pLen, padding);
825
System.arraycopy(ctext2, 0, ciphertext, cStart, ctext2.length);
826
break;
827
828
default:
829
throw new GSSException(GSSException.FAILURE, -1,
830
"Unsupported seal algorithm: " + sealAlg);
831
}
832
}
833
834
/*
835
* Encrypt data in the new GSS tokens
836
*
837
* Wrap Tokens (with confidentiality)
838
* { Encrypt(16-byte confounder | plaintext | 16-byte token_header) |
839
* 12-byte HMAC }
840
* where HMAC is on {16-byte confounder | plaintext | 16-byte token_header}
841
* HMAC is not encrypted; it is appended at the end.
842
*/
843
int encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,
844
byte[] plaintext, int pStart, int pLen, byte[] ciphertext, int cStart,
845
int key_usage) throws GSSException {
846
847
byte[] ctext = null;
848
switch (etype) {
849
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
850
ctext = aes128Encrypt(confounder, tokenHeader,
851
plaintext, pStart, pLen, key_usage);
852
break;
853
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
854
ctext = aes256Encrypt(confounder, tokenHeader,
855
plaintext, pStart, pLen, key_usage);
856
break;
857
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
858
ctext = aes128Sha2Encrypt(confounder, tokenHeader,
859
plaintext, pStart, pLen, key_usage);
860
break;
861
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
862
ctext = aes256Sha2Encrypt(confounder, tokenHeader,
863
plaintext, pStart, pLen, key_usage);
864
break;
865
default:
866
throw new GSSException(GSSException.FAILURE, -1,
867
"Unsupported etype: " + etype);
868
}
869
System.arraycopy(ctext, 0, ciphertext, cStart, ctext.length);
870
return ctext.length;
871
}
872
873
// --------------------- DES methods
874
875
/**
876
* Computes the DesCbc checksum based on the algorithm published in FIPS
877
* Publication 113. This involves applying padding to the data passed
878
* in, then performing DesCbc encryption on the data with a zero initial
879
* vector, and finally returning the last 8 bytes of the encryption
880
* result.
881
*
882
* @param key the bytes for the DES key
883
* @param header a header to process first before the data is.
884
* @param data the data to checksum
885
* @param offset the offset where the data begins
886
* @param len the length of the data
887
* @throws GSSException when an error occuse in the encryption
888
*/
889
private byte[] getDesCbcChecksum(byte key[],
890
byte[] header,
891
byte[] data, int offset, int len)
892
throws GSSException {
893
894
Cipher des = getInitializedDes(true, key, ZERO_IV);
895
896
int blockSize = des.getBlockSize();
897
898
/*
899
* Here the data need not be a multiple of the blocksize
900
* (8). Encrypt and throw away results for all blocks except for
901
* the very last block.
902
*/
903
904
byte[] finalBlock = new byte[blockSize];
905
906
int numBlocks = len / blockSize;
907
int lastBytes = len % blockSize;
908
if (lastBytes == 0) {
909
// No need for padding. Save last block from application data
910
numBlocks -= 1;
911
System.arraycopy(data, offset + numBlocks*blockSize,
912
finalBlock, 0, blockSize);
913
} else {
914
System.arraycopy(data, offset + numBlocks*blockSize,
915
finalBlock, 0, lastBytes);
916
// Zero padding automatically done
917
}
918
919
try {
920
byte[] temp = new byte[Math.max(blockSize,
921
(header == null? blockSize : header.length))];
922
923
if (header != null) {
924
// header will be null when doing DES-MD5 Checksum
925
des.update(header, 0, header.length, temp, 0);
926
}
927
928
// Iterate over all but the last block
929
for (int i = 0; i < numBlocks; i++) {
930
des.update(data, offset, blockSize,
931
temp, 0);
932
offset += blockSize;
933
}
934
935
// Now process the final block
936
byte[] retVal = new byte[blockSize];
937
des.update(finalBlock, 0, blockSize, retVal, 0);
938
des.doFinal();
939
940
return retVal;
941
} catch (GeneralSecurityException e) {
942
GSSException ge = new GSSException(GSSException.FAILURE, -1,
943
"Could not use DES Cipher - " + e.getMessage());
944
ge.initCause(e);
945
throw ge;
946
}
947
}
948
949
/**
950
* Obtains an initialized DES cipher.
951
*
952
* @param encryptMode true if encryption is desired, false is decryption
953
* is desired.
954
* @param key the bytes for the DES key
955
* @param ivBytes the initial vector bytes
956
*/
957
private final Cipher getInitializedDes(boolean encryptMode, byte[] key,
958
byte[] ivBytes)
959
throws GSSException {
960
961
962
try {
963
IvParameterSpec iv = new IvParameterSpec(ivBytes);
964
SecretKey jceKey = (SecretKey) (new SecretKeySpec(key, "DES"));
965
966
Cipher desCipher = Cipher.getInstance("DES/CBC/NoPadding");
967
desCipher.init(
968
(encryptMode ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE),
969
jceKey, iv);
970
return desCipher;
971
} catch (GeneralSecurityException e) {
972
GSSException ge = new GSSException(GSSException.FAILURE, -1,
973
e.getMessage());
974
ge.initCause(e);
975
throw ge;
976
}
977
}
978
979
/**
980
* Helper routine to decrypt fromm a byte array and write the
981
* application data straight to an output array with minimal
982
* buffer copies. The confounder and the padding are stored
983
* separately and not copied into this output array.
984
* @param key the DES key to use
985
* @param cipherText the encrypted data
986
* @param offset the offset for the encrypted data
987
* @param len the length of the encrypted data
988
* @param dataOutBuf the output buffer where the application data
989
* should be writte
990
* @param dataOffset the offser where the application data should
991
* be written.
992
* @throws GSSException is an error occurs while decrypting the
993
* data
994
*/
995
private void desCbcDecrypt(WrapToken token, byte[] key, byte[] cipherText,
996
int offset, int len, byte[] dataOutBuf, int dataOffset)
997
throws GSSException {
998
999
try {
1000
1001
int temp = 0;
1002
1003
Cipher des = getInitializedDes(false, key, ZERO_IV);
1004
1005
/*
1006
* Remove the counfounder first.
1007
* CONFOUNDER_SIZE is one DES block ie 8 bytes.
1008
*/
1009
temp = des.update(cipherText, offset, WrapToken.CONFOUNDER_SIZE,
1010
token.confounder);
1011
// temp should be CONFOUNDER_SIZE
1012
// debug("\n\ttemp is " + temp + " and CONFOUNDER_SIZE is "
1013
// + CONFOUNDER_SIZE);
1014
1015
offset += WrapToken.CONFOUNDER_SIZE;
1016
len -= WrapToken.CONFOUNDER_SIZE;
1017
1018
/*
1019
* len is a multiple of 8 due to padding.
1020
* Decrypt all blocks directly into the output buffer except for
1021
* the very last block. Remove the trailing padding bytes from the
1022
* very last block and copy that into the output buffer.
1023
*/
1024
1025
int blockSize = des.getBlockSize();
1026
int numBlocks = len / blockSize - 1;
1027
1028
// Iterate over all but the last block
1029
for (int i = 0; i < numBlocks; i++) {
1030
temp = des.update(cipherText, offset, blockSize,
1031
dataOutBuf, dataOffset);
1032
// temp should be blockSize
1033
// debug("\n\ttemp is " + temp + " and blockSize is "
1034
// + blockSize);
1035
1036
offset += blockSize;
1037
dataOffset += blockSize;
1038
}
1039
1040
// Now process the last block
1041
byte[] finalBlock = new byte[blockSize];
1042
des.update(cipherText, offset, blockSize, finalBlock);
1043
1044
des.doFinal();
1045
1046
/*
1047
* There is always at least one padding byte. The padding bytes
1048
* are all the value of the number of padding bytes.
1049
*/
1050
1051
int padSize = finalBlock[blockSize - 1];
1052
if (padSize < 1 || padSize > 8)
1053
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
1054
"Invalid padding on Wrap Token");
1055
token.padding = WrapToken.pads[padSize];
1056
blockSize -= padSize;
1057
1058
// Copy this last block into the output buffer
1059
System.arraycopy(finalBlock, 0, dataOutBuf, dataOffset,
1060
blockSize);
1061
1062
} catch (GeneralSecurityException e) {
1063
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1064
"Could not use DES cipher - " + e.getMessage());
1065
ge.initCause(e);
1066
throw ge;
1067
}
1068
}
1069
1070
/**
1071
* Helper routine to decrypt from an InputStream and write the
1072
* application data straight to an output array with minimal
1073
* buffer copies. The confounder and the padding are stored
1074
* separately and not copied into this output array.
1075
* @param key the DES key to use
1076
* @param is the InputStream from which the cipher text should be
1077
* read
1078
* @param len the length of the ciphertext data
1079
* @param dataOutBuf the output buffer where the application data
1080
* should be writte
1081
* @param dataOffset the offser where the application data should
1082
* be written.
1083
* @throws GSSException is an error occurs while decrypting the
1084
* data
1085
*/
1086
private void desCbcDecrypt(WrapToken token, byte[] key,
1087
InputStream is, int len, byte[] dataOutBuf, int dataOffset)
1088
throws GSSException, IOException {
1089
1090
int temp = 0;
1091
1092
Cipher des = getInitializedDes(false, key, ZERO_IV);
1093
1094
WrapTokenInputStream truncatedInputStream =
1095
new WrapTokenInputStream(is, len);
1096
CipherInputStream cis = new CipherInputStream(truncatedInputStream,
1097
des);
1098
/*
1099
* Remove the counfounder first.
1100
* CONFOUNDER_SIZE is one DES block ie 8 bytes.
1101
*/
1102
temp = cis.read(token.confounder);
1103
1104
len -= temp;
1105
// temp should be CONFOUNDER_SIZE
1106
// debug("Got " + temp + " bytes; CONFOUNDER_SIZE is "
1107
// + CONFOUNDER_SIZE + "\n");
1108
// debug("Confounder is " + getHexBytes(confounder) + "\n");
1109
1110
1111
/*
1112
* len is a multiple of 8 due to padding.
1113
* Decrypt all blocks directly into the output buffer except for
1114
* the very last block. Remove the trailing padding bytes from the
1115
* very last block and copy that into the output buffer.
1116
*/
1117
1118
int blockSize = des.getBlockSize();
1119
int numBlocks = len / blockSize - 1;
1120
1121
// Iterate over all but the last block
1122
for (int i = 0; i < numBlocks; i++) {
1123
// debug("dataOffset is " + dataOffset + "\n");
1124
temp = cis.read(dataOutBuf, dataOffset, blockSize);
1125
1126
// temp should be blockSize
1127
// debug("Got " + temp + " bytes and blockSize is "
1128
// + blockSize + "\n");
1129
// debug("Bytes are: "
1130
// + getHexBytes(dataOutBuf, dataOffset, temp) + "\n");
1131
dataOffset += blockSize;
1132
}
1133
1134
// Now process the last block
1135
byte[] finalBlock = new byte[blockSize];
1136
// debug("Will call read on finalBlock" + "\n");
1137
temp = cis.read(finalBlock);
1138
// temp should be blockSize
1139
/*
1140
debug("Got " + temp + " bytes and blockSize is "
1141
+ blockSize + "\n");
1142
debug("Bytes are: "
1143
+ getHexBytes(finalBlock, 0, temp) + "\n");
1144
debug("Will call doFinal" + "\n");
1145
*/
1146
try {
1147
des.doFinal();
1148
} catch (GeneralSecurityException e) {
1149
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1150
"Could not use DES cipher - " + e.getMessage());
1151
ge.initCause(e);
1152
throw ge;
1153
}
1154
1155
/*
1156
* There is always at least one padding byte. The padding bytes
1157
* are all the value of the number of padding bytes.
1158
*/
1159
1160
int padSize = finalBlock[blockSize - 1];
1161
if (padSize < 1 || padSize > 8)
1162
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
1163
"Invalid padding on Wrap Token");
1164
token.padding = WrapToken.pads[padSize];
1165
blockSize -= padSize;
1166
1167
// Copy this last block into the output buffer
1168
System.arraycopy(finalBlock, 0, dataOutBuf, dataOffset,
1169
blockSize);
1170
}
1171
1172
private static byte[] getDesEncryptionKey(byte[] key)
1173
throws GSSException {
1174
1175
/*
1176
* To meet export control requirements, double check that the
1177
* key being used is no longer than 64 bits.
1178
*
1179
* Note that from a protocol point of view, an
1180
* algorithm that is not DES will be rejected before this
1181
* point. Also, a DES key that is not 64 bits will be
1182
* rejected by a good JCE provider.
1183
*/
1184
if (key.length > 8)
1185
throw new GSSException(GSSException.FAILURE, -100,
1186
"Invalid DES Key!");
1187
1188
byte[] retVal = new byte[key.length];
1189
for (int i = 0; i < key.length; i++)
1190
retVal[i] = (byte)(key[i] ^ 0xf0); // RFC 1964, Section 1.2.2
1191
return retVal;
1192
}
1193
1194
// ---- DES3-KD methods
1195
private void des3KdDecrypt(WrapToken token, byte[] ciphertext,
1196
int cStart, int cLen, byte[] plaintext, int pStart)
1197
throws GSSException {
1198
byte[] ptext;
1199
try {
1200
ptext = Des3.decryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,
1201
ciphertext, cStart, cLen);
1202
} catch (GeneralSecurityException e) {
1203
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1204
"Could not use DES3-KD Cipher - " + e.getMessage());
1205
ge.initCause(e);
1206
throw ge;
1207
}
1208
1209
/*
1210
Krb5Token.debug("\ndes3KdDecrypt in: " +
1211
Krb5Token.getHexBytes(ciphertext, cStart, cLen));
1212
Krb5Token.debug("\ndes3KdDecrypt plain: " +
1213
Krb5Token.getHexBytes(ptext));
1214
*/
1215
1216
// Strip out confounder and padding
1217
/*
1218
* There is always at least one padding byte. The padding bytes
1219
* are all the value of the number of padding bytes.
1220
*/
1221
int padSize = ptext[ptext.length - 1];
1222
if (padSize < 1 || padSize > 8)
1223
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
1224
"Invalid padding on Wrap Token");
1225
1226
token.padding = WrapToken.pads[padSize];
1227
int len = ptext.length - WrapToken.CONFOUNDER_SIZE - padSize;
1228
1229
System.arraycopy(ptext, WrapToken.CONFOUNDER_SIZE,
1230
plaintext, pStart, len);
1231
1232
// Needed to calculate checksum
1233
System.arraycopy(ptext, 0, token.confounder,
1234
0, WrapToken.CONFOUNDER_SIZE);
1235
}
1236
1237
private byte[] des3KdEncrypt(byte[] confounder, byte[] plaintext,
1238
int start, int len, byte[] padding) throws GSSException {
1239
1240
1241
// [confounder | plaintext | padding]
1242
byte[] all = new byte[confounder.length + len + padding.length];
1243
System.arraycopy(confounder, 0, all, 0, confounder.length);
1244
System.arraycopy(plaintext, start, all, confounder.length, len);
1245
System.arraycopy(padding, 0, all, confounder.length + len,
1246
padding.length);
1247
1248
// Krb5Token.debug("\ndes3KdEncrypt:" + Krb5Token.getHexBytes(all));
1249
1250
// Encrypt
1251
try {
1252
byte[] answer = Des3.encryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,
1253
all, 0, all.length);
1254
// Krb5Token.debug("\ndes3KdEncrypt encrypted:" +
1255
// Krb5Token.getHexBytes(answer));
1256
return answer;
1257
} catch (Exception e) {
1258
// GeneralSecurityException, KrbCryptoException
1259
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1260
"Could not use DES3-KD Cipher - " + e.getMessage());
1261
ge.initCause(e);
1262
throw ge;
1263
}
1264
}
1265
1266
// ---- RC4-HMAC methods
1267
private void arcFourDecrypt(WrapToken token, byte[] ciphertext,
1268
int cStart, int cLen, byte[] plaintext, int pStart)
1269
throws GSSException {
1270
1271
// obtain Sequence number needed for decryption
1272
// first decrypt the Sequence Number using checksum
1273
byte[] seqNum = decryptSeq(token.getChecksum(),
1274
token.getEncSeqNumber(), 0, 8);
1275
1276
byte[] ptext;
1277
try {
1278
ptext = ArcFourHmac.decryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,
1279
ciphertext, cStart, cLen, seqNum);
1280
} catch (GeneralSecurityException e) {
1281
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1282
"Could not use ArcFour Cipher - " + e.getMessage());
1283
ge.initCause(e);
1284
throw ge;
1285
}
1286
1287
/*
1288
Krb5Token.debug("\narcFourDecrypt in: " +
1289
Krb5Token.getHexBytes(ciphertext, cStart, cLen));
1290
Krb5Token.debug("\narcFourDecrypt plain: " +
1291
Krb5Token.getHexBytes(ptext));
1292
*/
1293
1294
// Strip out confounder and padding
1295
/*
1296
* There is always at least one padding byte. The padding bytes
1297
* are all the value of the number of padding bytes.
1298
*/
1299
int padSize = ptext[ptext.length - 1];
1300
if (padSize < 1)
1301
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
1302
"Invalid padding on Wrap Token");
1303
1304
token.padding = WrapToken.pads[padSize];
1305
int len = ptext.length - WrapToken.CONFOUNDER_SIZE - padSize;
1306
1307
System.arraycopy(ptext, WrapToken.CONFOUNDER_SIZE,
1308
plaintext, pStart, len);
1309
1310
// Krb5Token.debug("\narcFourDecrypt plaintext: " +
1311
// Krb5Token.getHexBytes(plaintext));
1312
1313
// Needed to calculate checksum
1314
System.arraycopy(ptext, 0, token.confounder,
1315
0, WrapToken.CONFOUNDER_SIZE);
1316
}
1317
1318
private byte[] arcFourEncrypt(WrapToken token, byte[] confounder,
1319
byte[] plaintext, int start, int len, byte[] padding)
1320
throws GSSException {
1321
1322
// [confounder | plaintext | padding]
1323
byte[] all = new byte[confounder.length + len + padding.length];
1324
System.arraycopy(confounder, 0, all, 0, confounder.length);
1325
System.arraycopy(plaintext, start, all, confounder.length, len);
1326
System.arraycopy(padding, 0, all, confounder.length + len,
1327
padding.length);
1328
1329
// get the token Sequence Number required for encryption
1330
// Note: When using this RC4 based encryption type, the sequence number
1331
// is always sent in big-endian rather than little-endian order.
1332
byte[] seqNum = new byte[4];
1333
WrapToken.writeBigEndian(token.getSequenceNumber(), seqNum);
1334
1335
// Krb5Token.debug("\narcFourEncrypt:" + Krb5Token.getHexBytes(all));
1336
1337
// Encrypt
1338
try {
1339
byte[] answer = ArcFourHmac.encryptRaw(keybytes, KG_USAGE_SEAL,
1340
seqNum, all, 0, all.length);
1341
// Krb5Token.debug("\narcFourEncrypt encrypted:" +
1342
// Krb5Token.getHexBytes(answer));
1343
return answer;
1344
} catch (Exception e) {
1345
// GeneralSecurityException, KrbCryptoException
1346
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1347
"Could not use ArcFour Cipher - " + e.getMessage());
1348
ge.initCause(e);
1349
throw ge;
1350
}
1351
}
1352
1353
// ---- AES methods
1354
private byte[] aes128Encrypt(byte[] confounder, byte[] tokenHeader,
1355
byte[] plaintext, int start, int len, int key_usage)
1356
throws GSSException {
1357
1358
// encrypt { AES-plaintext-data | filler | header }
1359
// AES-plaintext-data { confounder | plaintext }
1360
// WrapToken = { tokenHeader |
1361
// Encrypt (confounder | plaintext | tokenHeader ) | HMAC }
1362
1363
byte[] all = new byte[confounder.length + len + tokenHeader.length];
1364
System.arraycopy(confounder, 0, all, 0, confounder.length);
1365
System.arraycopy(plaintext, start, all, confounder.length, len);
1366
System.arraycopy(tokenHeader, 0, all, confounder.length+len,
1367
tokenHeader.length);
1368
1369
// Krb5Token.debug("\naes128Encrypt:" + Krb5Token.getHexBytes(all));
1370
try {
1371
byte[] answer = Aes128.encryptRaw(keybytes, key_usage,
1372
ZERO_IV_AES,
1373
all, 0, all.length);
1374
// Krb5Token.debug("\naes128Encrypt encrypted:" +
1375
// Krb5Token.getHexBytes(answer));
1376
return answer;
1377
} catch (Exception e) {
1378
// GeneralSecurityException, KrbCryptoException
1379
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1380
"Could not use AES128 Cipher - " + e.getMessage());
1381
ge.initCause(e);
1382
throw ge;
1383
}
1384
}
1385
1386
private byte[] aes128Sha2Encrypt(byte[] confounder, byte[] tokenHeader,
1387
byte[] plaintext, int start, int len, int key_usage)
1388
throws GSSException {
1389
1390
// encrypt { AES-plaintext-data | filler | header }
1391
// AES-plaintext-data { confounder | plaintext }
1392
// WrapToken = { tokenHeader |
1393
// Encrypt (confounder | plaintext | tokenHeader ) | HMAC }
1394
1395
byte[] all = new byte[confounder.length + len + tokenHeader.length];
1396
System.arraycopy(confounder, 0, all, 0, confounder.length);
1397
System.arraycopy(plaintext, start, all, confounder.length, len);
1398
System.arraycopy(tokenHeader, 0, all, confounder.length+len,
1399
tokenHeader.length);
1400
1401
// Krb5Token.debug("\naes128Sha2Encrypt:" + Krb5Token.getHexBytes(all));
1402
try {
1403
byte[] answer = Aes128Sha2.encryptRaw(keybytes, key_usage,
1404
ZERO_IV_AES,
1405
all, 0, all.length);
1406
// Krb5Token.debug("\naes128Sha2Encrypt encrypted:" +
1407
// Krb5Token.getHexBytes(answer));
1408
return answer;
1409
} catch (Exception e) {
1410
// GeneralSecurityException, KrbCryptoException
1411
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1412
"Could not use Aes128Sha2 Cipher - " + e.getMessage());
1413
ge.initCause(e);
1414
throw ge;
1415
}
1416
}
1417
1418
private void aes128Decrypt(WrapToken_v2 token, byte[] ciphertext,
1419
int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)
1420
throws GSSException {
1421
1422
byte[] ptext = null;
1423
1424
try {
1425
ptext = Aes128.decryptRaw(keybytes, key_usage,
1426
ZERO_IV_AES, ciphertext, cStart, cLen);
1427
} catch (GeneralSecurityException e) {
1428
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1429
"Could not use AES128 Cipher - " + e.getMessage());
1430
ge.initCause(e);
1431
throw ge;
1432
}
1433
1434
/*
1435
Krb5Token.debug("\naes128Decrypt in: " +
1436
Krb5Token.getHexBytes(ciphertext, cStart, cLen));
1437
Krb5Token.debug("\naes128Decrypt plain: " +
1438
Krb5Token.getHexBytes(ptext));
1439
Krb5Token.debug("\naes128Decrypt ptext: " +
1440
Krb5Token.getHexBytes(ptext));
1441
*/
1442
1443
// Strip out confounder and token header
1444
int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -
1445
WrapToken_v2.TOKEN_HEADER_SIZE;
1446
System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,
1447
plaintext, pStart, len);
1448
1449
/*
1450
Krb5Token.debug("\naes128Decrypt plaintext: " +
1451
Krb5Token.getHexBytes(plaintext, pStart, len));
1452
*/
1453
}
1454
1455
private void aes128Sha2Decrypt(WrapToken_v2 token, byte[] ciphertext,
1456
int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)
1457
throws GSSException {
1458
1459
byte[] ptext = null;
1460
1461
try {
1462
ptext = Aes128Sha2.decryptRaw(keybytes, key_usage,
1463
ZERO_IV_AES, ciphertext, cStart, cLen);
1464
} catch (GeneralSecurityException e) {
1465
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1466
"Could not use AES128Sha2 Cipher - " + e.getMessage());
1467
ge.initCause(e);
1468
throw ge;
1469
}
1470
1471
/*
1472
Krb5Token.debug("\naes128Sha2Decrypt in: " +
1473
Krb5Token.getHexBytes(ciphertext, cStart, cLen));
1474
Krb5Token.debug("\naes128Sha2Decrypt plain: " +
1475
Krb5Token.getHexBytes(ptext));
1476
Krb5Token.debug("\naes128Sha2Decrypt ptext: " +
1477
Krb5Token.getHexBytes(ptext));
1478
*/
1479
1480
// Strip out confounder and token header
1481
int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -
1482
WrapToken_v2.TOKEN_HEADER_SIZE;
1483
System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,
1484
plaintext, pStart, len);
1485
1486
/*
1487
Krb5Token.debug("\naes128Sha2Decrypt plaintext: " +
1488
Krb5Token.getHexBytes(plaintext, pStart, len));
1489
*/
1490
}
1491
1492
private byte[] aes256Encrypt(byte[] confounder, byte[] tokenHeader,
1493
byte[] plaintext, int start, int len, int key_usage)
1494
throws GSSException {
1495
1496
// encrypt { AES-plaintext-data | filler | header }
1497
// AES-plaintext-data { confounder | plaintext }
1498
// WrapToken = { tokenHeader |
1499
// Encrypt (confounder | plaintext | tokenHeader ) | HMAC }
1500
1501
byte[] all = new byte[confounder.length + len + tokenHeader.length];
1502
System.arraycopy(confounder, 0, all, 0, confounder.length);
1503
System.arraycopy(plaintext, start, all, confounder.length, len);
1504
System.arraycopy(tokenHeader, 0, all, confounder.length+len,
1505
tokenHeader.length);
1506
1507
// Krb5Token.debug("\naes256Encrypt:" + Krb5Token.getHexBytes(all));
1508
1509
try {
1510
byte[] answer = Aes256.encryptRaw(keybytes, key_usage,
1511
ZERO_IV_AES, all, 0, all.length);
1512
// Krb5Token.debug("\naes256Encrypt encrypted:" +
1513
// Krb5Token.getHexBytes(answer));
1514
return answer;
1515
} catch (Exception e) {
1516
// GeneralSecurityException, KrbCryptoException
1517
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1518
"Could not use AES256 Cipher - " + e.getMessage());
1519
ge.initCause(e);
1520
throw ge;
1521
}
1522
}
1523
1524
private byte[] aes256Sha2Encrypt(byte[] confounder, byte[] tokenHeader,
1525
byte[] plaintext, int start, int len, int key_usage)
1526
throws GSSException {
1527
1528
// encrypt { AES-plaintext-data | filler | header }
1529
// AES-plaintext-data { confounder | plaintext }
1530
// WrapToken = { tokenHeader |
1531
// Encrypt (confounder | plaintext | tokenHeader ) | HMAC }
1532
1533
byte[] all = new byte[confounder.length + len + tokenHeader.length];
1534
System.arraycopy(confounder, 0, all, 0, confounder.length);
1535
System.arraycopy(plaintext, start, all, confounder.length, len);
1536
System.arraycopy(tokenHeader, 0, all, confounder.length+len,
1537
tokenHeader.length);
1538
1539
// Krb5Token.debug("\naes256Sha2Encrypt:" + Krb5Token.getHexBytes(all));
1540
1541
try {
1542
byte[] answer = Aes256Sha2.encryptRaw(keybytes, key_usage,
1543
ZERO_IV_AES, all, 0, all.length);
1544
// Krb5Token.debug("\naes256Sha2Encrypt encrypted:" +
1545
// Krb5Token.getHexBytes(answer));
1546
return answer;
1547
} catch (Exception e) {
1548
// GeneralSecurityException, KrbCryptoException
1549
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1550
"Could not use Aes256Sha2 Cipher - " + e.getMessage());
1551
ge.initCause(e);
1552
throw ge;
1553
}
1554
}
1555
1556
private void aes256Decrypt(WrapToken_v2 token, byte[] ciphertext,
1557
int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)
1558
throws GSSException {
1559
1560
byte[] ptext;
1561
try {
1562
ptext = Aes256.decryptRaw(keybytes, key_usage,
1563
ZERO_IV_AES, ciphertext, cStart, cLen);
1564
} catch (GeneralSecurityException e) {
1565
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1566
"Could not use AES128 Cipher - " + e.getMessage());
1567
ge.initCause(e);
1568
throw ge;
1569
}
1570
1571
/*
1572
Krb5Token.debug("\naes256Decrypt in: " +
1573
Krb5Token.getHexBytes(ciphertext, cStart, cLen));
1574
Krb5Token.debug("\naes256Decrypt plain: " +
1575
Krb5Token.getHexBytes(ptext));
1576
Krb5Token.debug("\naes256Decrypt ptext: " +
1577
Krb5Token.getHexBytes(ptext));
1578
*/
1579
1580
// Strip out confounder and token header
1581
int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -
1582
WrapToken_v2.TOKEN_HEADER_SIZE;
1583
System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,
1584
plaintext, pStart, len);
1585
1586
/*
1587
Krb5Token.debug("\naes128Decrypt plaintext: " +
1588
Krb5Token.getHexBytes(plaintext, pStart, len));
1589
*/
1590
1591
}
1592
1593
private void aes256Sha2Decrypt(WrapToken_v2 token, byte[] ciphertext,
1594
int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)
1595
throws GSSException {
1596
1597
byte[] ptext;
1598
try {
1599
ptext = Aes256Sha2.decryptRaw(keybytes, key_usage,
1600
ZERO_IV_AES, ciphertext, cStart, cLen);
1601
} catch (GeneralSecurityException e) {
1602
GSSException ge = new GSSException(GSSException.FAILURE, -1,
1603
"Could not use AES256Sha2 Cipher - " + e.getMessage());
1604
ge.initCause(e);
1605
throw ge;
1606
}
1607
1608
/*
1609
Krb5Token.debug("\naes256Sha2Decrypt in: " +
1610
Krb5Token.getHexBytes(ciphertext, cStart, cLen));
1611
Krb5Token.debug("\naes256Sha2Decrypt plain: " +
1612
Krb5Token.getHexBytes(ptext));
1613
Krb5Token.debug("\naes256Sha2Decrypt ptext: " +
1614
Krb5Token.getHexBytes(ptext));
1615
*/
1616
1617
// Strip out confounder and token header
1618
int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -
1619
WrapToken_v2.TOKEN_HEADER_SIZE;
1620
System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,
1621
plaintext, pStart, len);
1622
1623
/*
1624
Krb5Token.debug("\naes256Sha2Decrypt plaintext: " +
1625
Krb5Token.getHexBytes(plaintext, pStart, len));
1626
*/
1627
1628
}
1629
1630
/**
1631
* This class provides a truncated inputstream needed by WrapToken. The
1632
* truncated inputstream is passed to CipherInputStream. It prevents
1633
* the CipherInputStream from treating the bytes of the following token
1634
* as part fo the ciphertext for this token.
1635
*/
1636
class WrapTokenInputStream extends InputStream {
1637
1638
private InputStream is;
1639
private int length;
1640
private int remaining;
1641
1642
private int temp;
1643
1644
public WrapTokenInputStream(InputStream is, int length) {
1645
this.is = is;
1646
this.length = length;
1647
remaining = length;
1648
}
1649
1650
public final int read() throws IOException {
1651
if (remaining == 0)
1652
return -1;
1653
else {
1654
temp = is.read();
1655
if (temp != -1)
1656
remaining -= temp;
1657
return temp;
1658
}
1659
}
1660
1661
public final int read(byte[] b) throws IOException {
1662
if (remaining == 0)
1663
return -1;
1664
else {
1665
temp = Math.min(remaining, b.length);
1666
temp = is.read(b, 0, temp);
1667
if (temp != -1)
1668
remaining -= temp;
1669
return temp;
1670
}
1671
}
1672
1673
public final int read(byte[] b,
1674
int off,
1675
int len) throws IOException {
1676
if (remaining == 0)
1677
return -1;
1678
else {
1679
temp = Math.min(remaining, len);
1680
temp = is.read(b, off, temp);
1681
if (temp != -1)
1682
remaining -= temp;
1683
return temp;
1684
}
1685
}
1686
1687
public final long skip(long n) throws IOException {
1688
if (remaining == 0)
1689
return 0;
1690
else {
1691
temp = (int) Math.min(remaining, n);
1692
temp = (int) is.skip(temp);
1693
remaining -= temp;
1694
return temp;
1695
}
1696
}
1697
1698
public final int available() throws IOException {
1699
return Math.min(remaining, is.available());
1700
}
1701
1702
public final void close() throws IOException {
1703
remaining = 0;
1704
}
1705
}
1706
}
1707
1708