1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.client5.http.impl.auth;
28
29 import java.nio.charset.Charset;
30 import java.nio.charset.StandardCharsets;
31 import java.security.Key;
32 import java.security.MessageDigest;
33 import java.security.NoSuchAlgorithmException;
34 import java.security.cert.Certificate;
35 import java.security.cert.CertificateEncodingException;
36 import java.util.Arrays;
37 import java.util.Locale;
38 import java.util.Random;
39
40 import javax.crypto.Cipher;
41 import javax.crypto.spec.SecretKeySpec;
42
43 import org.apache.hc.client5.http.utils.Base64;
44 import org.apache.hc.client5.http.utils.ByteArrayBuilder;
45
46
47
48
49
50
51
52
53
54 @Deprecated
55 final class NTLMEngineImpl implements NTLMEngine {
56
57
58 private static final Charset UNICODE_LITTLE_UNMARKED = Charset.forName("UnicodeLittleUnmarked");
59
60 private static final Charset DEFAULT_CHARSET = StandardCharsets.US_ASCII;
61
62
63
64
65
66
67 static final int FLAG_REQUEST_UNICODE_ENCODING = 0x00000001;
68 static final int FLAG_REQUEST_OEM_ENCODING = 0x00000002;
69 static final int FLAG_REQUEST_TARGET = 0x00000004;
70 static final int FLAG_REQUEST_SIGN = 0x00000010;
71 static final int FLAG_REQUEST_SEAL = 0x00000020;
72 static final int FLAG_REQUEST_LAN_MANAGER_KEY = 0x00000080;
73 static final int FLAG_REQUEST_NTLMv1 = 0x00000200;
74 static final int FLAG_DOMAIN_PRESENT = 0x00001000;
75 static final int FLAG_WORKSTATION_PRESENT = 0x00002000;
76 static final int FLAG_REQUEST_ALWAYS_SIGN = 0x00008000;
77 static final int FLAG_REQUEST_NTLM2_SESSION = 0x00080000;
78 static final int FLAG_REQUEST_VERSION = 0x02000000;
79 static final int FLAG_TARGETINFO_PRESENT = 0x00800000;
80 static final int FLAG_REQUEST_128BIT_KEY_EXCH = 0x20000000;
81 static final int FLAG_REQUEST_EXPLICIT_KEY_EXCH = 0x40000000;
82 static final int FLAG_REQUEST_56BIT_ENCRYPTION = 0x80000000;
83
84
85
86 static final int MSV_AV_EOL = 0x0000;
87 static final int MSV_AV_NB_COMPUTER_NAME = 0x0001;
88 static final int MSV_AV_NB_DOMAIN_NAME = 0x0002;
89 static final int MSV_AV_DNS_COMPUTER_NAME = 0x0003;
90 static final int MSV_AV_DNS_DOMAIN_NAME = 0x0004;
91 static final int MSV_AV_DNS_TREE_NAME = 0x0005;
92 static final int MSV_AV_FLAGS = 0x0006;
93 static final int MSV_AV_TIMESTAMP = 0x0007;
94 static final int MSV_AV_SINGLE_HOST = 0x0008;
95 static final int MSV_AV_TARGET_NAME = 0x0009;
96 static final int MSV_AV_CHANNEL_BINDINGS = 0x000A;
97
98 static final int MSV_AV_FLAGS_ACCOUNT_AUTH_CONSTAINED = 0x00000001;
99 static final int MSV_AV_FLAGS_MIC = 0x00000002;
100 static final int MSV_AV_FLAGS_UNTRUSTED_TARGET_SPN = 0x00000004;
101
102
103 private static final java.security.SecureRandom RND_GEN;
104 static {
105 java.security.SecureRandom rnd = null;
106 try {
107 rnd = java.security.SecureRandom.getInstance("SHA1PRNG");
108 } catch (final Exception ignore) {
109
110 }
111 RND_GEN = rnd;
112 }
113
114
115 private static final byte[] SIGNATURE = getNullTerminatedAsciiString("NTLMSSP");
116
117
118
119 private static final byte[] SIGN_MAGIC_SERVER = getNullTerminatedAsciiString(
120 "session key to server-to-client signing key magic constant");
121 private static final byte[] SIGN_MAGIC_CLIENT = getNullTerminatedAsciiString(
122 "session key to client-to-server signing key magic constant");
123 private static final byte[] SEAL_MAGIC_SERVER = getNullTerminatedAsciiString(
124 "session key to server-to-client sealing key magic constant");
125 private static final byte[] SEAL_MAGIC_CLIENT = getNullTerminatedAsciiString(
126 "session key to client-to-server sealing key magic constant");
127
128
129 private static final byte[] MAGIC_TLS_SERVER_ENDPOINT = "tls-server-end-point:".getBytes(StandardCharsets.US_ASCII);
130
131 private static byte[] getNullTerminatedAsciiString( final String source )
132 {
133 final byte[] bytesWithoutNull = source.getBytes(StandardCharsets.US_ASCII);
134 final byte[] target = new byte[bytesWithoutNull.length + 1];
135 System.arraycopy(bytesWithoutNull, 0, target, 0, bytesWithoutNull.length);
136 target[bytesWithoutNull.length] = (byte) 0x00;
137 return target;
138 }
139
140 private static final String TYPE_1_MESSAGE = new Type1Message().getResponse();
141
142 NTLMEngineImpl() {
143 }
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160 static String getResponseFor(final String message, final String username, final char[] password,
161 final String host, final String domain) throws NTLMEngineException {
162
163 final String response;
164 if (message == null || message.trim().isEmpty()) {
165 response = getType1Message(host, domain);
166 } else {
167 final Type2Message t2m = new Type2Message(message);
168 response = getType3Message(username, password, host, domain, t2m.getChallenge(),
169 t2m.getFlags(), t2m.getTarget(), t2m.getTargetInfo());
170 }
171 return response;
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189 static String getResponseFor(final String message, final String username, final char[] password,
190 final String host, final String domain, final Certificate peerServerCertificate) throws NTLMEngineException {
191
192 final String response;
193 if (message == null || message.trim().isEmpty()) {
194 response = new Type1Message(host, domain).getResponse();
195 } else {
196 final Type1Message t1m = new Type1Message(host, domain);
197 final Type2Message t2m = new Type2Message(message);
198 response = getType3Message(username, password, host, domain, t2m.getChallenge(),
199 t2m.getFlags(), t2m.getTarget(), t2m.getTargetInfo(),
200 peerServerCertificate, t1m.getBytes(), t2m.getBytes());
201 }
202 return response;
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216 static String getType1Message(final String host, final String domain) {
217
218
219 return TYPE_1_MESSAGE;
220 }
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242 static String getType3Message(final String user, final char[] password, final String host, final String domain,
243 final byte[] nonce, final int type2Flags, final String target, final byte[] targetInformation)
244 throws NTLMEngineException {
245 return new Type3Message(domain, host, user, password, nonce, type2Flags, target,
246 targetInformation).getResponse();
247 }
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267 static String getType3Message(final String user, final char[] password, final String host, final String domain,
268 final byte[] nonce, final int type2Flags, final String target, final byte[] targetInformation,
269 final Certificate peerServerCertificate, final byte[] type1Message, final byte[] type2Message)
270 throws NTLMEngineException {
271 return new Type3Message(domain, host, user, password, nonce, type2Flags, target,
272 targetInformation, peerServerCertificate, type1Message, type2Message).getResponse();
273 }
274
275 private static int readULong(final byte[] src, final int index) {
276 if (src.length < index + 4) {
277 return 0;
278 }
279 return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8)
280 | ((src[index + 2] & 0xff) << 16) | ((src[index + 3] & 0xff) << 24);
281 }
282
283 private static int readUShort(final byte[] src, final int index) {
284 if (src.length < index + 2) {
285 return 0;
286 }
287 return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8);
288 }
289
290 private static byte[] readSecurityBuffer(final byte[] src, final int index) {
291 final int length = readUShort(src, index);
292 final int offset = readULong(src, index + 4);
293 if (src.length < offset + length) {
294 return new byte[length];
295 }
296 final byte[] buffer = new byte[length];
297 System.arraycopy(src, offset, buffer, 0, length);
298 return buffer;
299 }
300
301
302 private static byte[] makeRandomChallenge(final Random random) {
303 final byte[] rval = new byte[8];
304 synchronized (random) {
305 random.nextBytes(rval);
306 }
307 return rval;
308 }
309
310
311 private static byte[] makeSecondaryKey(final Random random) {
312 final byte[] rval = new byte[16];
313 synchronized (random) {
314 random.nextBytes(rval);
315 }
316 return rval;
317 }
318
319 static class CipherGen {
320
321 final Random random;
322 final long currentTime;
323
324 final String domain;
325 final String user;
326 final char[] password;
327 final byte[] challenge;
328 final String target;
329 final byte[] targetInformation;
330
331
332 byte[] clientChallenge;
333 byte[] clientChallenge2;
334 byte[] secondaryKey;
335 byte[] timestamp;
336
337
338 byte[] lmHash;
339 byte[] lmResponse;
340 byte[] ntlmHash;
341 byte[] ntlmResponse;
342 byte[] ntlmv2Hash;
343 byte[] lmv2Hash;
344 byte[] lmv2Response;
345 byte[] ntlmv2Blob;
346 byte[] ntlmv2Response;
347 byte[] ntlm2SessionResponse;
348 byte[] lm2SessionResponse;
349 byte[] lmUserSessionKey;
350 byte[] ntlmUserSessionKey;
351 byte[] ntlmv2UserSessionKey;
352 byte[] ntlm2SessionResponseUserSessionKey;
353 byte[] lanManagerSessionKey;
354
355 public CipherGen(final Random random, final long currentTime,
356 final String domain, final String user, final char[] password,
357 final byte[] challenge, final String target, final byte[] targetInformation,
358 final byte[] clientChallenge, final byte[] clientChallenge2,
359 final byte[] secondaryKey, final byte[] timestamp) {
360 this.random = random;
361 this.currentTime = currentTime;
362
363 this.domain = domain;
364 this.target = target;
365 this.user = user;
366 this.password = password;
367 this.challenge = challenge;
368 this.targetInformation = targetInformation;
369 this.clientChallenge = clientChallenge;
370 this.clientChallenge2 = clientChallenge2;
371 this.secondaryKey = secondaryKey;
372 this.timestamp = timestamp;
373 }
374
375 public CipherGen(final Random random, final long currentTime,
376 final String domain,
377 final String user,
378 final char[] password,
379 final byte[] challenge,
380 final String target,
381 final byte[] targetInformation) {
382 this(random, currentTime, domain, user, password, challenge, target, targetInformation, null, null, null, null);
383 }
384
385
386 public byte[] getClientChallenge() {
387 if (clientChallenge == null) {
388 clientChallenge = makeRandomChallenge(random);
389 }
390 return clientChallenge;
391 }
392
393
394 public byte[] getClientChallenge2() {
395 if (clientChallenge2 == null) {
396 clientChallenge2 = makeRandomChallenge(random);
397 }
398 return clientChallenge2;
399 }
400
401
402 public byte[] getSecondaryKey() {
403 if (secondaryKey == null) {
404 secondaryKey = makeSecondaryKey(random);
405 }
406 return secondaryKey;
407 }
408
409
410 public byte[] getLMHash()
411 throws NTLMEngineException {
412 if (lmHash == null) {
413 lmHash = lmHash(password);
414 }
415 return lmHash;
416 }
417
418
419 public byte[] getLMResponse()
420 throws NTLMEngineException {
421 if (lmResponse == null) {
422 lmResponse = lmResponse(getLMHash(),challenge);
423 }
424 return lmResponse;
425 }
426
427
428 public byte[] getNTLMHash()
429 throws NTLMEngineException {
430 if (ntlmHash == null) {
431 ntlmHash = ntlmHash(password);
432 }
433 return ntlmHash;
434 }
435
436
437 public byte[] getNTLMResponse()
438 throws NTLMEngineException {
439 if (ntlmResponse == null) {
440 ntlmResponse = lmResponse(getNTLMHash(),challenge);
441 }
442 return ntlmResponse;
443 }
444
445
446 public byte[] getLMv2Hash()
447 throws NTLMEngineException {
448 if (lmv2Hash == null) {
449 lmv2Hash = lmv2Hash(domain, user, getNTLMHash());
450 }
451 return lmv2Hash;
452 }
453
454
455 public byte[] getNTLMv2Hash()
456 throws NTLMEngineException {
457 if (ntlmv2Hash == null) {
458 ntlmv2Hash = ntlmv2Hash(domain, user, getNTLMHash());
459 }
460 return ntlmv2Hash;
461 }
462
463
464 public byte[] getTimestamp() {
465 if (timestamp == null) {
466 long time = this.currentTime;
467 time += 11644473600000L;
468 time *= 10000;
469
470 timestamp = new byte[8];
471 for (int i = 0; i < 8; i++) {
472 timestamp[i] = (byte) time;
473 time >>>= 8;
474 }
475 }
476 return timestamp;
477 }
478
479
480 public byte[] getNTLMv2Blob() {
481 if (ntlmv2Blob == null) {
482 ntlmv2Blob = createBlob(getClientChallenge2(), targetInformation, getTimestamp());
483 }
484 return ntlmv2Blob;
485 }
486
487
488 public byte[] getNTLMv2Response()
489 throws NTLMEngineException {
490 if (ntlmv2Response == null) {
491 ntlmv2Response = lmv2Response(getNTLMv2Hash(),challenge,getNTLMv2Blob());
492 }
493 return ntlmv2Response;
494 }
495
496
497 public byte[] getLMv2Response()
498 throws NTLMEngineException {
499 if (lmv2Response == null) {
500 lmv2Response = lmv2Response(getLMv2Hash(),challenge,getClientChallenge());
501 }
502 return lmv2Response;
503 }
504
505
506 public byte[] getNTLM2SessionResponse()
507 throws NTLMEngineException {
508 if (ntlm2SessionResponse == null) {
509 ntlm2SessionResponse = ntlm2SessionResponse(getNTLMHash(),challenge,getClientChallenge());
510 }
511 return ntlm2SessionResponse;
512 }
513
514
515 public byte[] getLM2SessionResponse() {
516 if (lm2SessionResponse == null) {
517 final byte[] clntChallenge = getClientChallenge();
518 lm2SessionResponse = new byte[24];
519 System.arraycopy(clntChallenge, 0, lm2SessionResponse, 0, clntChallenge.length);
520 Arrays.fill(lm2SessionResponse, clntChallenge.length, lm2SessionResponse.length, (byte) 0x00);
521 }
522 return lm2SessionResponse;
523 }
524
525
526 public byte[] getLMUserSessionKey()
527 throws NTLMEngineException {
528 if (lmUserSessionKey == null) {
529 lmUserSessionKey = new byte[16];
530 System.arraycopy(getLMHash(), 0, lmUserSessionKey, 0, 8);
531 Arrays.fill(lmUserSessionKey, 8, 16, (byte) 0x00);
532 }
533 return lmUserSessionKey;
534 }
535
536
537 public byte[] getNTLMUserSessionKey()
538 throws NTLMEngineException {
539 if (ntlmUserSessionKey == null) {
540 final MD4 md4 = new MD4();
541 md4.update(getNTLMHash());
542 ntlmUserSessionKey = md4.getOutput();
543 }
544 return ntlmUserSessionKey;
545 }
546
547
548 public byte[] getNTLMv2UserSessionKey()
549 throws NTLMEngineException {
550 if (ntlmv2UserSessionKey == null) {
551 final byte[] ntlmv2hash = getNTLMv2Hash();
552 final byte[] truncatedResponse = new byte[16];
553 System.arraycopy(getNTLMv2Response(), 0, truncatedResponse, 0, 16);
554 ntlmv2UserSessionKey = hmacMD5(truncatedResponse, ntlmv2hash);
555 }
556 return ntlmv2UserSessionKey;
557 }
558
559
560 public byte[] getNTLM2SessionResponseUserSessionKey()
561 throws NTLMEngineException {
562 if (ntlm2SessionResponseUserSessionKey == null) {
563 final byte[] ntlm2SessionResponseNonce = getLM2SessionResponse();
564 final byte[] sessionNonce = new byte[challenge.length + ntlm2SessionResponseNonce.length];
565 System.arraycopy(challenge, 0, sessionNonce, 0, challenge.length);
566 System.arraycopy(ntlm2SessionResponseNonce, 0, sessionNonce, challenge.length, ntlm2SessionResponseNonce.length);
567 ntlm2SessionResponseUserSessionKey = hmacMD5(sessionNonce,getNTLMUserSessionKey());
568 }
569 return ntlm2SessionResponseUserSessionKey;
570 }
571
572
573 public byte[] getLanManagerSessionKey()
574 throws NTLMEngineException {
575 if (lanManagerSessionKey == null) {
576 try {
577 final byte[] keyBytes = new byte[14];
578 System.arraycopy(getLMHash(), 0, keyBytes, 0, 8);
579 Arrays.fill(keyBytes, 8, keyBytes.length, (byte)0xbd);
580 final Key lowKey = createDESKey(keyBytes, 0);
581 final Key highKey = createDESKey(keyBytes, 7);
582 final byte[] truncatedResponse = new byte[8];
583 System.arraycopy(getLMResponse(), 0, truncatedResponse, 0, truncatedResponse.length);
584 Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
585 des.init(Cipher.ENCRYPT_MODE, lowKey);
586 final byte[] lowPart = des.doFinal(truncatedResponse);
587 des = Cipher.getInstance("DES/ECB/NoPadding");
588 des.init(Cipher.ENCRYPT_MODE, highKey);
589 final byte[] highPart = des.doFinal(truncatedResponse);
590 lanManagerSessionKey = new byte[16];
591 System.arraycopy(lowPart, 0, lanManagerSessionKey, 0, lowPart.length);
592 System.arraycopy(highPart, 0, lanManagerSessionKey, lowPart.length, highPart.length);
593 } catch (final Exception e) {
594 throw new NTLMEngineException(e.getMessage(), e);
595 }
596 }
597 return lanManagerSessionKey;
598 }
599 }
600
601
602 static byte[] hmacMD5(final byte[] value, final byte[] key) {
603 final HMACMD5 hmacMD5 = new HMACMD5(key);
604 hmacMD5.update(value);
605 return hmacMD5.getOutput();
606 }
607
608
609 static byte[] RC4(final byte[] value, final byte[] key)
610 throws NTLMEngineException {
611 try {
612 final Cipher rc4 = Cipher.getInstance("RC4");
613 rc4.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "RC4"));
614 return rc4.doFinal(value);
615 } catch (final Exception e) {
616 throw new NTLMEngineException(e.getMessage(), e);
617 }
618 }
619
620
621
622
623
624
625
626
627
628 static byte[] ntlm2SessionResponse(final byte[] ntlmHash, final byte[] challenge,
629 final byte[] clientChallenge) throws NTLMEngineException {
630 try {
631 final MessageDigest md5 = getMD5();
632 md5.update(challenge);
633 md5.update(clientChallenge);
634 final byte[] digest = md5.digest();
635
636 final byte[] sessionHash = new byte[8];
637 System.arraycopy(digest, 0, sessionHash, 0, 8);
638 return lmResponse(ntlmHash, sessionHash);
639 } catch (final Exception e) {
640 if (e instanceof NTLMEngineException) {
641 throw (NTLMEngineException) e;
642 }
643 throw new NTLMEngineException(e.getMessage(), e);
644 }
645 }
646
647
648
649
650
651
652
653
654
655
656 private static byte[] lmHash(final char[] password) throws NTLMEngineException {
657 try {
658 final char[] tmp = new char[password.length];
659 for (int i = 0; i < password.length; i++) {
660 tmp[i] = Character.toUpperCase(password[i]);
661 }
662 final byte[] oemPassword = new ByteArrayBuilder().append(tmp).toByteArray();
663 final int length = Math.min(oemPassword.length, 14);
664 final byte[] keyBytes = new byte[14];
665 System.arraycopy(oemPassword, 0, keyBytes, 0, length);
666 final Key lowKey = createDESKey(keyBytes, 0);
667 final Key highKey = createDESKey(keyBytes, 7);
668 final byte[] magicConstant = "KGS!@#$%".getBytes(StandardCharsets.US_ASCII);
669 final Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
670 des.init(Cipher.ENCRYPT_MODE, lowKey);
671 final byte[] lowHash = des.doFinal(magicConstant);
672 des.init(Cipher.ENCRYPT_MODE, highKey);
673 final byte[] highHash = des.doFinal(magicConstant);
674 final byte[] lmHash = new byte[16];
675 System.arraycopy(lowHash, 0, lmHash, 0, 8);
676 System.arraycopy(highHash, 0, lmHash, 8, 8);
677 return lmHash;
678 } catch (final Exception e) {
679 throw new NTLMEngineException(e.getMessage(), e);
680 }
681 }
682
683
684
685
686
687
688
689
690
691
692 private static byte[] ntlmHash(final char[] password) throws NTLMEngineException {
693 final byte[] unicodePassword = new ByteArrayBuilder()
694 .charset(UNICODE_LITTLE_UNMARKED).append(password).toByteArray();
695 final MD4 md4 = new MD4();
696 md4.update(unicodePassword);
697 return md4.getOutput();
698 }
699
700
701
702
703
704
705
706 private static byte[] lmv2Hash(final String domain, final String user, final byte[] ntlmHash)
707 throws NTLMEngineException {
708 final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
709
710 hmacMD5.update(user.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED));
711 if (domain != null) {
712 hmacMD5.update(domain.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED));
713 }
714 return hmacMD5.getOutput();
715 }
716
717
718
719
720
721
722
723 private static byte[] ntlmv2Hash(final String domain, final String user, final byte[] ntlmHash)
724 throws NTLMEngineException {
725 final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
726
727 hmacMD5.update(user.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED));
728 if (domain != null) {
729 hmacMD5.update(domain.getBytes(UNICODE_LITTLE_UNMARKED));
730 }
731 return hmacMD5.getOutput();
732 }
733
734
735
736
737
738
739
740
741
742
743
744 private static byte[] lmResponse(final byte[] hash, final byte[] challenge) throws NTLMEngineException {
745 try {
746 final byte[] keyBytes = new byte[21];
747 System.arraycopy(hash, 0, keyBytes, 0, 16);
748 final Key lowKey = createDESKey(keyBytes, 0);
749 final Key middleKey = createDESKey(keyBytes, 7);
750 final Key highKey = createDESKey(keyBytes, 14);
751 final Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
752 des.init(Cipher.ENCRYPT_MODE, lowKey);
753 final byte[] lowResponse = des.doFinal(challenge);
754 des.init(Cipher.ENCRYPT_MODE, middleKey);
755 final byte[] middleResponse = des.doFinal(challenge);
756 des.init(Cipher.ENCRYPT_MODE, highKey);
757 final byte[] highResponse = des.doFinal(challenge);
758 final byte[] lmResponse = new byte[24];
759 System.arraycopy(lowResponse, 0, lmResponse, 0, 8);
760 System.arraycopy(middleResponse, 0, lmResponse, 8, 8);
761 System.arraycopy(highResponse, 0, lmResponse, 16, 8);
762 return lmResponse;
763 } catch (final Exception e) {
764 throw new NTLMEngineException(e.getMessage(), e);
765 }
766 }
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782 private static byte[] lmv2Response(final byte[] hash, final byte[] challenge, final byte[] clientData) {
783 final HMACMD5 hmacMD5 = new HMACMD5(hash);
784 hmacMD5.update(challenge);
785 hmacMD5.update(clientData);
786 final byte[] mac = hmacMD5.getOutput();
787 final byte[] lmv2Response = new byte[mac.length + clientData.length];
788 System.arraycopy(mac, 0, lmv2Response, 0, mac.length);
789 System.arraycopy(clientData, 0, lmv2Response, mac.length, clientData.length);
790 return lmv2Response;
791 }
792
793 enum Mode
794 {
795 CLIENT, SERVER
796 }
797
798 static class Handle
799 {
800 private final byte[] signingKey;
801 private byte[] sealingKey;
802 private final Cipher rc4;
803 final Mode mode;
804 final private boolean isConnection;
805 int sequenceNumber;
806
807
808 Handle( final byte[] exportedSessionKey, final Mode mode, final boolean isConnection ) throws NTLMEngineException
809 {
810 this.isConnection = isConnection;
811 this.mode = mode;
812 try
813 {
814 final MessageDigest signMd5 = getMD5();
815 final MessageDigest sealMd5 = getMD5();
816 signMd5.update( exportedSessionKey );
817 sealMd5.update( exportedSessionKey );
818 if ( mode == Mode.CLIENT )
819 {
820 signMd5.update( SIGN_MAGIC_CLIENT );
821 sealMd5.update( SEAL_MAGIC_CLIENT );
822 }
823 else
824 {
825 signMd5.update( SIGN_MAGIC_SERVER );
826 sealMd5.update( SEAL_MAGIC_SERVER );
827 }
828 signingKey = signMd5.digest();
829 sealingKey = sealMd5.digest();
830 }
831 catch ( final Exception e )
832 {
833 throw new NTLMEngineException( e.getMessage(), e );
834 }
835 rc4 = initCipher();
836 }
837
838 public byte[] getSigningKey()
839 {
840 return signingKey;
841 }
842
843
844 public byte[] getSealingKey()
845 {
846 return sealingKey;
847 }
848
849 private Cipher initCipher() throws NTLMEngineException
850 {
851 final Cipher cipher;
852 try
853 {
854 cipher = Cipher.getInstance( "RC4" );
855 if ( mode == Mode.CLIENT )
856 {
857 cipher.init( Cipher.ENCRYPT_MODE, new SecretKeySpec( sealingKey, "RC4" ) );
858 }
859 else
860 {
861 cipher.init( Cipher.DECRYPT_MODE, new SecretKeySpec( sealingKey, "RC4" ) );
862 }
863 }
864 catch ( final Exception e )
865 {
866 throw new NTLMEngineException( e.getMessage(), e );
867 }
868 return cipher;
869 }
870
871
872 private void advanceMessageSequence() throws NTLMEngineException
873 {
874 if ( !isConnection )
875 {
876 final MessageDigest sealMd5 = getMD5();
877 sealMd5.update( sealingKey );
878 final byte[] seqNumBytes = new byte[4];
879 writeULong( seqNumBytes, sequenceNumber, 0 );
880 sealMd5.update( seqNumBytes );
881 sealingKey = sealMd5.digest();
882 initCipher();
883 }
884 sequenceNumber++;
885 }
886
887 private byte[] encrypt( final byte[] data )
888 {
889 return rc4.update( data );
890 }
891
892 private byte[] decrypt( final byte[] data )
893 {
894 return rc4.update( data );
895 }
896
897 private byte[] computeSignature( final byte[] message )
898 {
899 final byte[] sig = new byte[16];
900
901
902 sig[0] = 0x01;
903 sig[1] = 0x00;
904 sig[2] = 0x00;
905 sig[3] = 0x00;
906
907
908 final HMACMD5 hmacMD5 = new HMACMD5( signingKey );
909 hmacMD5.update( encodeLong( sequenceNumber ) );
910 hmacMD5.update( message );
911 final byte[] hmac = hmacMD5.getOutput();
912 final byte[] trimmedHmac = new byte[8];
913 System.arraycopy( hmac, 0, trimmedHmac, 0, 8 );
914 final byte[] encryptedHmac = encrypt( trimmedHmac );
915 System.arraycopy( encryptedHmac, 0, sig, 4, 8 );
916
917
918 encodeLong( sig, 12, sequenceNumber );
919
920 return sig;
921 }
922
923 private boolean validateSignature( final byte[] signature, final byte[] message )
924 {
925 final byte[] computedSignature = computeSignature( message );
926
927
928
929 return Arrays.equals( signature, computedSignature );
930 }
931
932 public byte[] signAndEncryptMessage( final byte[] cleartextMessage ) throws NTLMEngineException
933 {
934 final byte[] encryptedMessage = encrypt( cleartextMessage );
935 final byte[] signature = computeSignature( cleartextMessage );
936 final byte[] outMessage = new byte[signature.length + encryptedMessage.length];
937 System.arraycopy( signature, 0, outMessage, 0, signature.length );
938 System.arraycopy( encryptedMessage, 0, outMessage, signature.length, encryptedMessage.length );
939 advanceMessageSequence();
940 return outMessage;
941 }
942
943 public byte[] decryptAndVerifySignedMessage( final byte[] inMessage ) throws NTLMEngineException
944 {
945 final byte[] signature = new byte[16];
946 System.arraycopy( inMessage, 0, signature, 0, signature.length );
947 final byte[] encryptedMessage = new byte[inMessage.length - 16];
948 System.arraycopy( inMessage, 16, encryptedMessage, 0, encryptedMessage.length );
949 final byte[] cleartextMessage = decrypt( encryptedMessage );
950 if ( !validateSignature( signature, cleartextMessage ) )
951 {
952 throw new NTLMEngineException( "Wrong signature" );
953 }
954 advanceMessageSequence();
955 return cleartextMessage;
956 }
957
958 }
959
960 private static byte[] encodeLong( final int value )
961 {
962 final byte[] enc = new byte[4];
963 encodeLong( enc, 0, value );
964 return enc;
965 }
966
967 private static void encodeLong( final byte[] buf, final int offset, final int value )
968 {
969 buf[offset + 0] = ( byte ) ( value & 0xff );
970 buf[offset + 1] = ( byte ) ( value >> 8 & 0xff );
971 buf[offset + 2] = ( byte ) ( value >> 16 & 0xff );
972 buf[offset + 3] = ( byte ) ( value >> 24 & 0xff );
973 }
974
975
976
977
978
979
980
981
982
983
984
985
986 private static byte[] createBlob(final byte[] clientChallenge, final byte[] targetInformation, final byte[] timestamp) {
987 final byte[] blobSignature = new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00 };
988 final byte[] reserved = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
989 final byte[] unknown1 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
990 final byte[] unknown2 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
991 final byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8
992 + unknown1.length + targetInformation.length + unknown2.length];
993 int offset = 0;
994 System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length);
995 offset += blobSignature.length;
996 System.arraycopy(reserved, 0, blob, offset, reserved.length);
997 offset += reserved.length;
998 System.arraycopy(timestamp, 0, blob, offset, timestamp.length);
999 offset += timestamp.length;
1000 System.arraycopy(clientChallenge, 0, blob, offset, 8);
1001 offset += 8;
1002 System.arraycopy(unknown1, 0, blob, offset, unknown1.length);
1003 offset += unknown1.length;
1004 System.arraycopy(targetInformation, 0, blob, offset, targetInformation.length);
1005 offset += targetInformation.length;
1006 System.arraycopy(unknown2, 0, blob, offset, unknown2.length);
1007 offset += unknown2.length;
1008 return blob;
1009 }
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023 private static Key createDESKey(final byte[] bytes, final int offset) {
1024 final byte[] keyBytes = new byte[7];
1025 System.arraycopy(bytes, offset, keyBytes, 0, 7);
1026 final byte[] material = new byte[8];
1027 material[0] = keyBytes[0];
1028 material[1] = (byte) (keyBytes[0] << 7 | (keyBytes[1] & 0xff) >>> 1);
1029 material[2] = (byte) (keyBytes[1] << 6 | (keyBytes[2] & 0xff) >>> 2);
1030 material[3] = (byte) (keyBytes[2] << 5 | (keyBytes[3] & 0xff) >>> 3);
1031 material[4] = (byte) (keyBytes[3] << 4 | (keyBytes[4] & 0xff) >>> 4);
1032 material[5] = (byte) (keyBytes[4] << 3 | (keyBytes[5] & 0xff) >>> 5);
1033 material[6] = (byte) (keyBytes[5] << 2 | (keyBytes[6] & 0xff) >>> 6);
1034 material[7] = (byte) (keyBytes[6] << 1);
1035 oddParity(material);
1036 return new SecretKeySpec(material, "DES");
1037 }
1038
1039
1040
1041
1042
1043
1044
1045 private static void oddParity(final byte[] bytes) {
1046 for (int i = 0; i < bytes.length; i++) {
1047 final byte b = bytes[i];
1048 final boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3)
1049 ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0;
1050 if (needsParity) {
1051 bytes[i] |= (byte) 0x01;
1052 } else {
1053 bytes[i] &= (byte) 0xfe;
1054 }
1055 }
1056 }
1057
1058
1059
1060
1061
1062
1063 private static Charset getCharset(final int flags) throws NTLMEngineException
1064 {
1065 if ((flags & FLAG_REQUEST_UNICODE_ENCODING) == 0) {
1066 return DEFAULT_CHARSET;
1067 }
1068 return UNICODE_LITTLE_UNMARKED;
1069 }
1070
1071
1072 static class NTLMMessage {
1073
1074 byte[] messageContents;
1075
1076
1077 int currentOutputPosition;
1078
1079
1080 NTLMMessage() {
1081 }
1082
1083
1084 NTLMMessage(final String messageBody, final int expectedType) throws NTLMEngineException {
1085 this(Base64.decodeBase64(messageBody.getBytes(DEFAULT_CHARSET)), expectedType);
1086 }
1087
1088
1089 NTLMMessage(final byte[] message, final int expectedType) throws NTLMEngineException {
1090 messageContents = message;
1091
1092 if (messageContents.length < SIGNATURE.length) {
1093 throw new NTLMEngineException("NTLM message decoding error - packet too short");
1094 }
1095 int i = 0;
1096 while (i < SIGNATURE.length) {
1097 if (messageContents[i] != SIGNATURE[i]) {
1098 throw new NTLMEngineException(
1099 "NTLM message expected - instead got unrecognized bytes");
1100 }
1101 i++;
1102 }
1103
1104
1105 final int type = readULong(SIGNATURE.length);
1106 if (type != expectedType) {
1107 throw new NTLMEngineException("NTLM type " + expectedType
1108 + " message expected - instead got type " + type);
1109 }
1110
1111 currentOutputPosition = messageContents.length;
1112 }
1113
1114
1115
1116
1117
1118 int getPreambleLength() {
1119 return SIGNATURE.length + 4;
1120 }
1121
1122
1123 int getMessageLength() {
1124 return currentOutputPosition;
1125 }
1126
1127
1128 byte readByte(final int position) throws NTLMEngineException {
1129 if (messageContents.length < position + 1) {
1130 throw new NTLMEngineException("NTLM: Message too short");
1131 }
1132 return messageContents[position];
1133 }
1134
1135
1136 void readBytes(final byte[] buffer, final int position) throws NTLMEngineException {
1137 if (messageContents.length < position + buffer.length) {
1138 throw new NTLMEngineException("NTLM: Message too short");
1139 }
1140 System.arraycopy(messageContents, position, buffer, 0, buffer.length);
1141 }
1142
1143
1144 int readUShort(final int position) {
1145 return NTLMEngineImpl.readUShort(messageContents, position);
1146 }
1147
1148
1149 int readULong(final int position) {
1150 return NTLMEngineImpl.readULong(messageContents, position);
1151 }
1152
1153
1154 byte[] readSecurityBuffer(final int position) {
1155 return NTLMEngineImpl.readSecurityBuffer(messageContents, position);
1156 }
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166 void prepareResponse(final int maxlength, final int messageType) {
1167 messageContents = new byte[maxlength];
1168 currentOutputPosition = 0;
1169 addBytes(SIGNATURE);
1170 addULong(messageType);
1171 }
1172
1173
1174
1175
1176
1177
1178
1179 void addByte(final byte b) {
1180 messageContents[currentOutputPosition] = b;
1181 currentOutputPosition++;
1182 }
1183
1184
1185
1186
1187
1188
1189
1190 void addBytes(final byte[] bytes) {
1191 if (bytes == null) {
1192 return;
1193 }
1194 for (final byte b : bytes) {
1195 messageContents[currentOutputPosition] = b;
1196 currentOutputPosition++;
1197 }
1198 }
1199
1200
1201 void addUShort(final int value) {
1202 addByte((byte) (value & 0xff));
1203 addByte((byte) (value >> 8 & 0xff));
1204 }
1205
1206
1207 void addULong(final int value) {
1208 addByte((byte) (value & 0xff));
1209 addByte((byte) (value >> 8 & 0xff));
1210 addByte((byte) (value >> 16 & 0xff));
1211 addByte((byte) (value >> 24 & 0xff));
1212 }
1213
1214
1215
1216
1217
1218
1219
1220 public String getResponse() {
1221 return new String(Base64.encodeBase64(getBytes()), StandardCharsets.US_ASCII);
1222 }
1223
1224 public byte[] getBytes() {
1225 if (messageContents == null) {
1226 buildMessage();
1227 }
1228 if (messageContents.length > currentOutputPosition) {
1229 final byte[] tmp = new byte[currentOutputPosition];
1230 System.arraycopy( messageContents, 0, tmp, 0, currentOutputPosition );
1231 messageContents = tmp;
1232 }
1233 return messageContents;
1234 }
1235
1236 void buildMessage() {
1237 throw new RuntimeException("Message builder not implemented for "+getClass().getName());
1238 }
1239 }
1240
1241
1242 static class Type1Message extends NTLMMessage {
1243
1244 private final byte[] hostBytes;
1245 private final byte[] domainBytes;
1246 private final int flags;
1247
1248 Type1Message(final String domain, final String host) {
1249 this(domain, host, null);
1250 }
1251
1252 Type1Message(final String domain, final String host, final Integer flags) {
1253 super();
1254 this.flags = ((flags == null)?getDefaultFlags(): flags.intValue());
1255
1256
1257 final String unqualifiedHost = host;
1258 final String unqualifiedDomain = domain;
1259
1260 hostBytes = unqualifiedHost != null ?
1261 unqualifiedHost.getBytes(UNICODE_LITTLE_UNMARKED) : null;
1262 domainBytes = unqualifiedDomain != null ?
1263 unqualifiedDomain.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED) : null;
1264 }
1265
1266 Type1Message() {
1267 super();
1268 hostBytes = null;
1269 domainBytes = null;
1270 flags = getDefaultFlags();
1271 }
1272
1273 private int getDefaultFlags() {
1274 return
1275
1276
1277
1278
1279
1280 FLAG_REQUEST_NTLMv1 |
1281 FLAG_REQUEST_NTLM2_SESSION |
1282
1283
1284 FLAG_REQUEST_VERSION |
1285
1286
1287 FLAG_REQUEST_ALWAYS_SIGN |
1288
1289
1290
1291
1292 FLAG_REQUEST_128BIT_KEY_EXCH |
1293 FLAG_REQUEST_56BIT_ENCRYPTION |
1294
1295
1296 FLAG_REQUEST_UNICODE_ENCODING;
1297
1298 }
1299
1300
1301
1302
1303
1304 @Override
1305 void buildMessage() {
1306 int domainBytesLength = 0;
1307 if ( domainBytes != null ) {
1308 domainBytesLength = domainBytes.length;
1309 }
1310 int hostBytesLength = 0;
1311 if ( hostBytes != null ) {
1312 hostBytesLength = hostBytes.length;
1313 }
1314
1315
1316
1317 final int finalLength = 32 + 8 + hostBytesLength + domainBytesLength;
1318
1319
1320
1321 prepareResponse(finalLength, 1);
1322
1323
1324 addULong(flags);
1325
1326
1327 addUShort(domainBytesLength);
1328 addUShort(domainBytesLength);
1329
1330
1331 addULong(hostBytesLength + 32 + 8);
1332
1333
1334 addUShort(hostBytesLength);
1335 addUShort(hostBytesLength);
1336
1337
1338 addULong(32 + 8);
1339
1340
1341 addUShort(0x0105);
1342
1343 addULong(2600);
1344
1345 addUShort(0x0f00);
1346
1347
1348 if (hostBytes != null) {
1349 addBytes(hostBytes);
1350 }
1351
1352 if (domainBytes != null) {
1353 addBytes(domainBytes);
1354 }
1355 }
1356
1357 }
1358
1359
1360 static class Type2Message extends NTLMMessage {
1361 final byte[] challenge;
1362 String target;
1363 byte[] targetInfo;
1364 final int flags;
1365
1366 Type2Message(final String messageBody) throws NTLMEngineException {
1367 this(Base64.decodeBase64(messageBody.getBytes(DEFAULT_CHARSET)));
1368 }
1369
1370 Type2Message(final byte[] message) throws NTLMEngineException {
1371 super(message, 2);
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388 challenge = new byte[8];
1389 readBytes(challenge, 24);
1390
1391 flags = readULong(20);
1392
1393
1394 target = null;
1395
1396
1397
1398 if (getMessageLength() >= 12 + 8) {
1399 final byte[] bytes = readSecurityBuffer(12);
1400 if (bytes.length != 0) {
1401 target = new String(bytes, getCharset(flags));
1402 }
1403 }
1404
1405
1406 targetInfo = null;
1407
1408 if (getMessageLength() >= 40 + 8) {
1409 final byte[] bytes = readSecurityBuffer(40);
1410 if (bytes.length != 0) {
1411 targetInfo = bytes;
1412 }
1413 }
1414 }
1415
1416
1417 byte[] getChallenge() {
1418 return challenge;
1419 }
1420
1421
1422 String getTarget() {
1423 return target;
1424 }
1425
1426
1427 byte[] getTargetInfo() {
1428 return targetInfo;
1429 }
1430
1431
1432 int getFlags() {
1433 return flags;
1434 }
1435
1436 }
1437
1438
1439 static class Type3Message extends NTLMMessage {
1440
1441 final byte[] type1Message;
1442 final byte[] type2Message;
1443
1444 final int type2Flags;
1445
1446 final byte[] domainBytes;
1447 final byte[] hostBytes;
1448 final byte[] userBytes;
1449
1450 byte[] lmResp;
1451 byte[] ntResp;
1452 final byte[] sessionKey;
1453 final byte[] exportedSessionKey;
1454
1455 final boolean computeMic;
1456
1457
1458
1459 Type3Message(final String domain,
1460 final String host,
1461 final String user,
1462 final char[] password,
1463 final byte[] nonce,
1464 final int type2Flags,
1465 final String target,
1466 final byte[] targetInformation)
1467 throws NTLMEngineException {
1468 this(domain, host, user, password, nonce, type2Flags, target, targetInformation, null, null, null);
1469 }
1470
1471
1472
1473 Type3Message(final Random random, final long currentTime,
1474 final String domain,
1475 final String host,
1476 final String user,
1477 final char[] password,
1478 final byte[] nonce,
1479 final int type2Flags,
1480 final String target,
1481 final byte[] targetInformation)
1482 throws NTLMEngineException {
1483 this(random, currentTime, domain, host, user, password, nonce, type2Flags, target, targetInformation, null, null, null);
1484 }
1485
1486
1487 Type3Message(final String domain,
1488 final String host,
1489 final String user,
1490 final char[] password,
1491 final byte[] nonce,
1492 final int type2Flags,
1493 final String target,
1494 final byte[] targetInformation,
1495 final Certificate peerServerCertificate,
1496 final byte[] type1Message,
1497 final byte[] type2Message)
1498 throws NTLMEngineException {
1499 this(RND_GEN, System.currentTimeMillis(), domain, host, user, password, nonce, type2Flags, target, targetInformation, peerServerCertificate, type1Message, type2Message);
1500 }
1501
1502
1503 Type3Message(final Random random, final long currentTime,
1504 final String domain,
1505 final String host,
1506 final String user,
1507 final char[] password,
1508 final byte[] nonce,
1509 final int type2Flags,
1510 final String target,
1511 final byte[] targetInformation,
1512 final Certificate peerServerCertificate,
1513 final byte[] type1Message,
1514 final byte[] type2Message)
1515 throws NTLMEngineException {
1516
1517 if (random == null) {
1518 throw new NTLMEngineException("Random generator not available");
1519 }
1520
1521
1522 this.type2Flags = type2Flags;
1523 this.type1Message = type1Message;
1524 this.type2Message = type2Message;
1525
1526
1527 final String unqualifiedHost = host;
1528
1529 final String unqualifiedDomain = domain;
1530
1531 byte[] responseTargetInformation = targetInformation;
1532 if (peerServerCertificate != null) {
1533 responseTargetInformation = addGssMicAvsToTargetInfo(targetInformation, peerServerCertificate);
1534 computeMic = true;
1535 } else {
1536 computeMic = false;
1537 }
1538
1539
1540 final CipherGen gen = new CipherGen(random, currentTime,
1541 unqualifiedDomain,
1542 user,
1543 password,
1544 nonce,
1545 target,
1546 responseTargetInformation);
1547
1548
1549
1550 byte[] userSessionKey;
1551 try {
1552
1553
1554 if (((type2Flags & FLAG_TARGETINFO_PRESENT) != 0) &&
1555 targetInformation != null && target != null) {
1556
1557 ntResp = gen.getNTLMv2Response();
1558 lmResp = gen.getLMv2Response();
1559 if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) {
1560 userSessionKey = gen.getLanManagerSessionKey();
1561 } else {
1562 userSessionKey = gen.getNTLMv2UserSessionKey();
1563 }
1564 } else {
1565
1566 if ((type2Flags & FLAG_REQUEST_NTLM2_SESSION) != 0) {
1567
1568 ntResp = gen.getNTLM2SessionResponse();
1569 lmResp = gen.getLM2SessionResponse();
1570 if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) {
1571 userSessionKey = gen.getLanManagerSessionKey();
1572 } else {
1573 userSessionKey = gen.getNTLM2SessionResponseUserSessionKey();
1574 }
1575 } else {
1576 ntResp = gen.getNTLMResponse();
1577 lmResp = gen.getLMResponse();
1578 if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) {
1579 userSessionKey = gen.getLanManagerSessionKey();
1580 } else {
1581 userSessionKey = gen.getNTLMUserSessionKey();
1582 }
1583 }
1584 }
1585 } catch (final NTLMEngineException e) {
1586
1587
1588 ntResp = new byte[0];
1589 lmResp = gen.getLMResponse();
1590 if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) {
1591 userSessionKey = gen.getLanManagerSessionKey();
1592 } else {
1593 userSessionKey = gen.getLMUserSessionKey();
1594 }
1595 }
1596
1597 if ((type2Flags & FLAG_REQUEST_SIGN) != 0) {
1598 if ((type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) != 0) {
1599 exportedSessionKey = gen.getSecondaryKey();
1600 sessionKey = RC4(exportedSessionKey, userSessionKey);
1601 } else {
1602 sessionKey = userSessionKey;
1603 exportedSessionKey = sessionKey;
1604 }
1605 } else {
1606 if (computeMic) {
1607 throw new NTLMEngineException("Cannot sign/seal: no exported session key");
1608 }
1609 sessionKey = null;
1610 exportedSessionKey = null;
1611 }
1612 final Charset charset = getCharset(type2Flags);
1613 hostBytes = unqualifiedHost != null ? unqualifiedHost.getBytes(charset) : null;
1614 domainBytes = unqualifiedDomain != null ? unqualifiedDomain
1615 .toUpperCase(Locale.ROOT).getBytes(charset) : null;
1616 userBytes = user.getBytes(charset);
1617 }
1618
1619 public byte[] getEncryptedRandomSessionKey() {
1620 return sessionKey;
1621 }
1622
1623 public byte[] getExportedSessionKey() {
1624 return exportedSessionKey;
1625 }
1626
1627
1628 @Override
1629 void buildMessage() {
1630 final int ntRespLen = ntResp.length;
1631 final int lmRespLen = lmResp.length;
1632
1633 final int domainLen = domainBytes != null ? domainBytes.length : 0;
1634 final int hostLen = hostBytes != null ? hostBytes.length: 0;
1635 final int userLen = userBytes.length;
1636 final int sessionKeyLen;
1637 if (sessionKey != null) {
1638 sessionKeyLen = sessionKey.length;
1639 } else {
1640 sessionKeyLen = 0;
1641 }
1642
1643
1644 final int lmRespOffset = 72 +
1645 ( computeMic ? 16 : 0 );
1646 final int ntRespOffset = lmRespOffset + lmRespLen;
1647 final int domainOffset = ntRespOffset + ntRespLen;
1648 final int userOffset = domainOffset + domainLen;
1649 final int hostOffset = userOffset + userLen;
1650 final int sessionKeyOffset = hostOffset + hostLen;
1651 final int finalLength = sessionKeyOffset + sessionKeyLen;
1652
1653
1654 prepareResponse(finalLength, 3);
1655
1656
1657 addUShort(lmRespLen);
1658 addUShort(lmRespLen);
1659
1660
1661 addULong(lmRespOffset);
1662
1663
1664 addUShort(ntRespLen);
1665 addUShort(ntRespLen);
1666
1667
1668 addULong(ntRespOffset);
1669
1670
1671 addUShort(domainLen);
1672 addUShort(domainLen);
1673
1674
1675 addULong(domainOffset);
1676
1677
1678 addUShort(userLen);
1679 addUShort(userLen);
1680
1681
1682 addULong(userOffset);
1683
1684
1685 addUShort(hostLen);
1686 addUShort(hostLen);
1687
1688
1689 addULong(hostOffset);
1690
1691
1692 addUShort(sessionKeyLen);
1693 addUShort(sessionKeyLen);
1694
1695
1696 addULong(sessionKeyOffset);
1697
1698
1699 addULong(
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726 type2Flags
1727 );
1728
1729
1730 addUShort(0x0105);
1731
1732 addULong(2600);
1733
1734 addUShort(0x0f00);
1735
1736 int micPosition = -1;
1737 if ( computeMic ) {
1738 micPosition = currentOutputPosition;
1739 currentOutputPosition += 16;
1740 }
1741
1742
1743 addBytes(lmResp);
1744 addBytes(ntResp);
1745 addBytes(domainBytes);
1746 addBytes(userBytes);
1747 addBytes(hostBytes);
1748 if (sessionKey != null) {
1749 addBytes(sessionKey);
1750 }
1751
1752
1753
1754 if (computeMic) {
1755
1756 final HMACMD5 hmacMD5 = new HMACMD5( exportedSessionKey );
1757 hmacMD5.update( type1Message );
1758 hmacMD5.update( type2Message );
1759 hmacMD5.update( messageContents );
1760 final byte[] mic = hmacMD5.getOutput();
1761 System.arraycopy( mic, 0, messageContents, micPosition, mic.length );
1762 }
1763 }
1764
1765
1766
1767
1768
1769 private byte[] addGssMicAvsToTargetInfo( final byte[] originalTargetInfo,
1770 final Certificate peerServerCertificate ) throws NTLMEngineException
1771 {
1772 final byte[] newTargetInfo = new byte[originalTargetInfo.length + 8 + 20];
1773 final int appendLength = originalTargetInfo.length - 4;
1774 System.arraycopy( originalTargetInfo, 0, newTargetInfo, 0, appendLength );
1775 writeUShort( newTargetInfo, MSV_AV_FLAGS, appendLength );
1776 writeUShort( newTargetInfo, 4, appendLength + 2 );
1777 writeULong( newTargetInfo, MSV_AV_FLAGS_MIC, appendLength + 4 );
1778 writeUShort( newTargetInfo, MSV_AV_CHANNEL_BINDINGS, appendLength + 8 );
1779 writeUShort( newTargetInfo, 16, appendLength + 10 );
1780
1781 final byte[] channelBindingsHash;
1782 try
1783 {
1784 final byte[] certBytes = peerServerCertificate.getEncoded();
1785 final MessageDigest sha256 = MessageDigest.getInstance( "SHA-256" );
1786 final byte[] certHashBytes = sha256.digest( certBytes );
1787 final byte[] channelBindingStruct = new byte[16 + 4 + MAGIC_TLS_SERVER_ENDPOINT.length
1788 + certHashBytes.length];
1789 writeULong( channelBindingStruct, 0x00000035, 16 );
1790 System.arraycopy( MAGIC_TLS_SERVER_ENDPOINT, 0, channelBindingStruct, 20,
1791 MAGIC_TLS_SERVER_ENDPOINT.length );
1792 System.arraycopy( certHashBytes, 0, channelBindingStruct, 20 + MAGIC_TLS_SERVER_ENDPOINT.length,
1793 certHashBytes.length );
1794 final MessageDigest md5 = getMD5();
1795 channelBindingsHash = md5.digest( channelBindingStruct );
1796 }
1797 catch (final CertificateEncodingException | NoSuchAlgorithmException e )
1798 {
1799 throw new NTLMEngineException( e.getMessage(), e );
1800 }
1801
1802 System.arraycopy( channelBindingsHash, 0, newTargetInfo, appendLength + 12, 16 );
1803 return newTargetInfo;
1804 }
1805
1806 }
1807
1808 static void writeUShort(final byte[] buffer, final int value, final int offset) {
1809 buffer[offset] = ( byte ) ( value & 0xff );
1810 buffer[offset + 1] = ( byte ) ( value >> 8 & 0xff );
1811 }
1812
1813 static void writeULong(final byte[] buffer, final int value, final int offset) {
1814 buffer[offset] = (byte) (value & 0xff);
1815 buffer[offset + 1] = (byte) (value >> 8 & 0xff);
1816 buffer[offset + 2] = (byte) (value >> 16 & 0xff);
1817 buffer[offset + 3] = (byte) (value >> 24 & 0xff);
1818 }
1819
1820 static int F(final int x, final int y, final int z) {
1821 return ((x & y) | (~x & z));
1822 }
1823
1824 static int G(final int x, final int y, final int z) {
1825 return ((x & y) | (x & z) | (y & z));
1826 }
1827
1828 static int H(final int x, final int y, final int z) {
1829 return (x ^ y ^ z);
1830 }
1831
1832 static int rotintlft(final int val, final int numbits) {
1833 return ((val << numbits) | (val >>> (32 - numbits)));
1834 }
1835
1836 static MessageDigest getMD5() {
1837 try {
1838 return MessageDigest.getInstance("MD5");
1839 } catch (final NoSuchAlgorithmException ex) {
1840 throw new RuntimeException("MD5 message digest doesn't seem to exist - fatal error: "+ex.getMessage(), ex);
1841 }
1842 }
1843
1844
1845
1846
1847
1848
1849
1850
1851 static class MD4 {
1852 int A = 0x67452301;
1853 int B = 0xefcdab89;
1854 int C = 0x98badcfe;
1855 int D = 0x10325476;
1856 long count;
1857 final byte[] dataBuffer = new byte[64];
1858
1859 MD4() {
1860 }
1861
1862 void update(final byte[] input) {
1863
1864
1865
1866 int curBufferPos = (int) (count & 63L);
1867 int inputIndex = 0;
1868 while (input.length - inputIndex + curBufferPos >= dataBuffer.length) {
1869
1870
1871
1872 final int transferAmt = dataBuffer.length - curBufferPos;
1873 System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt);
1874 count += transferAmt;
1875 curBufferPos = 0;
1876 inputIndex += transferAmt;
1877 processBuffer();
1878 }
1879
1880
1881
1882 if (inputIndex < input.length) {
1883 final int transferAmt = input.length - inputIndex;
1884 System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt);
1885 count += transferAmt;
1886 curBufferPos += transferAmt;
1887 }
1888 }
1889
1890 byte[] getOutput() {
1891
1892
1893 final int bufferIndex = (int) (count & 63L);
1894 final int padLen = (bufferIndex < 56) ? (56 - bufferIndex) : (120 - bufferIndex);
1895 final byte[] postBytes = new byte[padLen + 8];
1896
1897
1898 postBytes[0] = (byte) 0x80;
1899
1900 for (int i = 0; i < 8; i++) {
1901 postBytes[padLen + i] = (byte) ((count * 8) >>> (8 * i));
1902 }
1903
1904
1905 update(postBytes);
1906
1907
1908 final byte[] result = new byte[16];
1909 writeULong(result, A, 0);
1910 writeULong(result, B, 4);
1911 writeULong(result, C, 8);
1912 writeULong(result, D, 12);
1913 return result;
1914 }
1915
1916 void processBuffer() {
1917
1918 final int[] d = new int[16];
1919
1920 for (int i = 0; i < 16; i++) {
1921 d[i] = (dataBuffer[i * 4] & 0xff) + ((dataBuffer[i * 4 + 1] & 0xff) << 8)
1922 + ((dataBuffer[i * 4 + 2] & 0xff) << 16)
1923 + ((dataBuffer[i * 4 + 3] & 0xff) << 24);
1924 }
1925
1926
1927 final int AA = A;
1928 final int BB = B;
1929 final int CC = C;
1930 final int DD = D;
1931 round1(d);
1932 round2(d);
1933 round3(d);
1934 A += AA;
1935 B += BB;
1936 C += CC;
1937 D += DD;
1938
1939 }
1940
1941 void round1(final int[] d) {
1942 A = rotintlft((A + F(B, C, D) + d[0]), 3);
1943 D = rotintlft((D + F(A, B, C) + d[1]), 7);
1944 C = rotintlft((C + F(D, A, B) + d[2]), 11);
1945 B = rotintlft((B + F(C, D, A) + d[3]), 19);
1946
1947 A = rotintlft((A + F(B, C, D) + d[4]), 3);
1948 D = rotintlft((D + F(A, B, C) + d[5]), 7);
1949 C = rotintlft((C + F(D, A, B) + d[6]), 11);
1950 B = rotintlft((B + F(C, D, A) + d[7]), 19);
1951
1952 A = rotintlft((A + F(B, C, D) + d[8]), 3);
1953 D = rotintlft((D + F(A, B, C) + d[9]), 7);
1954 C = rotintlft((C + F(D, A, B) + d[10]), 11);
1955 B = rotintlft((B + F(C, D, A) + d[11]), 19);
1956
1957 A = rotintlft((A + F(B, C, D) + d[12]), 3);
1958 D = rotintlft((D + F(A, B, C) + d[13]), 7);
1959 C = rotintlft((C + F(D, A, B) + d[14]), 11);
1960 B = rotintlft((B + F(C, D, A) + d[15]), 19);
1961 }
1962
1963 void round2(final int[] d) {
1964 A = rotintlft((A + G(B, C, D) + d[0] + 0x5a827999), 3);
1965 D = rotintlft((D + G(A, B, C) + d[4] + 0x5a827999), 5);
1966 C = rotintlft((C + G(D, A, B) + d[8] + 0x5a827999), 9);
1967 B = rotintlft((B + G(C, D, A) + d[12] + 0x5a827999), 13);
1968
1969 A = rotintlft((A + G(B, C, D) + d[1] + 0x5a827999), 3);
1970 D = rotintlft((D + G(A, B, C) + d[5] + 0x5a827999), 5);
1971 C = rotintlft((C + G(D, A, B) + d[9] + 0x5a827999), 9);
1972 B = rotintlft((B + G(C, D, A) + d[13] + 0x5a827999), 13);
1973
1974 A = rotintlft((A + G(B, C, D) + d[2] + 0x5a827999), 3);
1975 D = rotintlft((D + G(A, B, C) + d[6] + 0x5a827999), 5);
1976 C = rotintlft((C + G(D, A, B) + d[10] + 0x5a827999), 9);
1977 B = rotintlft((B + G(C, D, A) + d[14] + 0x5a827999), 13);
1978
1979 A = rotintlft((A + G(B, C, D) + d[3] + 0x5a827999), 3);
1980 D = rotintlft((D + G(A, B, C) + d[7] + 0x5a827999), 5);
1981 C = rotintlft((C + G(D, A, B) + d[11] + 0x5a827999), 9);
1982 B = rotintlft((B + G(C, D, A) + d[15] + 0x5a827999), 13);
1983
1984 }
1985
1986 void round3(final int[] d) {
1987 A = rotintlft((A + H(B, C, D) + d[0] + 0x6ed9eba1), 3);
1988 D = rotintlft((D + H(A, B, C) + d[8] + 0x6ed9eba1), 9);
1989 C = rotintlft((C + H(D, A, B) + d[4] + 0x6ed9eba1), 11);
1990 B = rotintlft((B + H(C, D, A) + d[12] + 0x6ed9eba1), 15);
1991
1992 A = rotintlft((A + H(B, C, D) + d[2] + 0x6ed9eba1), 3);
1993 D = rotintlft((D + H(A, B, C) + d[10] + 0x6ed9eba1), 9);
1994 C = rotintlft((C + H(D, A, B) + d[6] + 0x6ed9eba1), 11);
1995 B = rotintlft((B + H(C, D, A) + d[14] + 0x6ed9eba1), 15);
1996
1997 A = rotintlft((A + H(B, C, D) + d[1] + 0x6ed9eba1), 3);
1998 D = rotintlft((D + H(A, B, C) + d[9] + 0x6ed9eba1), 9);
1999 C = rotintlft((C + H(D, A, B) + d[5] + 0x6ed9eba1), 11);
2000 B = rotintlft((B + H(C, D, A) + d[13] + 0x6ed9eba1), 15);
2001
2002 A = rotintlft((A + H(B, C, D) + d[3] + 0x6ed9eba1), 3);
2003 D = rotintlft((D + H(A, B, C) + d[11] + 0x6ed9eba1), 9);
2004 C = rotintlft((C + H(D, A, B) + d[7] + 0x6ed9eba1), 11);
2005 B = rotintlft((B + H(C, D, A) + d[15] + 0x6ed9eba1), 15);
2006
2007 }
2008
2009 }
2010
2011
2012
2013
2014
2015 static class HMACMD5 {
2016 final byte[] ipad;
2017 final byte[] opad;
2018 final MessageDigest md5;
2019
2020 HMACMD5(final byte[] input) {
2021 byte[] key = input;
2022 md5 = getMD5();
2023
2024
2025 ipad = new byte[64];
2026 opad = new byte[64];
2027
2028 int keyLength = key.length;
2029 if (keyLength > 64) {
2030
2031 md5.update(key);
2032 key = md5.digest();
2033 keyLength = key.length;
2034 }
2035 int i = 0;
2036 while (i < keyLength) {
2037 ipad[i] = (byte) (key[i] ^ (byte) 0x36);
2038 opad[i] = (byte) (key[i] ^ (byte) 0x5c);
2039 i++;
2040 }
2041 while (i < 64) {
2042 ipad[i] = (byte) 0x36;
2043 opad[i] = (byte) 0x5c;
2044 i++;
2045 }
2046
2047
2048 md5.reset();
2049 md5.update(ipad);
2050
2051 }
2052
2053
2054 byte[] getOutput() {
2055 final byte[] digest = md5.digest();
2056 md5.update(opad);
2057 return md5.digest(digest);
2058 }
2059
2060
2061 void update(final byte[] input) {
2062 md5.update(input);
2063 }
2064
2065
2066 void update(final byte[] input, final int offset, final int length) {
2067 md5.update(input, offset, length);
2068 }
2069
2070 }
2071
2072 @Override
2073 public String generateType1Msg(
2074 final String domain,
2075 final String workstation) throws NTLMEngineException {
2076 return getType1Message(workstation, domain);
2077 }
2078
2079 @Override
2080 public String generateType3Msg(
2081 final String username,
2082 final char[] password,
2083 final String domain,
2084 final String workstation,
2085 final String challenge) throws NTLMEngineException {
2086 final Type2Message t2m = new Type2Message(challenge);
2087 return getType3Message(
2088 username,
2089 password,
2090 workstation,
2091 domain,
2092 t2m.getChallenge(),
2093 t2m.getFlags(),
2094 t2m.getTarget(),
2095 t2m.getTargetInfo());
2096 }
2097
2098 }