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.http.impl.auth;
28
29 import java.security.Key;
30 import java.security.MessageDigest;
31 import java.util.Arrays;
32 import java.util.Locale;
33
34 import javax.crypto.Cipher;
35 import javax.crypto.spec.SecretKeySpec;
36
37 import org.apache.commons.codec.binary.Base64;
38 import org.apache.http.util.EncodingUtils;
39
40
41
42
43
44
45
46 final class NTLMEngineImpl implements NTLMEngine {
47
48
49
50
51
52 protected final static int FLAG_REQUEST_UNICODE_ENCODING = 0x00000001;
53 protected final static int FLAG_REQUEST_TARGET = 0x00000004;
54 protected final static int FLAG_REQUEST_SIGN = 0x00000010;
55 protected final static int FLAG_REQUEST_SEAL = 0x00000020;
56 protected final static int FLAG_REQUEST_LAN_MANAGER_KEY = 0x00000080;
57 protected final static int FLAG_REQUEST_NTLMv1 = 0x00000200;
58 protected final static int FLAG_DOMAIN_PRESENT = 0x00001000;
59 protected final static int FLAG_WORKSTATION_PRESENT = 0x00002000;
60 protected final static int FLAG_REQUEST_ALWAYS_SIGN = 0x00008000;
61 protected final static int FLAG_REQUEST_NTLM2_SESSION = 0x00080000;
62 protected final static int FLAG_REQUEST_VERSION = 0x02000000;
63 protected final static int FLAG_TARGETINFO_PRESENT = 0x00800000;
64 protected final static int FLAG_REQUEST_128BIT_KEY_EXCH = 0x20000000;
65 protected final static int FLAG_REQUEST_EXPLICIT_KEY_EXCH = 0x40000000;
66 protected final static int FLAG_REQUEST_56BIT_ENCRYPTION = 0x80000000;
67
68
69
70 private static final java.security.SecureRandom RND_GEN;
71 static {
72 java.security.SecureRandom rnd = null;
73 try {
74 rnd = java.security.SecureRandom.getInstance("SHA1PRNG");
75 } catch (Exception e) {
76 }
77 RND_GEN = rnd;
78 }
79
80
81 static final String DEFAULT_CHARSET = "ASCII";
82
83
84 private String credentialCharset = DEFAULT_CHARSET;
85
86
87 private static byte[] SIGNATURE;
88
89 static {
90 byte[] bytesWithoutNull = EncodingUtils.getBytes("NTLMSSP", "ASCII");
91 SIGNATURE = new byte[bytesWithoutNull.length + 1];
92 System.arraycopy(bytesWithoutNull, 0, SIGNATURE, 0, bytesWithoutNull.length);
93 SIGNATURE[bytesWithoutNull.length] = (byte) 0x00;
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 final String getResponseFor(String message, String username, String password,
114 String host, String domain) throws NTLMEngineException {
115
116 final String response;
117 if (message == null || message.trim().equals("")) {
118 response = getType1Message(host, domain);
119 } else {
120 Type2Message t2m = new Type2Message(message);
121 response = getType3Message(username, password, host, domain, t2m.getChallenge(), t2m
122 .getFlags(), t2m.getTarget(), t2m.getTargetInfo());
123 }
124 return response;
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138 String getType1Message(String host, String domain) throws NTLMEngineException {
139 return new Type1Message(domain, host).getResponse();
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162 String getType3Message(String user, String password, String host, String domain,
163 byte[] nonce, int type2Flags, String target, byte[] targetInformation)
164 throws NTLMEngineException {
165 return new Type3Message(domain, host, user, password, nonce, type2Flags, target,
166 targetInformation).getResponse();
167 }
168
169
170
171
172 String getCredentialCharset() {
173 return credentialCharset;
174 }
175
176
177
178
179
180 void setCredentialCharset(String credentialCharset) {
181 this.credentialCharset = credentialCharset;
182 }
183
184
185 private static String stripDotSuffix(String value) {
186 int index = value.indexOf(".");
187 if (index != -1)
188 return value.substring(0, index);
189 return value;
190 }
191
192
193 private static String convertHost(String host) {
194 return stripDotSuffix(host);
195 }
196
197
198 private static String convertDomain(String domain) {
199 return stripDotSuffix(domain);
200 }
201
202 private static int readULong(byte[] src, int index) throws NTLMEngineException {
203 if (src.length < index + 4)
204 throw new NTLMEngineException("NTLM authentication - buffer too small for DWORD");
205 return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8)
206 | ((src[index + 2] & 0xff) << 16) | ((src[index + 3] & 0xff) << 24);
207 }
208
209 private static int readUShort(byte[] src, int index) throws NTLMEngineException {
210 if (src.length < index + 2)
211 throw new NTLMEngineException("NTLM authentication - buffer too small for WORD");
212 return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8);
213 }
214
215 private static byte[] readSecurityBuffer(byte[] src, int index) throws NTLMEngineException {
216 int length = readUShort(src, index);
217 int offset = readULong(src, index + 4);
218 if (src.length < offset + length)
219 throw new NTLMEngineException(
220 "NTLM authentication - buffer too small for data item");
221 byte[] buffer = new byte[length];
222 System.arraycopy(src, offset, buffer, 0, length);
223 return buffer;
224 }
225
226
227 private static byte[] makeRandomChallenge() throws NTLMEngineException {
228 if (RND_GEN == null) {
229 throw new NTLMEngineException("Random generator not available");
230 }
231 byte[] rval = new byte[8];
232 synchronized (RND_GEN) {
233 RND_GEN.nextBytes(rval);
234 }
235 return rval;
236 }
237
238
239 private static byte[] makeSecondaryKey() throws NTLMEngineException {
240 if (RND_GEN == null) {
241 throw new NTLMEngineException("Random generator not available");
242 }
243 byte[] rval = new byte[16];
244 synchronized (RND_GEN) {
245 RND_GEN.nextBytes(rval);
246 }
247 return rval;
248 }
249
250 protected static class CipherGen {
251
252 protected final String domain;
253 protected final String user;
254 protected final String password;
255 protected final byte[] challenge;
256 protected final String target;
257 protected final byte[] targetInformation;
258
259
260 protected byte[] clientChallenge;
261 protected byte[] clientChallenge2;
262 protected byte[] secondaryKey;
263 protected byte[] timestamp;
264
265
266 protected byte[] lmHash = null;
267 protected byte[] lmResponse = null;
268 protected byte[] ntlmHash = null;
269 protected byte[] ntlmResponse = null;
270 protected byte[] ntlmv2Hash = null;
271 protected byte[] lmv2Hash = null;
272 protected byte[] lmv2Response = null;
273 protected byte[] ntlmv2Blob = null;
274 protected byte[] ntlmv2Response = null;
275 protected byte[] ntlm2SessionResponse = null;
276 protected byte[] lm2SessionResponse = null;
277 protected byte[] lmUserSessionKey = null;
278 protected byte[] ntlmUserSessionKey = null;
279 protected byte[] ntlmv2UserSessionKey = null;
280 protected byte[] ntlm2SessionResponseUserSessionKey = null;
281 protected byte[] lanManagerSessionKey = null;
282
283 public CipherGen(String domain, String user, String password,
284 byte[] challenge, String target, byte[] targetInformation,
285 byte[] clientChallenge, byte[] clientChallenge2,
286 byte[] secondaryKey, byte[] timestamp) {
287 this.domain = domain;
288 this.target = target;
289 this.user = user;
290 this.password = password;
291 this.challenge = challenge;
292 this.targetInformation = targetInformation;
293 this.clientChallenge = clientChallenge;
294 this.clientChallenge2 = clientChallenge2;
295 this.secondaryKey = secondaryKey;
296 this.timestamp = timestamp;
297 }
298
299 public CipherGen(String domain, String user, String password,
300 byte[] challenge, String target, byte[] targetInformation) {
301 this(domain, user, password, challenge, target, targetInformation, null, null, null, null);
302 }
303
304
305 public byte[] getClientChallenge()
306 throws NTLMEngineException {
307 if (clientChallenge == null)
308 clientChallenge = makeRandomChallenge();
309 return clientChallenge;
310 }
311
312
313 public byte[] getClientChallenge2()
314 throws NTLMEngineException {
315 if (clientChallenge2 == null)
316 clientChallenge2 = makeRandomChallenge();
317 return clientChallenge2;
318 }
319
320
321 public byte[] getSecondaryKey()
322 throws NTLMEngineException {
323 if (secondaryKey == null)
324 secondaryKey = makeSecondaryKey();
325 return secondaryKey;
326 }
327
328
329 public byte[] getLMHash()
330 throws NTLMEngineException {
331 if (lmHash == null)
332 lmHash = lmHash(password);
333 return lmHash;
334 }
335
336
337 public byte[] getLMResponse()
338 throws NTLMEngineException {
339 if (lmResponse == null)
340 lmResponse = lmResponse(getLMHash(),challenge);
341 return lmResponse;
342 }
343
344
345 public byte[] getNTLMHash()
346 throws NTLMEngineException {
347 if (ntlmHash == null)
348 ntlmHash = ntlmHash(password);
349 return ntlmHash;
350 }
351
352
353 public byte[] getNTLMResponse()
354 throws NTLMEngineException {
355 if (ntlmResponse == null)
356 ntlmResponse = lmResponse(getNTLMHash(),challenge);
357 return ntlmResponse;
358 }
359
360
361 public byte[] getLMv2Hash()
362 throws NTLMEngineException {
363 if (lmv2Hash == null)
364 lmv2Hash = lmv2Hash(domain, user, getNTLMHash());
365 return lmv2Hash;
366 }
367
368
369 public byte[] getNTLMv2Hash()
370 throws NTLMEngineException {
371 if (ntlmv2Hash == null)
372 ntlmv2Hash = ntlmv2Hash(domain, user, getNTLMHash());
373 return ntlmv2Hash;
374 }
375
376
377 public byte[] getTimestamp() {
378 if (timestamp == null) {
379 long time = System.currentTimeMillis();
380 time += 11644473600000l;
381 time *= 10000;
382
383 timestamp = new byte[8];
384 for (int i = 0; i < 8; i++) {
385 timestamp[i] = (byte) time;
386 time >>>= 8;
387 }
388 }
389 return timestamp;
390 }
391
392
393 public byte[] getNTLMv2Blob()
394 throws NTLMEngineException {
395 if (ntlmv2Blob == null)
396 ntlmv2Blob = createBlob(getClientChallenge2(), targetInformation, getTimestamp());
397 return ntlmv2Blob;
398 }
399
400
401 public byte[] getNTLMv2Response()
402 throws NTLMEngineException {
403 if (ntlmv2Response == null)
404 ntlmv2Response = lmv2Response(getNTLMv2Hash(),challenge,getNTLMv2Blob());
405 return ntlmv2Response;
406 }
407
408
409 public byte[] getLMv2Response()
410 throws NTLMEngineException {
411 if (lmv2Response == null)
412 lmv2Response = lmv2Response(getLMv2Hash(),challenge,getClientChallenge());
413 return lmv2Response;
414 }
415
416
417 public byte[] getNTLM2SessionResponse()
418 throws NTLMEngineException {
419 if (ntlm2SessionResponse == null)
420 ntlm2SessionResponse = ntlm2SessionResponse(getNTLMHash(),challenge,getClientChallenge());
421 return ntlm2SessionResponse;
422 }
423
424
425 public byte[] getLM2SessionResponse()
426 throws NTLMEngineException {
427 if (lm2SessionResponse == null) {
428 byte[] clientChallenge = getClientChallenge();
429 lm2SessionResponse = new byte[24];
430 System.arraycopy(clientChallenge, 0, lm2SessionResponse, 0, clientChallenge.length);
431 Arrays.fill(lm2SessionResponse, clientChallenge.length, lm2SessionResponse.length, (byte) 0x00);
432 }
433 return lm2SessionResponse;
434 }
435
436
437 public byte[] getLMUserSessionKey()
438 throws NTLMEngineException {
439 if (lmUserSessionKey == null) {
440 byte[] lmHash = getLMHash();
441 lmUserSessionKey = new byte[16];
442 System.arraycopy(lmHash, 0, lmUserSessionKey, 0, 8);
443 Arrays.fill(lmUserSessionKey, 8, 16, (byte) 0x00);
444 }
445 return lmUserSessionKey;
446 }
447
448
449 public byte[] getNTLMUserSessionKey()
450 throws NTLMEngineException {
451 if (ntlmUserSessionKey == null) {
452 byte[] ntlmHash = getNTLMHash();
453 MD4 md4 = new MD4();
454 md4.update(ntlmHash);
455 ntlmUserSessionKey = md4.getOutput();
456 }
457 return ntlmUserSessionKey;
458 }
459
460
461 public byte[] getNTLMv2UserSessionKey()
462 throws NTLMEngineException {
463 if (ntlmv2UserSessionKey == null) {
464 byte[] ntlmv2hash = getNTLMv2Hash();
465 byte[] truncatedResponse = new byte[16];
466 System.arraycopy(getNTLMv2Response(), 0, truncatedResponse, 0, 16);
467 ntlmv2UserSessionKey = hmacMD5(truncatedResponse, ntlmv2hash);
468 }
469 return ntlmv2UserSessionKey;
470 }
471
472
473 public byte[] getNTLM2SessionResponseUserSessionKey()
474 throws NTLMEngineException {
475 if (ntlm2SessionResponseUserSessionKey == null) {
476 byte[] ntlmUserSessionKey = getNTLMUserSessionKey();
477 byte[] ntlm2SessionResponseNonce = getLM2SessionResponse();
478 byte[] sessionNonce = new byte[challenge.length + ntlm2SessionResponseNonce.length];
479 System.arraycopy(challenge, 0, sessionNonce, 0, challenge.length);
480 System.arraycopy(ntlm2SessionResponseNonce, 0, sessionNonce, challenge.length, ntlm2SessionResponseNonce.length);
481 ntlm2SessionResponseUserSessionKey = hmacMD5(sessionNonce,ntlmUserSessionKey);
482 }
483 return ntlm2SessionResponseUserSessionKey;
484 }
485
486
487 public byte[] getLanManagerSessionKey()
488 throws NTLMEngineException {
489 if (lanManagerSessionKey == null) {
490 byte[] lmHash = getLMHash();
491 byte[] lmResponse = getLMResponse();
492 try {
493 byte[] keyBytes = new byte[14];
494 System.arraycopy(lmHash, 0, keyBytes, 0, 8);
495 Arrays.fill(keyBytes, 8, keyBytes.length, (byte)0xbd);
496 Key lowKey = createDESKey(keyBytes, 0);
497 Key highKey = createDESKey(keyBytes, 7);
498 byte[] truncatedResponse = new byte[8];
499 System.arraycopy(lmResponse, 0, truncatedResponse, 0, truncatedResponse.length);
500 Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
501 des.init(Cipher.ENCRYPT_MODE, lowKey);
502 byte[] lowPart = des.doFinal(truncatedResponse);
503 des = Cipher.getInstance("DES/ECB/NoPadding");
504 des.init(Cipher.ENCRYPT_MODE, highKey);
505 byte[] highPart = des.doFinal(truncatedResponse);
506 lanManagerSessionKey = new byte[16];
507 System.arraycopy(lowPart, 0, lanManagerSessionKey, 0, lowPart.length);
508 System.arraycopy(highPart, 0, lanManagerSessionKey, lowPart.length, highPart.length);
509 } catch (Exception e) {
510 throw new NTLMEngineException(e.getMessage(), e);
511 }
512 }
513 return lanManagerSessionKey;
514 }
515 }
516
517
518 static byte[] hmacMD5(byte[] value, byte[] key)
519 throws NTLMEngineException {
520 HMACMD5 hmacMD5 = new HMACMD5(key);
521 hmacMD5.update(value);
522 return hmacMD5.getOutput();
523 }
524
525
526 static byte[] RC4(byte[] value, byte[] key)
527 throws NTLMEngineException {
528 try {
529 Cipher rc4 = Cipher.getInstance("RC4");
530 rc4.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "RC4"));
531 return rc4.doFinal(value);
532 } catch (Exception e) {
533 throw new NTLMEngineException(e.getMessage(), e);
534 }
535 }
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552 static byte[] ntlm2SessionResponse(byte[] ntlmHash, byte[] challenge,
553 byte[] clientChallenge) throws NTLMEngineException {
554 try {
555
556
557
558
559
560
561
562
563
564
565
566
567
568 MessageDigest md5 = MessageDigest.getInstance("MD5");
569 md5.update(challenge);
570 md5.update(clientChallenge);
571 byte[] digest = md5.digest();
572
573 byte[] sessionHash = new byte[8];
574 System.arraycopy(digest, 0, sessionHash, 0, 8);
575 return lmResponse(ntlmHash, sessionHash);
576 } catch (Exception e) {
577 if (e instanceof NTLMEngineException)
578 throw (NTLMEngineException) e;
579 throw new NTLMEngineException(e.getMessage(), e);
580 }
581 }
582
583
584
585
586
587
588
589
590
591
592 private static byte[] lmHash(String password) throws NTLMEngineException {
593 try {
594 byte[] oemPassword = password.toUpperCase(Locale.US).getBytes("US-ASCII");
595 int length = Math.min(oemPassword.length, 14);
596 byte[] keyBytes = new byte[14];
597 System.arraycopy(oemPassword, 0, keyBytes, 0, length);
598 Key lowKey = createDESKey(keyBytes, 0);
599 Key highKey = createDESKey(keyBytes, 7);
600 byte[] magicConstant = "KGS!@#$%".getBytes("US-ASCII");
601 Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
602 des.init(Cipher.ENCRYPT_MODE, lowKey);
603 byte[] lowHash = des.doFinal(magicConstant);
604 des.init(Cipher.ENCRYPT_MODE, highKey);
605 byte[] highHash = des.doFinal(magicConstant);
606 byte[] lmHash = new byte[16];
607 System.arraycopy(lowHash, 0, lmHash, 0, 8);
608 System.arraycopy(highHash, 0, lmHash, 8, 8);
609 return lmHash;
610 } catch (Exception e) {
611 throw new NTLMEngineException(e.getMessage(), e);
612 }
613 }
614
615
616
617
618
619
620
621
622
623
624 private static byte[] ntlmHash(String password) throws NTLMEngineException {
625 try {
626 byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked");
627 MD4 md4 = new MD4();
628 md4.update(unicodePassword);
629 return md4.getOutput();
630 } catch (java.io.UnsupportedEncodingException e) {
631 throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e);
632 }
633 }
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648 private static byte[] lmv2Hash(String domain, String user, byte[] ntlmHash)
649 throws NTLMEngineException {
650 try {
651 HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
652
653 hmacMD5.update(user.toUpperCase(Locale.US).getBytes("UnicodeLittleUnmarked"));
654 hmacMD5.update(domain.toUpperCase(Locale.US).getBytes("UnicodeLittleUnmarked"));
655 return hmacMD5.getOutput();
656 } catch (java.io.UnsupportedEncodingException e) {
657 throw new NTLMEngineException("Unicode not supported! " + e.getMessage(), e);
658 }
659 }
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674 private static byte[] ntlmv2Hash(String domain, String user, byte[] ntlmHash)
675 throws NTLMEngineException {
676 try {
677 HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
678
679 hmacMD5.update(user.toUpperCase(Locale.US).getBytes("UnicodeLittleUnmarked"));
680 hmacMD5.update(domain.getBytes("UnicodeLittleUnmarked"));
681 return hmacMD5.getOutput();
682 } catch (java.io.UnsupportedEncodingException e) {
683 throw new NTLMEngineException("Unicode not supported! " + e.getMessage(), e);
684 }
685 }
686
687
688
689
690
691
692
693
694
695
696
697 private static byte[] lmResponse(byte[] hash, byte[] challenge) throws NTLMEngineException {
698 try {
699 byte[] keyBytes = new byte[21];
700 System.arraycopy(hash, 0, keyBytes, 0, 16);
701 Key lowKey = createDESKey(keyBytes, 0);
702 Key middleKey = createDESKey(keyBytes, 7);
703 Key highKey = createDESKey(keyBytes, 14);
704 Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
705 des.init(Cipher.ENCRYPT_MODE, lowKey);
706 byte[] lowResponse = des.doFinal(challenge);
707 des.init(Cipher.ENCRYPT_MODE, middleKey);
708 byte[] middleResponse = des.doFinal(challenge);
709 des.init(Cipher.ENCRYPT_MODE, highKey);
710 byte[] highResponse = des.doFinal(challenge);
711 byte[] lmResponse = new byte[24];
712 System.arraycopy(lowResponse, 0, lmResponse, 0, 8);
713 System.arraycopy(middleResponse, 0, lmResponse, 8, 8);
714 System.arraycopy(highResponse, 0, lmResponse, 16, 8);
715 return lmResponse;
716 } catch (Exception e) {
717 throw new NTLMEngineException(e.getMessage(), e);
718 }
719 }
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735 private static byte[] lmv2Response(byte[] hash, byte[] challenge, byte[] clientData)
736 throws NTLMEngineException {
737 HMACMD5 hmacMD5 = new HMACMD5(hash);
738 hmacMD5.update(challenge);
739 hmacMD5.update(clientData);
740 byte[] mac = hmacMD5.getOutput();
741 byte[] lmv2Response = new byte[mac.length + clientData.length];
742 System.arraycopy(mac, 0, lmv2Response, 0, mac.length);
743 System.arraycopy(clientData, 0, lmv2Response, mac.length, clientData.length);
744 return lmv2Response;
745 }
746
747
748
749
750
751
752
753
754
755
756
757
758 private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformation, byte[] timestamp) {
759 byte[] blobSignature = new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00 };
760 byte[] reserved = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
761 byte[] unknown1 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
762 byte[] unknown2 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
763 byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8
764 + unknown1.length + targetInformation.length + unknown2.length];
765 int offset = 0;
766 System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length);
767 offset += blobSignature.length;
768 System.arraycopy(reserved, 0, blob, offset, reserved.length);
769 offset += reserved.length;
770 System.arraycopy(timestamp, 0, blob, offset, timestamp.length);
771 offset += timestamp.length;
772 System.arraycopy(clientChallenge, 0, blob, offset, 8);
773 offset += 8;
774 System.arraycopy(unknown1, 0, blob, offset, unknown1.length);
775 offset += unknown1.length;
776 System.arraycopy(targetInformation, 0, blob, offset, targetInformation.length);
777 offset += targetInformation.length;
778 System.arraycopy(unknown2, 0, blob, offset, unknown2.length);
779 offset += unknown2.length;
780 return blob;
781 }
782
783
784
785
786
787
788
789
790
791
792
793
794
795 private static Key createDESKey(byte[] bytes, int offset) {
796 byte[] keyBytes = new byte[7];
797 System.arraycopy(bytes, offset, keyBytes, 0, 7);
798 byte[] material = new byte[8];
799 material[0] = keyBytes[0];
800 material[1] = (byte) (keyBytes[0] << 7 | (keyBytes[1] & 0xff) >>> 1);
801 material[2] = (byte) (keyBytes[1] << 6 | (keyBytes[2] & 0xff) >>> 2);
802 material[3] = (byte) (keyBytes[2] << 5 | (keyBytes[3] & 0xff) >>> 3);
803 material[4] = (byte) (keyBytes[3] << 4 | (keyBytes[4] & 0xff) >>> 4);
804 material[5] = (byte) (keyBytes[4] << 3 | (keyBytes[5] & 0xff) >>> 5);
805 material[6] = (byte) (keyBytes[5] << 2 | (keyBytes[6] & 0xff) >>> 6);
806 material[7] = (byte) (keyBytes[6] << 1);
807 oddParity(material);
808 return new SecretKeySpec(material, "DES");
809 }
810
811
812
813
814
815
816
817 private static void oddParity(byte[] bytes) {
818 for (int i = 0; i < bytes.length; i++) {
819 byte b = bytes[i];
820 boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3)
821 ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0;
822 if (needsParity) {
823 bytes[i] |= (byte) 0x01;
824 } else {
825 bytes[i] &= (byte) 0xfe;
826 }
827 }
828 }
829
830
831 static class NTLMMessage {
832
833 private byte[] messageContents = null;
834
835
836 private int currentOutputPosition = 0;
837
838
839 NTLMMessage() {
840 }
841
842
843 NTLMMessage(String messageBody, int expectedType) throws NTLMEngineException {
844 messageContents = Base64.decodeBase64(EncodingUtils.getBytes(messageBody,
845 DEFAULT_CHARSET));
846
847 if (messageContents.length < SIGNATURE.length)
848 throw new NTLMEngineException("NTLM message decoding error - packet too short");
849 int i = 0;
850 while (i < SIGNATURE.length) {
851 if (messageContents[i] != SIGNATURE[i])
852 throw new NTLMEngineException(
853 "NTLM message expected - instead got unrecognized bytes");
854 i++;
855 }
856
857
858 int type = readULong(SIGNATURE.length);
859 if (type != expectedType)
860 throw new NTLMEngineException("NTLM type " + Integer.toString(expectedType)
861 + " message expected - instead got type " + Integer.toString(type));
862
863 currentOutputPosition = messageContents.length;
864 }
865
866
867
868
869
870 protected int getPreambleLength() {
871 return SIGNATURE.length + 4;
872 }
873
874
875 protected int getMessageLength() {
876 return currentOutputPosition;
877 }
878
879
880 protected byte readByte(int position) throws NTLMEngineException {
881 if (messageContents.length < position + 1)
882 throw new NTLMEngineException("NTLM: Message too short");
883 return messageContents[position];
884 }
885
886
887 protected void readBytes(byte[] buffer, int position) throws NTLMEngineException {
888 if (messageContents.length < position + buffer.length)
889 throw new NTLMEngineException("NTLM: Message too short");
890 System.arraycopy(messageContents, position, buffer, 0, buffer.length);
891 }
892
893
894 protected int readUShort(int position) throws NTLMEngineException {
895 return NTLMEngineImpl.readUShort(messageContents, position);
896 }
897
898
899 protected int readULong(int position) throws NTLMEngineException {
900 return NTLMEngineImpl.readULong(messageContents, position);
901 }
902
903
904 protected byte[] readSecurityBuffer(int position) throws NTLMEngineException {
905 return NTLMEngineImpl.readSecurityBuffer(messageContents, position);
906 }
907
908
909
910
911
912
913
914
915
916 protected void prepareResponse(int maxlength, int messageType) {
917 messageContents = new byte[maxlength];
918 currentOutputPosition = 0;
919 addBytes(SIGNATURE);
920 addULong(messageType);
921 }
922
923
924
925
926
927
928
929 protected void addByte(byte b) {
930 messageContents[currentOutputPosition] = b;
931 currentOutputPosition++;
932 }
933
934
935
936
937
938
939
940 protected void addBytes(byte[] bytes) {
941 for (byte b : bytes) {
942 messageContents[currentOutputPosition] = b;
943 currentOutputPosition++;
944 }
945 }
946
947
948 protected void addUShort(int value) {
949 addByte((byte) (value & 0xff));
950 addByte((byte) (value >> 8 & 0xff));
951 }
952
953
954 protected void addULong(int value) {
955 addByte((byte) (value & 0xff));
956 addByte((byte) (value >> 8 & 0xff));
957 addByte((byte) (value >> 16 & 0xff));
958 addByte((byte) (value >> 24 & 0xff));
959 }
960
961
962
963
964
965
966
967 String getResponse() {
968 byte[] resp;
969 if (messageContents.length > currentOutputPosition) {
970 byte[] tmp = new byte[currentOutputPosition];
971 for (int i = 0; i < currentOutputPosition; i++) {
972 tmp[i] = messageContents[i];
973 }
974 resp = tmp;
975 } else {
976 resp = messageContents;
977 }
978 return EncodingUtils.getAsciiString(Base64.encodeBase64(resp));
979 }
980
981 }
982
983
984 static class Type1Message extends NTLMMessage {
985 protected byte[] hostBytes;
986 protected byte[] domainBytes;
987
988
989 Type1Message(String domain, String host) throws NTLMEngineException {
990 super();
991 try {
992
993 String unqualifiedHost = convertHost(host);
994
995 String unqualifiedDomain = convertDomain(domain);
996
997 hostBytes = unqualifiedHost.getBytes("ASCII");
998 domainBytes = unqualifiedDomain.toUpperCase(Locale.US).getBytes("ASCII");
999 } catch (java.io.UnsupportedEncodingException e) {
1000 throw new NTLMEngineException("Unicode unsupported: " + e.getMessage(), e);
1001 }
1002 }
1003
1004
1005
1006
1007
1008 @Override
1009 String getResponse() {
1010
1011
1012 int finalLength = 32 + 8
1013
1014
1015
1016 prepareResponse(finalLength, 1);
1017
1018
1019 addULong(
1020
1021
1022
1023
1024
1025 FLAG_REQUEST_NTLMv1 |
1026 FLAG_REQUEST_NTLM2_SESSION |
1027
1028
1029 FLAG_REQUEST_VERSION |
1030
1031
1032 FLAG_REQUEST_ALWAYS_SIGN |
1033
1034
1035
1036
1037 FLAG_REQUEST_128BIT_KEY_EXCH |
1038 FLAG_REQUEST_56BIT_ENCRYPTION |
1039
1040
1041 FLAG_REQUEST_UNICODE_ENCODING);
1042
1043
1044 addUShort(
1045 addUShort(
1046
1047
1048 addULong(
1049
1050
1051 addUShort(
1052 addUShort(
1053
1054
1055 addULong(32 + 8);
1056
1057
1058 addUShort(0x0105);
1059
1060 addULong(2600);
1061
1062 addUShort(0x0f00);
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072 return super.getResponse();
1073 }
1074
1075 }
1076
1077
1078 static class Type2Message extends NTLMMessage {
1079 protected byte[] challenge;
1080 protected String target;
1081 protected byte[] targetInfo;
1082 protected int flags;
1083
1084 Type2Message(String message) throws NTLMEngineException {
1085 super(message, 2);
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102 challenge = new byte[8];
1103 readBytes(challenge, 24);
1104
1105 flags = readULong(20);
1106
1107 if ((flags & FLAG_REQUEST_UNICODE_ENCODING) == 0)
1108 throw new NTLMEngineException(
1109 "NTLM type 2 message has flags that make no sense: "
1110 + Integer.toString(flags));
1111
1112
1113 target = null;
1114
1115
1116
1117 if (getMessageLength() >= 12 + 8) {
1118 byte[] bytes = readSecurityBuffer(12);
1119 if (bytes.length != 0) {
1120 try {
1121 target = new String(bytes, "UnicodeLittleUnmarked");
1122 } catch (java.io.UnsupportedEncodingException e) {
1123 throw new NTLMEngineException(e.getMessage(), e);
1124 }
1125 }
1126 }
1127
1128
1129 targetInfo = null;
1130
1131 if (getMessageLength() >= 40 + 8) {
1132 byte[] bytes = readSecurityBuffer(40);
1133 if (bytes.length != 0) {
1134 targetInfo = bytes;
1135 }
1136 }
1137 }
1138
1139
1140 byte[] getChallenge() {
1141 return challenge;
1142 }
1143
1144
1145 String getTarget() {
1146 return target;
1147 }
1148
1149
1150 byte[] getTargetInfo() {
1151 return targetInfo;
1152 }
1153
1154
1155 int getFlags() {
1156 return flags;
1157 }
1158
1159 }
1160
1161
1162 static class Type3Message extends NTLMMessage {
1163
1164 protected int type2Flags;
1165
1166 protected byte[] domainBytes;
1167 protected byte[] hostBytes;
1168 protected byte[] userBytes;
1169
1170 protected byte[] lmResp;
1171 protected byte[] ntResp;
1172 protected byte[] sessionKey;
1173
1174
1175
1176 Type3Message(String domain, String host, String user, String password, byte[] nonce,
1177 int type2Flags, String target, byte[] targetInformation)
1178 throws NTLMEngineException {
1179
1180 this.type2Flags = type2Flags;
1181
1182
1183 String unqualifiedHost = convertHost(host);
1184
1185 String unqualifiedDomain = convertDomain(domain);
1186
1187
1188 CipherGen gen = new CipherGen(unqualifiedDomain, user, password, nonce, target, targetInformation);
1189
1190
1191
1192 byte[] userSessionKey;
1193 try {
1194
1195
1196 if (((type2Flags & FLAG_TARGETINFO_PRESENT) != 0) &&
1197 targetInformation != null && target != null) {
1198
1199 ntResp = gen.getNTLMv2Response();
1200 lmResp = gen.getLMv2Response();
1201 if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0)
1202 userSessionKey = gen.getLanManagerSessionKey();
1203 else
1204 userSessionKey = gen.getNTLMv2UserSessionKey();
1205 } else {
1206
1207 if ((type2Flags & FLAG_REQUEST_NTLM2_SESSION) != 0) {
1208
1209 ntResp = gen.getNTLM2SessionResponse();
1210 lmResp = gen.getLM2SessionResponse();
1211 if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0)
1212 userSessionKey = gen.getLanManagerSessionKey();
1213 else
1214 userSessionKey = gen.getNTLM2SessionResponseUserSessionKey();
1215 } else {
1216 ntResp = gen.getNTLMResponse();
1217 lmResp = gen.getLMResponse();
1218 if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0)
1219 userSessionKey = gen.getLanManagerSessionKey();
1220 else
1221 userSessionKey = gen.getNTLMUserSessionKey();
1222 }
1223 }
1224 } catch (NTLMEngineException e) {
1225
1226
1227 ntResp = new byte[0];
1228 lmResp = gen.getLMResponse();
1229 if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0)
1230 userSessionKey = gen.getLanManagerSessionKey();
1231 else
1232 userSessionKey = gen.getLMUserSessionKey();
1233 }
1234
1235 if ((type2Flags & FLAG_REQUEST_SIGN) != 0) {
1236 if ((type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) != 0)
1237 sessionKey = RC4(gen.getSecondaryKey(), userSessionKey);
1238 else
1239 sessionKey = userSessionKey;
1240 } else {
1241 sessionKey = null;
1242 }
1243
1244 try {
1245 domainBytes = unqualifiedDomain.toUpperCase(Locale.US).getBytes("UnicodeLittleUnmarked");
1246 hostBytes = unqualifiedHost.getBytes("UnicodeLittleUnmarked");
1247 userBytes = user.getBytes("UnicodeLittleUnmarked");
1248 } catch (java.io.UnsupportedEncodingException e) {
1249 throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e);
1250 }
1251 }
1252
1253
1254 @Override
1255 String getResponse() {
1256 int ntRespLen = ntResp.length;
1257 int lmRespLen = lmResp.length;
1258
1259 int domainLen = domainBytes.length;
1260 int hostLen = hostBytes.length;
1261 int userLen = userBytes.length;
1262 int sessionKeyLen;
1263 if (sessionKey != null)
1264 sessionKeyLen = sessionKey.length;
1265 else
1266 sessionKeyLen = 0;
1267
1268
1269 int lmRespOffset = 72;
1270 int ntRespOffset = lmRespOffset + lmRespLen;
1271 int domainOffset = ntRespOffset + ntRespLen;
1272 int userOffset = domainOffset + domainLen;
1273 int hostOffset = userOffset + userLen;
1274 int sessionKeyOffset = hostOffset + hostLen;
1275 int finalLength = sessionKeyOffset + sessionKeyLen;
1276
1277
1278 prepareResponse(finalLength, 3);
1279
1280
1281 addUShort(lmRespLen);
1282 addUShort(lmRespLen);
1283
1284
1285 addULong(lmRespOffset);
1286
1287
1288 addUShort(ntRespLen);
1289 addUShort(ntRespLen);
1290
1291
1292 addULong(ntRespOffset);
1293
1294
1295 addUShort(domainLen);
1296 addUShort(domainLen);
1297
1298
1299 addULong(domainOffset);
1300
1301
1302 addUShort(userLen);
1303 addUShort(userLen);
1304
1305
1306 addULong(userOffset);
1307
1308
1309 addUShort(hostLen);
1310 addUShort(hostLen);
1311
1312
1313 addULong(hostOffset);
1314
1315
1316 addUShort(sessionKeyLen);
1317 addUShort(sessionKeyLen);
1318
1319
1320 addULong(sessionKeyOffset);
1321
1322
1323 addULong(
1324
1325
1326
1327
1328 (type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) |
1329 (type2Flags & FLAG_REQUEST_NTLMv1) |
1330 (type2Flags & FLAG_REQUEST_NTLM2_SESSION) |
1331
1332
1333 FLAG_REQUEST_VERSION |
1334
1335
1336 (type2Flags & FLAG_REQUEST_ALWAYS_SIGN) |
1337 (type2Flags & FLAG_REQUEST_SEAL) |
1338 (type2Flags & FLAG_REQUEST_SIGN) |
1339
1340
1341 (type2Flags & FLAG_REQUEST_128BIT_KEY_EXCH) |
1342 (type2Flags & FLAG_REQUEST_56BIT_ENCRYPTION) |
1343 (type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) |
1344
1345 (type2Flags & FLAG_TARGETINFO_PRESENT) |
1346 (type2Flags & FLAG_REQUEST_UNICODE_ENCODING) |
1347 (type2Flags & FLAG_REQUEST_TARGET)
1348 );
1349
1350
1351 addUShort(0x0105);
1352
1353 addULong(2600);
1354
1355 addUShort(0x0f00);
1356
1357
1358 addBytes(lmResp);
1359 addBytes(ntResp);
1360 addBytes(domainBytes);
1361 addBytes(userBytes);
1362 addBytes(hostBytes);
1363 if (sessionKey != null)
1364 addBytes(sessionKey);
1365
1366 return super.getResponse();
1367 }
1368 }
1369
1370 static void writeULong(byte[] buffer, int value, int offset) {
1371 buffer[offset] = (byte) (value & 0xff);
1372 buffer[offset + 1] = (byte) (value >> 8 & 0xff);
1373 buffer[offset + 2] = (byte) (value >> 16 & 0xff);
1374 buffer[offset + 3] = (byte) (value >> 24 & 0xff);
1375 }
1376
1377 static int F(int x, int y, int z) {
1378 return ((x & y) | (~x & z));
1379 }
1380
1381 static int G(int x, int y, int z) {
1382 return ((x & y) | (x & z) | (y & z));
1383 }
1384
1385 static int H(int x, int y, int z) {
1386 return (x ^ y ^ z);
1387 }
1388
1389 static int rotintlft(int val, int numbits) {
1390 return ((val << numbits) | (val >>> (32 - numbits)));
1391 }
1392
1393
1394
1395
1396
1397
1398
1399
1400 static class MD4 {
1401 protected int A = 0x67452301;
1402 protected int B = 0xefcdab89;
1403 protected int C = 0x98badcfe;
1404 protected int D = 0x10325476;
1405 protected long count = 0L;
1406 protected byte[] dataBuffer = new byte[64];
1407
1408 MD4() {
1409 }
1410
1411 void update(byte[] input) {
1412
1413
1414
1415 int curBufferPos = (int) (count & 63L);
1416 int inputIndex = 0;
1417 while (input.length - inputIndex + curBufferPos >= dataBuffer.length) {
1418
1419
1420
1421 int transferAmt = dataBuffer.length - curBufferPos;
1422 System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt);
1423 count += transferAmt;
1424 curBufferPos = 0;
1425 inputIndex += transferAmt;
1426 processBuffer();
1427 }
1428
1429
1430
1431 if (inputIndex < input.length) {
1432 int transferAmt = input.length - inputIndex;
1433 System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt);
1434 count += transferAmt;
1435 curBufferPos += transferAmt;
1436 }
1437 }
1438
1439 byte[] getOutput() {
1440
1441
1442 int bufferIndex = (int) (count & 63L);
1443 int padLen = (bufferIndex < 56) ? (56 - bufferIndex) : (120 - bufferIndex);
1444 byte[] postBytes = new byte[padLen + 8];
1445
1446
1447 postBytes[0] = (byte) 0x80;
1448
1449 for (int i = 0; i < 8; i++) {
1450 postBytes[padLen + i] = (byte) ((count * 8) >>> (8 * i));
1451 }
1452
1453
1454 update(postBytes);
1455
1456
1457 byte[] result = new byte[16];
1458 writeULong(result, A, 0);
1459 writeULong(result, B, 4);
1460 writeULong(result, C, 8);
1461 writeULong(result, D, 12);
1462 return result;
1463 }
1464
1465 protected void processBuffer() {
1466
1467 int[] d = new int[16];
1468
1469 for (int i = 0; i < 16; i++) {
1470 d[i] = (dataBuffer[i * 4] & 0xff) + ((dataBuffer[i * 4 + 1] & 0xff) << 8)
1471 + ((dataBuffer[i * 4 + 2] & 0xff) << 16)
1472 + ((dataBuffer[i * 4 + 3] & 0xff) << 24);
1473 }
1474
1475
1476 int AA = A;
1477 int BB = B;
1478 int CC = C;
1479 int DD = D;
1480 round1(d);
1481 round2(d);
1482 round3(d);
1483 A += AA;
1484 B += BB;
1485 C += CC;
1486 D += DD;
1487
1488 }
1489
1490 protected void round1(int[] d) {
1491 A = rotintlft((A + F(B, C, D) + d[0]), 3);
1492 D = rotintlft((D + F(A, B, C) + d[1]), 7);
1493 C = rotintlft((C + F(D, A, B) + d[2]), 11);
1494 B = rotintlft((B + F(C, D, A) + d[3]), 19);
1495
1496 A = rotintlft((A + F(B, C, D) + d[4]), 3);
1497 D = rotintlft((D + F(A, B, C) + d[5]), 7);
1498 C = rotintlft((C + F(D, A, B) + d[6]), 11);
1499 B = rotintlft((B + F(C, D, A) + d[7]), 19);
1500
1501 A = rotintlft((A + F(B, C, D) + d[8]), 3);
1502 D = rotintlft((D + F(A, B, C) + d[9]), 7);
1503 C = rotintlft((C + F(D, A, B) + d[10]), 11);
1504 B = rotintlft((B + F(C, D, A) + d[11]), 19);
1505
1506 A = rotintlft((A + F(B, C, D) + d[12]), 3);
1507 D = rotintlft((D + F(A, B, C) + d[13]), 7);
1508 C = rotintlft((C + F(D, A, B) + d[14]), 11);
1509 B = rotintlft((B + F(C, D, A) + d[15]), 19);
1510 }
1511
1512 protected void round2(int[] d) {
1513 A = rotintlft((A + G(B, C, D) + d[0] + 0x5a827999), 3);
1514 D = rotintlft((D + G(A, B, C) + d[4] + 0x5a827999), 5);
1515 C = rotintlft((C + G(D, A, B) + d[8] + 0x5a827999), 9);
1516 B = rotintlft((B + G(C, D, A) + d[12] + 0x5a827999), 13);
1517
1518 A = rotintlft((A + G(B, C, D) + d[1] + 0x5a827999), 3);
1519 D = rotintlft((D + G(A, B, C) + d[5] + 0x5a827999), 5);
1520 C = rotintlft((C + G(D, A, B) + d[9] + 0x5a827999), 9);
1521 B = rotintlft((B + G(C, D, A) + d[13] + 0x5a827999), 13);
1522
1523 A = rotintlft((A + G(B, C, D) + d[2] + 0x5a827999), 3);
1524 D = rotintlft((D + G(A, B, C) + d[6] + 0x5a827999), 5);
1525 C = rotintlft((C + G(D, A, B) + d[10] + 0x5a827999), 9);
1526 B = rotintlft((B + G(C, D, A) + d[14] + 0x5a827999), 13);
1527
1528 A = rotintlft((A + G(B, C, D) + d[3] + 0x5a827999), 3);
1529 D = rotintlft((D + G(A, B, C) + d[7] + 0x5a827999), 5);
1530 C = rotintlft((C + G(D, A, B) + d[11] + 0x5a827999), 9);
1531 B = rotintlft((B + G(C, D, A) + d[15] + 0x5a827999), 13);
1532
1533 }
1534
1535 protected void round3(int[] d) {
1536 A = rotintlft((A + H(B, C, D) + d[0] + 0x6ed9eba1), 3);
1537 D = rotintlft((D + H(A, B, C) + d[8] + 0x6ed9eba1), 9);
1538 C = rotintlft((C + H(D, A, B) + d[4] + 0x6ed9eba1), 11);
1539 B = rotintlft((B + H(C, D, A) + d[12] + 0x6ed9eba1), 15);
1540
1541 A = rotintlft((A + H(B, C, D) + d[2] + 0x6ed9eba1), 3);
1542 D = rotintlft((D + H(A, B, C) + d[10] + 0x6ed9eba1), 9);
1543 C = rotintlft((C + H(D, A, B) + d[6] + 0x6ed9eba1), 11);
1544 B = rotintlft((B + H(C, D, A) + d[14] + 0x6ed9eba1), 15);
1545
1546 A = rotintlft((A + H(B, C, D) + d[1] + 0x6ed9eba1), 3);
1547 D = rotintlft((D + H(A, B, C) + d[9] + 0x6ed9eba1), 9);
1548 C = rotintlft((C + H(D, A, B) + d[5] + 0x6ed9eba1), 11);
1549 B = rotintlft((B + H(C, D, A) + d[13] + 0x6ed9eba1), 15);
1550
1551 A = rotintlft((A + H(B, C, D) + d[3] + 0x6ed9eba1), 3);
1552 D = rotintlft((D + H(A, B, C) + d[11] + 0x6ed9eba1), 9);
1553 C = rotintlft((C + H(D, A, B) + d[7] + 0x6ed9eba1), 11);
1554 B = rotintlft((B + H(C, D, A) + d[15] + 0x6ed9eba1), 15);
1555
1556 }
1557
1558 }
1559
1560
1561
1562
1563
1564 static class HMACMD5 {
1565 protected byte[] ipad;
1566 protected byte[] opad;
1567 protected MessageDigest md5;
1568
1569 HMACMD5(byte[] key) throws NTLMEngineException {
1570 try {
1571 md5 = MessageDigest.getInstance("MD5");
1572 } catch (Exception ex) {
1573
1574
1575 throw new NTLMEngineException(
1576 "Error getting md5 message digest implementation: " + ex.getMessage(), ex);
1577 }
1578
1579
1580 ipad = new byte[64];
1581 opad = new byte[64];
1582
1583 int keyLength = key.length;
1584 if (keyLength > 64) {
1585
1586 md5.update(key);
1587 key = md5.digest();
1588 keyLength = key.length;
1589 }
1590 int i = 0;
1591 while (i < keyLength) {
1592 ipad[i] = (byte) (key[i] ^ (byte) 0x36);
1593 opad[i] = (byte) (key[i] ^ (byte) 0x5c);
1594 i++;
1595 }
1596 while (i < 64) {
1597 ipad[i] = (byte) 0x36;
1598 opad[i] = (byte) 0x5c;
1599 i++;
1600 }
1601
1602
1603 md5.reset();
1604 md5.update(ipad);
1605
1606 }
1607
1608
1609 byte[] getOutput() {
1610 byte[] digest = md5.digest();
1611 md5.update(opad);
1612 return md5.digest(digest);
1613 }
1614
1615
1616 void update(byte[] input) {
1617 md5.update(input);
1618 }
1619
1620
1621 void update(byte[] input, int offset, int length) {
1622 md5.update(input, offset, length);
1623 }
1624
1625 }
1626
1627 public String generateType1Msg(
1628 final String domain,
1629 final String workstation) throws NTLMEngineException {
1630 return getType1Message(workstation, domain);
1631 }
1632
1633 public String generateType3Msg(
1634 final String username,
1635 final String password,
1636 final String domain,
1637 final String workstation,
1638 final String challenge) throws NTLMEngineException {
1639 Type2Message t2m = new Type2Message(challenge);
1640 return getType3Message(
1641 username,
1642 password,
1643 workstation,
1644 domain,
1645 t2m.getChallenge(),
1646 t2m.getFlags(),
1647 t2m.getTarget(),
1648 t2m.getTargetInfo());
1649 }
1650
1651 }