View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.http.impl.auth;
28  
29  import java.io.UnsupportedEncodingException;
30  import java.nio.charset.Charset;
31  import java.security.Key;
32  import java.security.MessageDigest;
33  import java.util.Arrays;
34  import java.util.Locale;
35  
36  import javax.crypto.Cipher;
37  import javax.crypto.spec.SecretKeySpec;
38  
39  import org.apache.commons.codec.binary.Base64;
40  import org.apache.http.Consts;
41  import org.apache.http.annotation.NotThreadSafe;
42  import org.apache.http.util.CharsetUtils;
43  import org.apache.http.util.EncodingUtils;
44  
45  /**
46   * Provides an implementation for NTLMv1, NTLMv2, and NTLM2 Session forms of the NTLM
47   * authentication protocol.
48   *
49   * @since 4.1
50   */
51  @NotThreadSafe
52  final class NTLMEngineImpl implements NTLMEngine {
53  
54      /** Unicode encoding */
55      private static final Charset UNICODE_LITTLE_UNMARKED = CharsetUtils.lookup("UnicodeLittleUnmarked");
56      /** Character encoding */
57      private static final Charset DEFAULT_CHARSET = Consts.ASCII;
58  
59      // Flags we use; descriptions according to:
60      // http://davenport.sourceforge.net/ntlm.html
61      // and
62      // http://msdn.microsoft.com/en-us/library/cc236650%28v=prot.20%29.aspx
63      protected static final int FLAG_REQUEST_UNICODE_ENCODING = 0x00000001;      // Unicode string encoding requested
64      protected static final int FLAG_REQUEST_TARGET = 0x00000004;                      // Requests target field
65      protected static final int FLAG_REQUEST_SIGN = 0x00000010;  // Requests all messages have a signature attached, in NEGOTIATE message.
66      protected static final int FLAG_REQUEST_SEAL = 0x00000020;  // Request key exchange for message confidentiality in NEGOTIATE message.  MUST be used in conjunction with 56BIT.
67      protected static final int FLAG_REQUEST_LAN_MANAGER_KEY = 0x00000080;    // Request Lan Manager key instead of user session key
68      protected static final int FLAG_REQUEST_NTLMv1 = 0x00000200; // Request NTLMv1 security.  MUST be set in NEGOTIATE and CHALLENGE both
69      protected static final int FLAG_DOMAIN_PRESENT = 0x00001000;        // Domain is present in message
70      protected static final int FLAG_WORKSTATION_PRESENT = 0x00002000;   // Workstation is present in message
71      protected static final int FLAG_REQUEST_ALWAYS_SIGN = 0x00008000;   // Requests a signature block on all messages.  Overridden by REQUEST_SIGN and REQUEST_SEAL.
72      protected static final int FLAG_REQUEST_NTLM2_SESSION = 0x00080000; // From server in challenge, requesting NTLM2 session security
73      protected static final int FLAG_REQUEST_VERSION = 0x02000000;       // Request protocol version
74      protected static final int FLAG_TARGETINFO_PRESENT = 0x00800000;    // From server in challenge message, indicating targetinfo is present
75      protected static final int FLAG_REQUEST_128BIT_KEY_EXCH = 0x20000000; // Request explicit 128-bit key exchange
76      protected static final int FLAG_REQUEST_EXPLICIT_KEY_EXCH = 0x40000000;     // Request explicit key exchange
77      protected static final int FLAG_REQUEST_56BIT_ENCRYPTION = 0x80000000;      // Must be used in conjunction with SEAL
78  
79  
80      /** Secure random generator */
81      private static final java.security.SecureRandom RND_GEN;
82      static {
83          java.security.SecureRandom rnd = null;
84          try {
85              rnd = java.security.SecureRandom.getInstance("SHA1PRNG");
86          } catch (final Exception ignore) {
87          }
88          RND_GEN = rnd;
89      }
90  
91      /** The signature string as bytes in the default encoding */
92      private static final byte[] SIGNATURE;
93  
94      static {
95          final byte[] bytesWithoutNull = "NTLMSSP".getBytes(Consts.ASCII);
96          SIGNATURE = new byte[bytesWithoutNull.length + 1];
97          System.arraycopy(bytesWithoutNull, 0, SIGNATURE, 0, bytesWithoutNull.length);
98          SIGNATURE[bytesWithoutNull.length] = (byte) 0x00;
99      }
100 
101     private static final Type1Message TYPE_1_MESSAGE = new Type1Message();
102 
103     /**
104      * Returns the response for the given message.
105      *
106      * @param message
107      *            the message that was received from the server.
108      * @param username
109      *            the username to authenticate with.
110      * @param password
111      *            the password to authenticate with.
112      * @param host
113      *            The host.
114      * @param domain
115      *            the NT domain to authenticate in.
116      * @return The response.
117      * @throws org.apache.http.HttpException
118      *             If the messages cannot be retrieved.
119      */
120     static String getResponseFor(final String message, final String username, final String password,
121             final String host, final String domain) throws NTLMEngineException {
122 
123         final String response;
124         if (message == null || message.trim().equals("")) {
125             response = getType1Message(host, domain);
126         } else {
127             final Type2Message t2m = new Type2Message(message);
128             response = getType3Message(username, password, host, domain, t2m.getChallenge(), t2m
129                     .getFlags(), t2m.getTarget(), t2m.getTargetInfo());
130         }
131         return response;
132     }
133 
134     /**
135      * Creates the first message (type 1 message) in the NTLM authentication
136      * sequence. This message includes the user name, domain and host for the
137      * authentication session.
138      *
139      * @param host
140      *            the computer name of the host requesting authentication.
141      * @param domain
142      *            The domain to authenticate with.
143      * @return String the message to add to the HTTP request header.
144      */
145     static String getType1Message(final String host, final String domain) throws NTLMEngineException {
146         // For compatibility reason do not include domain and host in type 1 message
147         //return new Type1Message(domain, host).getResponse();
148         return TYPE_1_MESSAGE.getResponse();
149     }
150 
151     /**
152      * Creates the type 3 message using the given server nonce. The type 3
153      * message includes all the information for authentication, host, domain,
154      * username and the result of encrypting the nonce sent by the server using
155      * the user's password as the key.
156      *
157      * @param user
158      *            The user name. This should not include the domain name.
159      * @param password
160      *            The password.
161      * @param host
162      *            The host that is originating the authentication request.
163      * @param domain
164      *            The domain to authenticate within.
165      * @param nonce
166      *            the 8 byte array the server sent.
167      * @return The type 3 message.
168      * @throws NTLMEngineException
169      *             If {@encrypt(byte[],byte[])} fails.
170      */
171     static String getType3Message(final String user, final String password, final String host, final String domain,
172             final byte[] nonce, final int type2Flags, final String target, final byte[] targetInformation)
173             throws NTLMEngineException {
174         return new Type3Message(domain, host, user, password, nonce, type2Flags, target,
175                 targetInformation).getResponse();
176     }
177 
178     /** Strip dot suffix from a name */
179     private static String stripDotSuffix(final String value) {
180         if (value == null) {
181             return null;
182         }
183         final int index = value.indexOf(".");
184         if (index != -1) {
185             return value.substring(0, index);
186         }
187         return value;
188     }
189 
190     /** Convert host to standard form */
191     private static String convertHost(final String host) {
192         return stripDotSuffix(host);
193     }
194 
195     /** Convert domain to standard form */
196     private static String convertDomain(final String domain) {
197         return stripDotSuffix(domain);
198     }
199 
200     private static int readULong(final byte[] src, final int index) throws NTLMEngineException {
201         if (src.length < index + 4) {
202             throw new NTLMEngineException("NTLM authentication - buffer too small for DWORD");
203         }
204         return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8)
205                 | ((src[index + 2] & 0xff) << 16) | ((src[index + 3] & 0xff) << 24);
206     }
207 
208     private static int readUShort(final byte[] src, final int index) throws NTLMEngineException {
209         if (src.length < index + 2) {
210             throw new NTLMEngineException("NTLM authentication - buffer too small for WORD");
211         }
212         return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8);
213     }
214 
215     private static byte[] readSecurityBuffer(final byte[] src, final int index) throws NTLMEngineException {
216         final int length = readUShort(src, index);
217         final 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         }
222         final byte[] buffer = new byte[length];
223         System.arraycopy(src, offset, buffer, 0, length);
224         return buffer;
225     }
226 
227     /** Calculate a challenge block */
228     private static byte[] makeRandomChallenge() throws NTLMEngineException {
229         if (RND_GEN == null) {
230             throw new NTLMEngineException("Random generator not available");
231         }
232         final byte[] rval = new byte[8];
233         synchronized (RND_GEN) {
234             RND_GEN.nextBytes(rval);
235         }
236         return rval;
237     }
238 
239     /** Calculate a 16-byte secondary key */
240     private static byte[] makeSecondaryKey() throws NTLMEngineException {
241         if (RND_GEN == null) {
242             throw new NTLMEngineException("Random generator not available");
243         }
244         final byte[] rval = new byte[16];
245         synchronized (RND_GEN) {
246             RND_GEN.nextBytes(rval);
247         }
248         return rval;
249     }
250 
251     protected static class CipherGen {
252 
253         protected final String domain;
254         protected final String user;
255         protected final String password;
256         protected final byte[] challenge;
257         protected final String target;
258         protected final byte[] targetInformation;
259 
260         // Information we can generate but may be passed in (for testing)
261         protected byte[] clientChallenge;
262         protected byte[] clientChallenge2;
263         protected byte[] secondaryKey;
264         protected byte[] timestamp;
265 
266         // Stuff we always generate
267         protected byte[] lmHash = null;
268         protected byte[] lmResponse = null;
269         protected byte[] ntlmHash = null;
270         protected byte[] ntlmResponse = null;
271         protected byte[] ntlmv2Hash = null;
272         protected byte[] lmv2Hash = null;
273         protected byte[] lmv2Response = null;
274         protected byte[] ntlmv2Blob = null;
275         protected byte[] ntlmv2Response = null;
276         protected byte[] ntlm2SessionResponse = null;
277         protected byte[] lm2SessionResponse = null;
278         protected byte[] lmUserSessionKey = null;
279         protected byte[] ntlmUserSessionKey = null;
280         protected byte[] ntlmv2UserSessionKey = null;
281         protected byte[] ntlm2SessionResponseUserSessionKey = null;
282         protected byte[] lanManagerSessionKey = null;
283 
284         public CipherGen(final String domain, final String user, final String password,
285             final byte[] challenge, final String target, final byte[] targetInformation,
286             final byte[] clientChallenge, final byte[] clientChallenge2,
287             final byte[] secondaryKey, final byte[] timestamp) {
288             this.domain = domain;
289             this.target = target;
290             this.user = user;
291             this.password = password;
292             this.challenge = challenge;
293             this.targetInformation = targetInformation;
294             this.clientChallenge = clientChallenge;
295             this.clientChallenge2 = clientChallenge2;
296             this.secondaryKey = secondaryKey;
297             this.timestamp = timestamp;
298         }
299 
300         public CipherGen(final String domain, final String user, final String password,
301             final byte[] challenge, final String target, final byte[] targetInformation) {
302             this(domain, user, password, challenge, target, targetInformation, null, null, null, null);
303         }
304 
305         /** Calculate and return client challenge */
306         public byte[] getClientChallenge()
307             throws NTLMEngineException {
308             if (clientChallenge == null) {
309                 clientChallenge = makeRandomChallenge();
310             }
311             return clientChallenge;
312         }
313 
314         /** Calculate and return second client challenge */
315         public byte[] getClientChallenge2()
316             throws NTLMEngineException {
317             if (clientChallenge2 == null) {
318                 clientChallenge2 = makeRandomChallenge();
319             }
320             return clientChallenge2;
321         }
322 
323         /** Calculate and return random secondary key */
324         public byte[] getSecondaryKey()
325             throws NTLMEngineException {
326             if (secondaryKey == null) {
327                 secondaryKey = makeSecondaryKey();
328             }
329             return secondaryKey;
330         }
331 
332         /** Calculate and return the LMHash */
333         public byte[] getLMHash()
334             throws NTLMEngineException {
335             if (lmHash == null) {
336                 lmHash = lmHash(password);
337             }
338             return lmHash;
339         }
340 
341         /** Calculate and return the LMResponse */
342         public byte[] getLMResponse()
343             throws NTLMEngineException {
344             if (lmResponse == null) {
345                 lmResponse = lmResponse(getLMHash(),challenge);
346             }
347             return lmResponse;
348         }
349 
350         /** Calculate and return the NTLMHash */
351         public byte[] getNTLMHash()
352             throws NTLMEngineException {
353             if (ntlmHash == null) {
354                 ntlmHash = ntlmHash(password);
355             }
356             return ntlmHash;
357         }
358 
359         /** Calculate and return the NTLMResponse */
360         public byte[] getNTLMResponse()
361             throws NTLMEngineException {
362             if (ntlmResponse == null) {
363                 ntlmResponse = lmResponse(getNTLMHash(),challenge);
364             }
365             return ntlmResponse;
366         }
367 
368         /** Calculate the LMv2 hash */
369         public byte[] getLMv2Hash()
370             throws NTLMEngineException {
371             if (lmv2Hash == null) {
372                 lmv2Hash = lmv2Hash(domain, user, getNTLMHash());
373             }
374             return lmv2Hash;
375         }
376 
377         /** Calculate the NTLMv2 hash */
378         public byte[] getNTLMv2Hash()
379             throws NTLMEngineException {
380             if (ntlmv2Hash == null) {
381                 ntlmv2Hash = ntlmv2Hash(domain, user, getNTLMHash());
382             }
383             return ntlmv2Hash;
384         }
385 
386         /** Calculate a timestamp */
387         public byte[] getTimestamp() {
388             if (timestamp == null) {
389                 long time = System.currentTimeMillis();
390                 time += 11644473600000l; // milliseconds from January 1, 1601 -> epoch.
391                 time *= 10000; // tenths of a microsecond.
392                 // convert to little-endian byte array.
393                 timestamp = new byte[8];
394                 for (int i = 0; i < 8; i++) {
395                     timestamp[i] = (byte) time;
396                     time >>>= 8;
397                 }
398             }
399             return timestamp;
400         }
401 
402         /** Calculate the NTLMv2Blob */
403         public byte[] getNTLMv2Blob()
404             throws NTLMEngineException {
405             if (ntlmv2Blob == null) {
406                 ntlmv2Blob = createBlob(getClientChallenge2(), targetInformation, getTimestamp());
407             }
408             return ntlmv2Blob;
409         }
410 
411         /** Calculate the NTLMv2Response */
412         public byte[] getNTLMv2Response()
413             throws NTLMEngineException {
414             if (ntlmv2Response == null) {
415                 ntlmv2Response = lmv2Response(getNTLMv2Hash(),challenge,getNTLMv2Blob());
416             }
417             return ntlmv2Response;
418         }
419 
420         /** Calculate the LMv2Response */
421         public byte[] getLMv2Response()
422             throws NTLMEngineException {
423             if (lmv2Response == null) {
424                 lmv2Response = lmv2Response(getLMv2Hash(),challenge,getClientChallenge());
425             }
426             return lmv2Response;
427         }
428 
429         /** Get NTLM2SessionResponse */
430         public byte[] getNTLM2SessionResponse()
431             throws NTLMEngineException {
432             if (ntlm2SessionResponse == null) {
433                 ntlm2SessionResponse = ntlm2SessionResponse(getNTLMHash(),challenge,getClientChallenge());
434             }
435             return ntlm2SessionResponse;
436         }
437 
438         /** Calculate and return LM2 session response */
439         public byte[] getLM2SessionResponse()
440             throws NTLMEngineException {
441             if (lm2SessionResponse == null) {
442                 final byte[] clntChallenge = getClientChallenge();
443                 lm2SessionResponse = new byte[24];
444                 System.arraycopy(clntChallenge, 0, lm2SessionResponse, 0, clntChallenge.length);
445                 Arrays.fill(lm2SessionResponse, clntChallenge.length, lm2SessionResponse.length, (byte) 0x00);
446             }
447             return lm2SessionResponse;
448         }
449 
450         /** Get LMUserSessionKey */
451         public byte[] getLMUserSessionKey()
452             throws NTLMEngineException {
453             if (lmUserSessionKey == null) {
454                 lmUserSessionKey = new byte[16];
455                 System.arraycopy(getLMHash(), 0, lmUserSessionKey, 0, 8);
456                 Arrays.fill(lmUserSessionKey, 8, 16, (byte) 0x00);
457             }
458             return lmUserSessionKey;
459         }
460 
461         /** Get NTLMUserSessionKey */
462         public byte[] getNTLMUserSessionKey()
463             throws NTLMEngineException {
464             if (ntlmUserSessionKey == null) {
465                 final MD4 md4 = new MD4();
466                 md4.update(getNTLMHash());
467                 ntlmUserSessionKey = md4.getOutput();
468             }
469             return ntlmUserSessionKey;
470         }
471 
472         /** GetNTLMv2UserSessionKey */
473         public byte[] getNTLMv2UserSessionKey()
474             throws NTLMEngineException {
475             if (ntlmv2UserSessionKey == null) {
476                 final byte[] ntlmv2hash = getNTLMv2Hash();
477                 final byte[] truncatedResponse = new byte[16];
478                 System.arraycopy(getNTLMv2Response(), 0, truncatedResponse, 0, 16);
479                 ntlmv2UserSessionKey = hmacMD5(truncatedResponse, ntlmv2hash);
480             }
481             return ntlmv2UserSessionKey;
482         }
483 
484         /** Get NTLM2SessionResponseUserSessionKey */
485         public byte[] getNTLM2SessionResponseUserSessionKey()
486             throws NTLMEngineException {
487             if (ntlm2SessionResponseUserSessionKey == null) {
488                 final byte[] ntlm2SessionResponseNonce = getLM2SessionResponse();
489                 final byte[] sessionNonce = new byte[challenge.length + ntlm2SessionResponseNonce.length];
490                 System.arraycopy(challenge, 0, sessionNonce, 0, challenge.length);
491                 System.arraycopy(ntlm2SessionResponseNonce, 0, sessionNonce, challenge.length, ntlm2SessionResponseNonce.length);
492                 ntlm2SessionResponseUserSessionKey = hmacMD5(sessionNonce,getNTLMUserSessionKey());
493             }
494             return ntlm2SessionResponseUserSessionKey;
495         }
496 
497         /** Get LAN Manager session key */
498         public byte[] getLanManagerSessionKey()
499             throws NTLMEngineException {
500             if (lanManagerSessionKey == null) {
501                 try {
502                     final byte[] keyBytes = new byte[14];
503                     System.arraycopy(getLMHash(), 0, keyBytes, 0, 8);
504                     Arrays.fill(keyBytes, 8, keyBytes.length, (byte)0xbd);
505                     final Key lowKey = createDESKey(keyBytes, 0);
506                     final Key highKey = createDESKey(keyBytes, 7);
507                     final byte[] truncatedResponse = new byte[8];
508                     System.arraycopy(getLMResponse(), 0, truncatedResponse, 0, truncatedResponse.length);
509                     Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
510                     des.init(Cipher.ENCRYPT_MODE, lowKey);
511                     final byte[] lowPart = des.doFinal(truncatedResponse);
512                     des = Cipher.getInstance("DES/ECB/NoPadding");
513                     des.init(Cipher.ENCRYPT_MODE, highKey);
514                     final byte[] highPart = des.doFinal(truncatedResponse);
515                     lanManagerSessionKey = new byte[16];
516                     System.arraycopy(lowPart, 0, lanManagerSessionKey, 0, lowPart.length);
517                     System.arraycopy(highPart, 0, lanManagerSessionKey, lowPart.length, highPart.length);
518                 } catch (final Exception e) {
519                     throw new NTLMEngineException(e.getMessage(), e);
520                 }
521             }
522             return lanManagerSessionKey;
523         }
524     }
525 
526     /** Calculates HMAC-MD5 */
527     static byte[] hmacMD5(final byte[] value, final byte[] key)
528         throws NTLMEngineException {
529         final HMACMD5 hmacMD5 = new HMACMD5(key);
530         hmacMD5.update(value);
531         return hmacMD5.getOutput();
532     }
533 
534     /** Calculates RC4 */
535     static byte[] RC4(final byte[] value, final byte[] key)
536         throws NTLMEngineException {
537         try {
538             final Cipher rc4 = Cipher.getInstance("RC4");
539             rc4.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "RC4"));
540             return rc4.doFinal(value);
541         } catch (final Exception e) {
542             throw new NTLMEngineException(e.getMessage(), e);
543         }
544     }
545 
546     /**
547      * Calculates the NTLM2 Session Response for the given challenge, using the
548      * specified password and client challenge.
549      *
550      * @return The NTLM2 Session Response. This is placed in the NTLM response
551      *         field of the Type 3 message; the LM response field contains the
552      *         client challenge, null-padded to 24 bytes.
553      */
554     static byte[] ntlm2SessionResponse(final byte[] ntlmHash, final byte[] challenge,
555             final byte[] clientChallenge) throws NTLMEngineException {
556         try {
557             final MessageDigest md5 = MessageDigest.getInstance("MD5");
558             md5.update(challenge);
559             md5.update(clientChallenge);
560             final byte[] digest = md5.digest();
561 
562             final byte[] sessionHash = new byte[8];
563             System.arraycopy(digest, 0, sessionHash, 0, 8);
564             return lmResponse(ntlmHash, sessionHash);
565         } catch (final Exception e) {
566             if (e instanceof NTLMEngineException) {
567                 throw (NTLMEngineException) e;
568             }
569             throw new NTLMEngineException(e.getMessage(), e);
570         }
571     }
572 
573     /**
574      * Creates the LM Hash of the user's password.
575      *
576      * @param password
577      *            The password.
578      *
579      * @return The LM Hash of the given password, used in the calculation of the
580      *         LM Response.
581      */
582     private static byte[] lmHash(final String password) throws NTLMEngineException {
583         try {
584             final byte[] oemPassword = password.toUpperCase(Locale.ROOT).getBytes(Consts.ASCII);
585             final int length = Math.min(oemPassword.length, 14);
586             final byte[] keyBytes = new byte[14];
587             System.arraycopy(oemPassword, 0, keyBytes, 0, length);
588             final Key lowKey = createDESKey(keyBytes, 0);
589             final Key highKey = createDESKey(keyBytes, 7);
590             final byte[] magicConstant = "KGS!@#$%".getBytes(Consts.ASCII);
591             final Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
592             des.init(Cipher.ENCRYPT_MODE, lowKey);
593             final byte[] lowHash = des.doFinal(magicConstant);
594             des.init(Cipher.ENCRYPT_MODE, highKey);
595             final byte[] highHash = des.doFinal(magicConstant);
596             final byte[] lmHash = new byte[16];
597             System.arraycopy(lowHash, 0, lmHash, 0, 8);
598             System.arraycopy(highHash, 0, lmHash, 8, 8);
599             return lmHash;
600         } catch (final Exception e) {
601             throw new NTLMEngineException(e.getMessage(), e);
602         }
603     }
604 
605     /**
606      * Creates the NTLM Hash of the user's password.
607      *
608      * @param password
609      *            The password.
610      *
611      * @return The NTLM Hash of the given password, used in the calculation of
612      *         the NTLM Response and the NTLMv2 and LMv2 Hashes.
613      */
614     private static byte[] ntlmHash(final String password) throws NTLMEngineException {
615         if (UNICODE_LITTLE_UNMARKED == null) {
616             throw new NTLMEngineException("Unicode not supported");
617         }
618         final byte[] unicodePassword = password.getBytes(UNICODE_LITTLE_UNMARKED);
619         final MD4 md4 = new MD4();
620         md4.update(unicodePassword);
621         return md4.getOutput();
622     }
623 
624     /**
625      * Creates the LMv2 Hash of the user's password.
626      *
627      * @return The LMv2 Hash, used in the calculation of the NTLMv2 and LMv2
628      *         Responses.
629      */
630     private static byte[] lmv2Hash(final String domain, final String user, final byte[] ntlmHash)
631             throws NTLMEngineException {
632         if (UNICODE_LITTLE_UNMARKED == null) {
633             throw new NTLMEngineException("Unicode not supported");
634         }
635         final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
636         // Upper case username, upper case domain!
637         hmacMD5.update(user.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED));
638         if (domain != null) {
639             hmacMD5.update(domain.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED));
640         }
641         return hmacMD5.getOutput();
642     }
643 
644     /**
645      * Creates the NTLMv2 Hash of the user's password.
646      *
647      * @return The NTLMv2 Hash, used in the calculation of the NTLMv2 and LMv2
648      *         Responses.
649      */
650     private static byte[] ntlmv2Hash(final String domain, final String user, final byte[] ntlmHash)
651             throws NTLMEngineException {
652         if (UNICODE_LITTLE_UNMARKED == null) {
653             throw new NTLMEngineException("Unicode not supported");
654         }
655         final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
656         // Upper case username, mixed case target!!
657         hmacMD5.update(user.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED));
658         if (domain != null) {
659             hmacMD5.update(domain.getBytes(UNICODE_LITTLE_UNMARKED));
660         }
661         return hmacMD5.getOutput();
662     }
663 
664     /**
665      * Creates the LM Response from the given hash and Type 2 challenge.
666      *
667      * @param hash
668      *            The LM or NTLM Hash.
669      * @param challenge
670      *            The server challenge from the Type 2 message.
671      *
672      * @return The response (either LM or NTLM, depending on the provided hash).
673      */
674     private static byte[] lmResponse(final byte[] hash, final byte[] challenge) throws NTLMEngineException {
675         try {
676             final byte[] keyBytes = new byte[21];
677             System.arraycopy(hash, 0, keyBytes, 0, 16);
678             final Key lowKey = createDESKey(keyBytes, 0);
679             final Key middleKey = createDESKey(keyBytes, 7);
680             final Key highKey = createDESKey(keyBytes, 14);
681             final Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
682             des.init(Cipher.ENCRYPT_MODE, lowKey);
683             final byte[] lowResponse = des.doFinal(challenge);
684             des.init(Cipher.ENCRYPT_MODE, middleKey);
685             final byte[] middleResponse = des.doFinal(challenge);
686             des.init(Cipher.ENCRYPT_MODE, highKey);
687             final byte[] highResponse = des.doFinal(challenge);
688             final byte[] lmResponse = new byte[24];
689             System.arraycopy(lowResponse, 0, lmResponse, 0, 8);
690             System.arraycopy(middleResponse, 0, lmResponse, 8, 8);
691             System.arraycopy(highResponse, 0, lmResponse, 16, 8);
692             return lmResponse;
693         } catch (final Exception e) {
694             throw new NTLMEngineException(e.getMessage(), e);
695         }
696     }
697 
698     /**
699      * Creates the LMv2 Response from the given hash, client data, and Type 2
700      * challenge.
701      *
702      * @param hash
703      *            The NTLMv2 Hash.
704      * @param clientData
705      *            The client data (blob or client challenge).
706      * @param challenge
707      *            The server challenge from the Type 2 message.
708      *
709      * @return The response (either NTLMv2 or LMv2, depending on the client
710      *         data).
711      */
712     private static byte[] lmv2Response(final byte[] hash, final byte[] challenge, final byte[] clientData)
713             throws NTLMEngineException {
714         final HMACMD5 hmacMD5 = new HMACMD5(hash);
715         hmacMD5.update(challenge);
716         hmacMD5.update(clientData);
717         final byte[] mac = hmacMD5.getOutput();
718         final byte[] lmv2Response = new byte[mac.length + clientData.length];
719         System.arraycopy(mac, 0, lmv2Response, 0, mac.length);
720         System.arraycopy(clientData, 0, lmv2Response, mac.length, clientData.length);
721         return lmv2Response;
722     }
723 
724     /**
725      * Creates the NTLMv2 blob from the given target information block and
726      * client challenge.
727      *
728      * @param targetInformation
729      *            The target information block from the Type 2 message.
730      * @param clientChallenge
731      *            The random 8-byte client challenge.
732      *
733      * @return The blob, used in the calculation of the NTLMv2 Response.
734      */
735     private static byte[] createBlob(final byte[] clientChallenge, final byte[] targetInformation, final byte[] timestamp) {
736         final byte[] blobSignature = new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00 };
737         final byte[] reserved = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
738         final byte[] unknown1 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
739         final byte[] unknown2 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
740         final byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8
741                 + unknown1.length + targetInformation.length + unknown2.length];
742         int offset = 0;
743         System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length);
744         offset += blobSignature.length;
745         System.arraycopy(reserved, 0, blob, offset, reserved.length);
746         offset += reserved.length;
747         System.arraycopy(timestamp, 0, blob, offset, timestamp.length);
748         offset += timestamp.length;
749         System.arraycopy(clientChallenge, 0, blob, offset, 8);
750         offset += 8;
751         System.arraycopy(unknown1, 0, blob, offset, unknown1.length);
752         offset += unknown1.length;
753         System.arraycopy(targetInformation, 0, blob, offset, targetInformation.length);
754         offset += targetInformation.length;
755         System.arraycopy(unknown2, 0, blob, offset, unknown2.length);
756         offset += unknown2.length;
757         return blob;
758     }
759 
760     /**
761      * Creates a DES encryption key from the given key material.
762      *
763      * @param bytes
764      *            A byte array containing the DES key material.
765      * @param offset
766      *            The offset in the given byte array at which the 7-byte key
767      *            material starts.
768      *
769      * @return A DES encryption key created from the key material starting at
770      *         the specified offset in the given byte array.
771      */
772     private static Key createDESKey(final byte[] bytes, final int offset) {
773         final byte[] keyBytes = new byte[7];
774         System.arraycopy(bytes, offset, keyBytes, 0, 7);
775         final byte[] material = new byte[8];
776         material[0] = keyBytes[0];
777         material[1] = (byte) (keyBytes[0] << 7 | (keyBytes[1] & 0xff) >>> 1);
778         material[2] = (byte) (keyBytes[1] << 6 | (keyBytes[2] & 0xff) >>> 2);
779         material[3] = (byte) (keyBytes[2] << 5 | (keyBytes[3] & 0xff) >>> 3);
780         material[4] = (byte) (keyBytes[3] << 4 | (keyBytes[4] & 0xff) >>> 4);
781         material[5] = (byte) (keyBytes[4] << 3 | (keyBytes[5] & 0xff) >>> 5);
782         material[6] = (byte) (keyBytes[5] << 2 | (keyBytes[6] & 0xff) >>> 6);
783         material[7] = (byte) (keyBytes[6] << 1);
784         oddParity(material);
785         return new SecretKeySpec(material, "DES");
786     }
787 
788     /**
789      * Applies odd parity to the given byte array.
790      *
791      * @param bytes
792      *            The data whose parity bits are to be adjusted for odd parity.
793      */
794     private static void oddParity(final byte[] bytes) {
795         for (int i = 0; i < bytes.length; i++) {
796             final byte b = bytes[i];
797             final boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3)
798                     ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0;
799             if (needsParity) {
800                 bytes[i] |= (byte) 0x01;
801             } else {
802                 bytes[i] &= (byte) 0xfe;
803             }
804         }
805     }
806 
807     /** NTLM message generation, base class */
808     static class NTLMMessage {
809         /** The current response */
810         private byte[] messageContents = null;
811 
812         /** The current output position */
813         private int currentOutputPosition = 0;
814 
815         /** Constructor to use when message contents are not yet known */
816         NTLMMessage() {
817         }
818 
819         /** Constructor to use when message contents are known */
820         NTLMMessage(final String messageBody, final int expectedType) throws NTLMEngineException {
821             messageContents = Base64.decodeBase64(messageBody.getBytes(DEFAULT_CHARSET));
822             // Look for NTLM message
823             if (messageContents.length < SIGNATURE.length) {
824                 throw new NTLMEngineException("NTLM message decoding error - packet too short");
825             }
826             int i = 0;
827             while (i < SIGNATURE.length) {
828                 if (messageContents[i] != SIGNATURE[i]) {
829                     throw new NTLMEngineException(
830                             "NTLM message expected - instead got unrecognized bytes");
831                 }
832                 i++;
833             }
834 
835             // Check to be sure there's a type 2 message indicator next
836             final int type = readULong(SIGNATURE.length);
837             if (type != expectedType) {
838                 throw new NTLMEngineException("NTLM type " + Integer.toString(expectedType)
839                         + " message expected - instead got type " + Integer.toString(type));
840             }
841 
842             currentOutputPosition = messageContents.length;
843         }
844 
845         /**
846          * Get the length of the signature and flags, so calculations can adjust
847          * offsets accordingly.
848          */
849         protected int getPreambleLength() {
850             return SIGNATURE.length + 4;
851         }
852 
853         /** Get the message length */
854         protected int getMessageLength() {
855             return currentOutputPosition;
856         }
857 
858         /** Read a byte from a position within the message buffer */
859         protected byte readByte(final int position) throws NTLMEngineException {
860             if (messageContents.length < position + 1) {
861                 throw new NTLMEngineException("NTLM: Message too short");
862             }
863             return messageContents[position];
864         }
865 
866         /** Read a bunch of bytes from a position in the message buffer */
867         protected void readBytes(final byte[] buffer, final int position) throws NTLMEngineException {
868             if (messageContents.length < position + buffer.length) {
869                 throw new NTLMEngineException("NTLM: Message too short");
870             }
871             System.arraycopy(messageContents, position, buffer, 0, buffer.length);
872         }
873 
874         /** Read a ushort from a position within the message buffer */
875         protected int readUShort(final int position) throws NTLMEngineException {
876             return NTLMEngineImpl.readUShort(messageContents, position);
877         }
878 
879         /** Read a ulong from a position within the message buffer */
880         protected int readULong(final int position) throws NTLMEngineException {
881             return NTLMEngineImpl.readULong(messageContents, position);
882         }
883 
884         /** Read a security buffer from a position within the message buffer */
885         protected byte[] readSecurityBuffer(final int position) throws NTLMEngineException {
886             return NTLMEngineImpl.readSecurityBuffer(messageContents, position);
887         }
888 
889         /**
890          * Prepares the object to create a response of the given length.
891          *
892          * @param maxlength
893          *            the maximum length of the response to prepare, not
894          *            including the type and the signature (which this method
895          *            adds).
896          */
897         protected void prepareResponse(final int maxlength, final int messageType) {
898             messageContents = new byte[maxlength];
899             currentOutputPosition = 0;
900             addBytes(SIGNATURE);
901             addULong(messageType);
902         }
903 
904         /**
905          * Adds the given byte to the response.
906          *
907          * @param b
908          *            the byte to add.
909          */
910         protected void addByte(final byte b) {
911             messageContents[currentOutputPosition] = b;
912             currentOutputPosition++;
913         }
914 
915         /**
916          * Adds the given bytes to the response.
917          *
918          * @param bytes
919          *            the bytes to add.
920          */
921         protected void addBytes(final byte[] bytes) {
922             if (bytes == null) {
923                 return;
924             }
925             for (final byte b : bytes) {
926                 messageContents[currentOutputPosition] = b;
927                 currentOutputPosition++;
928             }
929         }
930 
931         /** Adds a USHORT to the response */
932         protected void addUShort(final int value) {
933             addByte((byte) (value & 0xff));
934             addByte((byte) (value >> 8 & 0xff));
935         }
936 
937         /** Adds a ULong to the response */
938         protected void addULong(final int value) {
939             addByte((byte) (value & 0xff));
940             addByte((byte) (value >> 8 & 0xff));
941             addByte((byte) (value >> 16 & 0xff));
942             addByte((byte) (value >> 24 & 0xff));
943         }
944 
945         /**
946          * Returns the response that has been generated after shrinking the
947          * array if required and base64 encodes the response.
948          *
949          * @return The response as above.
950          */
951         String getResponse() {
952             final byte[] resp;
953             if (messageContents.length > currentOutputPosition) {
954                 final byte[] tmp = new byte[currentOutputPosition];
955                 System.arraycopy(messageContents, 0, tmp, 0, currentOutputPosition);
956                 resp = tmp;
957             } else {
958                 resp = messageContents;
959             }
960             return EncodingUtils.getAsciiString(Base64.encodeBase64(resp));
961         }
962 
963     }
964 
965     /** Type 1 message assembly class */
966     static class Type1Message extends NTLMMessage {
967 
968         private final byte[] hostBytes;
969         private final byte[] domainBytes;
970 
971         Type1Message(final String domain, final String host) throws NTLMEngineException {
972             super();
973             if (UNICODE_LITTLE_UNMARKED == null) {
974                 throw new NTLMEngineException("Unicode not supported");
975             }
976             // Strip off domain name from the host!
977             final String unqualifiedHost = convertHost(host);
978             // Use only the base domain name!
979             final String unqualifiedDomain = convertDomain(domain);
980 
981             hostBytes = unqualifiedHost != null ?
982                     unqualifiedHost.getBytes(UNICODE_LITTLE_UNMARKED) : null;
983             domainBytes = unqualifiedDomain != null ?
984                     unqualifiedDomain.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED) : null;
985         }
986 
987         Type1Message() {
988             super();
989             hostBytes = null;
990             domainBytes = null;
991         }
992         /**
993          * Getting the response involves building the message before returning
994          * it
995          */
996         @Override
997         String getResponse() {
998             // Now, build the message. Calculate its length first, including
999             // signature or type.
1000             final int finalLength = 32 + 8 /*+ hostBytes.length + domainBytes.length */;
1001 
1002             // Set up the response. This will initialize the signature, message
1003             // type, and flags.
1004             prepareResponse(finalLength, 1);
1005 
1006             // Flags. These are the complete set of flags we support.
1007             addULong(
1008                     //FLAG_WORKSTATION_PRESENT |
1009                     //FLAG_DOMAIN_PRESENT |
1010 
1011                     // Required flags
1012                     //FLAG_REQUEST_LAN_MANAGER_KEY |
1013                     FLAG_REQUEST_NTLMv1 |
1014                     FLAG_REQUEST_NTLM2_SESSION |
1015 
1016                     // Protocol version request
1017                     FLAG_REQUEST_VERSION |
1018 
1019                     // Recommended privacy settings
1020                     FLAG_REQUEST_ALWAYS_SIGN |
1021                     //FLAG_REQUEST_SEAL |
1022                     //FLAG_REQUEST_SIGN |
1023 
1024                     // These must be set according to documentation, based on use of SEAL above
1025                     FLAG_REQUEST_128BIT_KEY_EXCH |
1026                     FLAG_REQUEST_56BIT_ENCRYPTION |
1027                     //FLAG_REQUEST_EXPLICIT_KEY_EXCH |
1028 
1029                     FLAG_REQUEST_UNICODE_ENCODING);
1030 
1031             // Domain length (two times).
1032             addUShort(/*domainBytes.length*/0);
1033             addUShort(/*domainBytes.length*/0);
1034 
1035             // Domain offset.
1036             addULong(/*hostBytes.length +*/ 32 + 8);
1037 
1038             // Host length (two times).
1039             addUShort(/*hostBytes.length*/0);
1040             addUShort(/*hostBytes.length*/0);
1041 
1042             // Host offset (always 32 + 8).
1043             addULong(32 + 8);
1044 
1045             // Version
1046             addUShort(0x0105);
1047             // Build
1048             addULong(2600);
1049             // NTLM revision
1050             addUShort(0x0f00);
1051 
1052             // Host (workstation) String.
1053             if (hostBytes != null) {
1054                 addBytes(hostBytes);
1055             }
1056             // Domain String.
1057             if (domainBytes != null) {
1058                 addBytes(domainBytes);
1059             }
1060 
1061             return super.getResponse();
1062         }
1063 
1064     }
1065 
1066     /** Type 2 message class */
1067     static class Type2Message extends NTLMMessage {
1068         protected byte[] challenge;
1069         protected String target;
1070         protected byte[] targetInfo;
1071         protected int flags;
1072 
1073         Type2Message(final String message) throws NTLMEngineException {
1074             super(message, 2);
1075 
1076             // Type 2 message is laid out as follows:
1077             // First 8 bytes: NTLMSSP[0]
1078             // Next 4 bytes: Ulong, value 2
1079             // Next 8 bytes, starting at offset 12: target field (2 ushort lengths, 1 ulong offset)
1080             // Next 4 bytes, starting at offset 20: Flags, e.g. 0x22890235
1081             // Next 8 bytes, starting at offset 24: Challenge
1082             // Next 8 bytes, starting at offset 32: ??? (8 bytes of zeros)
1083             // Next 8 bytes, starting at offset 40: targetinfo field (2 ushort lengths, 1 ulong offset)
1084             // Next 2 bytes, major/minor version number (e.g. 0x05 0x02)
1085             // Next 8 bytes, build number
1086             // Next 2 bytes, protocol version number (e.g. 0x00 0x0f)
1087             // Next, various text fields, and a ushort of value 0 at the end
1088 
1089             // Parse out the rest of the info we need from the message
1090             // The nonce is the 8 bytes starting from the byte in position 24.
1091             challenge = new byte[8];
1092             readBytes(challenge, 24);
1093 
1094             flags = readULong(20);
1095 
1096             if ((flags & FLAG_REQUEST_UNICODE_ENCODING) == 0) {
1097                 throw new NTLMEngineException(
1098                         "NTLM type 2 message indicates no support for Unicode. Flags are: "
1099                                 + Integer.toString(flags));
1100             }
1101 
1102             // Do the target!
1103             target = null;
1104             // The TARGET_DESIRED flag is said to not have understood semantics
1105             // in Type2 messages, so use the length of the packet to decide
1106             // how to proceed instead
1107             if (getMessageLength() >= 12 + 8) {
1108                 final byte[] bytes = readSecurityBuffer(12);
1109                 if (bytes.length != 0) {
1110                     try {
1111                         target = new String(bytes, "UnicodeLittleUnmarked");
1112                     } catch (final UnsupportedEncodingException e) {
1113                         throw new NTLMEngineException(e.getMessage(), e);
1114                     }
1115                 }
1116             }
1117 
1118             // Do the target info!
1119             targetInfo = null;
1120             // TARGET_DESIRED flag cannot be relied on, so use packet length
1121             if (getMessageLength() >= 40 + 8) {
1122                 final byte[] bytes = readSecurityBuffer(40);
1123                 if (bytes.length != 0) {
1124                     targetInfo = bytes;
1125                 }
1126             }
1127         }
1128 
1129         /** Retrieve the challenge */
1130         byte[] getChallenge() {
1131             return challenge;
1132         }
1133 
1134         /** Retrieve the target */
1135         String getTarget() {
1136             return target;
1137         }
1138 
1139         /** Retrieve the target info */
1140         byte[] getTargetInfo() {
1141             return targetInfo;
1142         }
1143 
1144         /** Retrieve the response flags */
1145         int getFlags() {
1146             return flags;
1147         }
1148 
1149     }
1150 
1151     /** Type 3 message assembly class */
1152     static class Type3Message extends NTLMMessage {
1153         // Response flags from the type2 message
1154         protected int type2Flags;
1155 
1156         protected byte[] domainBytes;
1157         protected byte[] hostBytes;
1158         protected byte[] userBytes;
1159 
1160         protected byte[] lmResp;
1161         protected byte[] ntResp;
1162         protected byte[] sessionKey;
1163 
1164 
1165         /** Constructor. Pass the arguments we will need */
1166         Type3Message(final String domain, final String host, final String user, final String password, final byte[] nonce,
1167                 final int type2Flags, final String target, final byte[] targetInformation)
1168                 throws NTLMEngineException {
1169             // Save the flags
1170             this.type2Flags = type2Flags;
1171 
1172             // Strip off domain name from the host!
1173             final String unqualifiedHost = convertHost(host);
1174             // Use only the base domain name!
1175             final String unqualifiedDomain = convertDomain(domain);
1176 
1177             // Create a cipher generator class.  Use domain BEFORE it gets modified!
1178             final CipherGen gen = new CipherGen(unqualifiedDomain, user, password, nonce, target, targetInformation);
1179 
1180             // Use the new code to calculate the responses, including v2 if that
1181             // seems warranted.
1182             byte[] userSessionKey;
1183             try {
1184                 // This conditional may not work on Windows Server 2008 R2 and above, where it has not yet
1185                 // been tested
1186                 if (((type2Flags & FLAG_TARGETINFO_PRESENT) != 0) &&
1187                     targetInformation != null && target != null) {
1188                     // NTLMv2
1189                     ntResp = gen.getNTLMv2Response();
1190                     lmResp = gen.getLMv2Response();
1191                     if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) {
1192                         userSessionKey = gen.getLanManagerSessionKey();
1193                     } else {
1194                         userSessionKey = gen.getNTLMv2UserSessionKey();
1195                     }
1196                 } else {
1197                     // NTLMv1
1198                     if ((type2Flags & FLAG_REQUEST_NTLM2_SESSION) != 0) {
1199                         // NTLM2 session stuff is requested
1200                         ntResp = gen.getNTLM2SessionResponse();
1201                         lmResp = gen.getLM2SessionResponse();
1202                         if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) {
1203                             userSessionKey = gen.getLanManagerSessionKey();
1204                         } else {
1205                             userSessionKey = gen.getNTLM2SessionResponseUserSessionKey();
1206                         }
1207                     } else {
1208                         ntResp = gen.getNTLMResponse();
1209                         lmResp = gen.getLMResponse();
1210                         if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) {
1211                             userSessionKey = gen.getLanManagerSessionKey();
1212                         } else {
1213                             userSessionKey = gen.getNTLMUserSessionKey();
1214                         }
1215                     }
1216                 }
1217             } catch (final NTLMEngineException e) {
1218                 // This likely means we couldn't find the MD4 hash algorithm -
1219                 // fail back to just using LM
1220                 ntResp = new byte[0];
1221                 lmResp = gen.getLMResponse();
1222                 if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) {
1223                     userSessionKey = gen.getLanManagerSessionKey();
1224                 } else {
1225                     userSessionKey = gen.getLMUserSessionKey();
1226                 }
1227             }
1228 
1229             if ((type2Flags & FLAG_REQUEST_SIGN) != 0) {
1230                 if ((type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) != 0) {
1231                     sessionKey = RC4(gen.getSecondaryKey(), userSessionKey);
1232                 } else {
1233                     sessionKey = userSessionKey;
1234                 }
1235             } else {
1236                 sessionKey = null;
1237             }
1238             if (UNICODE_LITTLE_UNMARKED == null) {
1239                 throw new NTLMEngineException("Unicode not supported");
1240             }
1241             hostBytes = unqualifiedHost != null ? unqualifiedHost.getBytes(UNICODE_LITTLE_UNMARKED) : null;
1242             domainBytes = unqualifiedDomain != null ? unqualifiedDomain
1243                     .toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED) : null;
1244             userBytes = user.getBytes(UNICODE_LITTLE_UNMARKED);
1245         }
1246 
1247         /** Assemble the response */
1248         @Override
1249         String getResponse() {
1250             final int ntRespLen = ntResp.length;
1251             final int lmRespLen = lmResp.length;
1252 
1253             final int domainLen = domainBytes != null ? domainBytes.length : 0;
1254             final int hostLen = hostBytes != null ? hostBytes.length: 0;
1255             final int userLen = userBytes.length;
1256             final int sessionKeyLen;
1257             if (sessionKey != null) {
1258                 sessionKeyLen = sessionKey.length;
1259             } else {
1260                 sessionKeyLen = 0;
1261             }
1262 
1263             // Calculate the layout within the packet
1264             final int lmRespOffset = 72;  // allocate space for the version
1265             final int ntRespOffset = lmRespOffset + lmRespLen;
1266             final int domainOffset = ntRespOffset + ntRespLen;
1267             final int userOffset = domainOffset + domainLen;
1268             final int hostOffset = userOffset + userLen;
1269             final int sessionKeyOffset = hostOffset + hostLen;
1270             final int finalLength = sessionKeyOffset + sessionKeyLen;
1271 
1272             // Start the response. Length includes signature and type
1273             prepareResponse(finalLength, 3);
1274 
1275             // LM Resp Length (twice)
1276             addUShort(lmRespLen);
1277             addUShort(lmRespLen);
1278 
1279             // LM Resp Offset
1280             addULong(lmRespOffset);
1281 
1282             // NT Resp Length (twice)
1283             addUShort(ntRespLen);
1284             addUShort(ntRespLen);
1285 
1286             // NT Resp Offset
1287             addULong(ntRespOffset);
1288 
1289             // Domain length (twice)
1290             addUShort(domainLen);
1291             addUShort(domainLen);
1292 
1293             // Domain offset.
1294             addULong(domainOffset);
1295 
1296             // User Length (twice)
1297             addUShort(userLen);
1298             addUShort(userLen);
1299 
1300             // User offset
1301             addULong(userOffset);
1302 
1303             // Host length (twice)
1304             addUShort(hostLen);
1305             addUShort(hostLen);
1306 
1307             // Host offset
1308             addULong(hostOffset);
1309 
1310             // Session key length (twice)
1311             addUShort(sessionKeyLen);
1312             addUShort(sessionKeyLen);
1313 
1314             // Session key offset
1315             addULong(sessionKeyOffset);
1316 
1317             // Flags.
1318             addULong(
1319                     //FLAG_WORKSTATION_PRESENT |
1320                     //FLAG_DOMAIN_PRESENT |
1321 
1322                     // Required flags
1323                     (type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) |
1324                     (type2Flags & FLAG_REQUEST_NTLMv1) |
1325                     (type2Flags & FLAG_REQUEST_NTLM2_SESSION) |
1326 
1327                     // Protocol version request
1328                     FLAG_REQUEST_VERSION |
1329 
1330                     // Recommended privacy settings
1331                     (type2Flags & FLAG_REQUEST_ALWAYS_SIGN) |
1332                     (type2Flags & FLAG_REQUEST_SEAL) |
1333                     (type2Flags & FLAG_REQUEST_SIGN) |
1334 
1335                     // These must be set according to documentation, based on use of SEAL above
1336                     (type2Flags & FLAG_REQUEST_128BIT_KEY_EXCH) |
1337                     (type2Flags & FLAG_REQUEST_56BIT_ENCRYPTION) |
1338                     (type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) |
1339 
1340                     (type2Flags & FLAG_TARGETINFO_PRESENT) |
1341                     (type2Flags & FLAG_REQUEST_UNICODE_ENCODING) |
1342                     (type2Flags & FLAG_REQUEST_TARGET)
1343             );
1344 
1345             // Version
1346             addUShort(0x0105);
1347             // Build
1348             addULong(2600);
1349             // NTLM revision
1350             addUShort(0x0f00);
1351 
1352             // Add the actual data
1353             addBytes(lmResp);
1354             addBytes(ntResp);
1355             addBytes(domainBytes);
1356             addBytes(userBytes);
1357             addBytes(hostBytes);
1358             if (sessionKey != null) {
1359                 addBytes(sessionKey);
1360             }
1361 
1362             return super.getResponse();
1363         }
1364     }
1365 
1366     static void writeULong(final byte[] buffer, final int value, final int offset) {
1367         buffer[offset] = (byte) (value & 0xff);
1368         buffer[offset + 1] = (byte) (value >> 8 & 0xff);
1369         buffer[offset + 2] = (byte) (value >> 16 & 0xff);
1370         buffer[offset + 3] = (byte) (value >> 24 & 0xff);
1371     }
1372 
1373     static int F(final int x, final int y, final int z) {
1374         return ((x & y) | (~x & z));
1375     }
1376 
1377     static int G(final int x, final int y, final int z) {
1378         return ((x & y) | (x & z) | (y & z));
1379     }
1380 
1381     static int H(final int x, final int y, final int z) {
1382         return (x ^ y ^ z);
1383     }
1384 
1385     static int rotintlft(final int val, final int numbits) {
1386         return ((val << numbits) | (val >>> (32 - numbits)));
1387     }
1388 
1389     /**
1390      * Cryptography support - MD4. The following class was based loosely on the
1391      * RFC and on code found at http://www.cs.umd.edu/~harry/jotp/src/md.java.
1392      * Code correctness was verified by looking at MD4.java from the jcifs
1393      * library (http://jcifs.samba.org). It was massaged extensively to the
1394      * final form found here by Karl Wright (kwright@metacarta.com).
1395      */
1396     static class MD4 {
1397         protected int A = 0x67452301;
1398         protected int B = 0xefcdab89;
1399         protected int C = 0x98badcfe;
1400         protected int D = 0x10325476;
1401         protected long count = 0L;
1402         protected byte[] dataBuffer = new byte[64];
1403 
1404         MD4() {
1405         }
1406 
1407         void update(final byte[] input) {
1408             // We always deal with 512 bits at a time. Correspondingly, there is
1409             // a buffer 64 bytes long that we write data into until it gets
1410             // full.
1411             int curBufferPos = (int) (count & 63L);
1412             int inputIndex = 0;
1413             while (input.length - inputIndex + curBufferPos >= dataBuffer.length) {
1414                 // We have enough data to do the next step. Do a partial copy
1415                 // and a transform, updating inputIndex and curBufferPos
1416                 // accordingly
1417                 final int transferAmt = dataBuffer.length - curBufferPos;
1418                 System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt);
1419                 count += transferAmt;
1420                 curBufferPos = 0;
1421                 inputIndex += transferAmt;
1422                 processBuffer();
1423             }
1424 
1425             // If there's anything left, copy it into the buffer and leave it.
1426             // We know there's not enough left to process.
1427             if (inputIndex < input.length) {
1428                 final int transferAmt = input.length - inputIndex;
1429                 System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt);
1430                 count += transferAmt;
1431                 curBufferPos += transferAmt;
1432             }
1433         }
1434 
1435         byte[] getOutput() {
1436             // Feed pad/length data into engine. This must round out the input
1437             // to a multiple of 512 bits.
1438             final int bufferIndex = (int) (count & 63L);
1439             final int padLen = (bufferIndex < 56) ? (56 - bufferIndex) : (120 - bufferIndex);
1440             final byte[] postBytes = new byte[padLen + 8];
1441             // Leading 0x80, specified amount of zero padding, then length in
1442             // bits.
1443             postBytes[0] = (byte) 0x80;
1444             // Fill out the last 8 bytes with the length
1445             for (int i = 0; i < 8; i++) {
1446                 postBytes[padLen + i] = (byte) ((count * 8) >>> (8 * i));
1447             }
1448 
1449             // Update the engine
1450             update(postBytes);
1451 
1452             // Calculate final result
1453             final byte[] result = new byte[16];
1454             writeULong(result, A, 0);
1455             writeULong(result, B, 4);
1456             writeULong(result, C, 8);
1457             writeULong(result, D, 12);
1458             return result;
1459         }
1460 
1461         protected void processBuffer() {
1462             // Convert current buffer to 16 ulongs
1463             final int[] d = new int[16];
1464 
1465             for (int i = 0; i < 16; i++) {
1466                 d[i] = (dataBuffer[i * 4] & 0xff) + ((dataBuffer[i * 4 + 1] & 0xff) << 8)
1467                         + ((dataBuffer[i * 4 + 2] & 0xff) << 16)
1468                         + ((dataBuffer[i * 4 + 3] & 0xff) << 24);
1469             }
1470 
1471             // Do a round of processing
1472             final int AA = A;
1473             final int BB = B;
1474             final int CC = C;
1475             final int DD = D;
1476             round1(d);
1477             round2(d);
1478             round3(d);
1479             A += AA;
1480             B += BB;
1481             C += CC;
1482             D += DD;
1483 
1484         }
1485 
1486         protected void round1(final int[] d) {
1487             A = rotintlft((A + F(B, C, D) + d[0]), 3);
1488             D = rotintlft((D + F(A, B, C) + d[1]), 7);
1489             C = rotintlft((C + F(D, A, B) + d[2]), 11);
1490             B = rotintlft((B + F(C, D, A) + d[3]), 19);
1491 
1492             A = rotintlft((A + F(B, C, D) + d[4]), 3);
1493             D = rotintlft((D + F(A, B, C) + d[5]), 7);
1494             C = rotintlft((C + F(D, A, B) + d[6]), 11);
1495             B = rotintlft((B + F(C, D, A) + d[7]), 19);
1496 
1497             A = rotintlft((A + F(B, C, D) + d[8]), 3);
1498             D = rotintlft((D + F(A, B, C) + d[9]), 7);
1499             C = rotintlft((C + F(D, A, B) + d[10]), 11);
1500             B = rotintlft((B + F(C, D, A) + d[11]), 19);
1501 
1502             A = rotintlft((A + F(B, C, D) + d[12]), 3);
1503             D = rotintlft((D + F(A, B, C) + d[13]), 7);
1504             C = rotintlft((C + F(D, A, B) + d[14]), 11);
1505             B = rotintlft((B + F(C, D, A) + d[15]), 19);
1506         }
1507 
1508         protected void round2(final int[] d) {
1509             A = rotintlft((A + G(B, C, D) + d[0] + 0x5a827999), 3);
1510             D = rotintlft((D + G(A, B, C) + d[4] + 0x5a827999), 5);
1511             C = rotintlft((C + G(D, A, B) + d[8] + 0x5a827999), 9);
1512             B = rotintlft((B + G(C, D, A) + d[12] + 0x5a827999), 13);
1513 
1514             A = rotintlft((A + G(B, C, D) + d[1] + 0x5a827999), 3);
1515             D = rotintlft((D + G(A, B, C) + d[5] + 0x5a827999), 5);
1516             C = rotintlft((C + G(D, A, B) + d[9] + 0x5a827999), 9);
1517             B = rotintlft((B + G(C, D, A) + d[13] + 0x5a827999), 13);
1518 
1519             A = rotintlft((A + G(B, C, D) + d[2] + 0x5a827999), 3);
1520             D = rotintlft((D + G(A, B, C) + d[6] + 0x5a827999), 5);
1521             C = rotintlft((C + G(D, A, B) + d[10] + 0x5a827999), 9);
1522             B = rotintlft((B + G(C, D, A) + d[14] + 0x5a827999), 13);
1523 
1524             A = rotintlft((A + G(B, C, D) + d[3] + 0x5a827999), 3);
1525             D = rotintlft((D + G(A, B, C) + d[7] + 0x5a827999), 5);
1526             C = rotintlft((C + G(D, A, B) + d[11] + 0x5a827999), 9);
1527             B = rotintlft((B + G(C, D, A) + d[15] + 0x5a827999), 13);
1528 
1529         }
1530 
1531         protected void round3(final int[] d) {
1532             A = rotintlft((A + H(B, C, D) + d[0] + 0x6ed9eba1), 3);
1533             D = rotintlft((D + H(A, B, C) + d[8] + 0x6ed9eba1), 9);
1534             C = rotintlft((C + H(D, A, B) + d[4] + 0x6ed9eba1), 11);
1535             B = rotintlft((B + H(C, D, A) + d[12] + 0x6ed9eba1), 15);
1536 
1537             A = rotintlft((A + H(B, C, D) + d[2] + 0x6ed9eba1), 3);
1538             D = rotintlft((D + H(A, B, C) + d[10] + 0x6ed9eba1), 9);
1539             C = rotintlft((C + H(D, A, B) + d[6] + 0x6ed9eba1), 11);
1540             B = rotintlft((B + H(C, D, A) + d[14] + 0x6ed9eba1), 15);
1541 
1542             A = rotintlft((A + H(B, C, D) + d[1] + 0x6ed9eba1), 3);
1543             D = rotintlft((D + H(A, B, C) + d[9] + 0x6ed9eba1), 9);
1544             C = rotintlft((C + H(D, A, B) + d[5] + 0x6ed9eba1), 11);
1545             B = rotintlft((B + H(C, D, A) + d[13] + 0x6ed9eba1), 15);
1546 
1547             A = rotintlft((A + H(B, C, D) + d[3] + 0x6ed9eba1), 3);
1548             D = rotintlft((D + H(A, B, C) + d[11] + 0x6ed9eba1), 9);
1549             C = rotintlft((C + H(D, A, B) + d[7] + 0x6ed9eba1), 11);
1550             B = rotintlft((B + H(C, D, A) + d[15] + 0x6ed9eba1), 15);
1551 
1552         }
1553 
1554     }
1555 
1556     /**
1557      * Cryptography support - HMACMD5 - algorithmically based on various web
1558      * resources by Karl Wright
1559      */
1560     static class HMACMD5 {
1561         protected byte[] ipad;
1562         protected byte[] opad;
1563         protected MessageDigest md5;
1564 
1565         HMACMD5(final byte[] input) throws NTLMEngineException {
1566             byte[] key = input;
1567             try {
1568                 md5 = MessageDigest.getInstance("MD5");
1569             } catch (final Exception ex) {
1570                 // Umm, the algorithm doesn't exist - throw an
1571                 // NTLMEngineException!
1572                 throw new NTLMEngineException(
1573                         "Error getting md5 message digest implementation: " + ex.getMessage(), ex);
1574             }
1575 
1576             // Initialize the pad buffers with the key
1577             ipad = new byte[64];
1578             opad = new byte[64];
1579 
1580             int keyLength = key.length;
1581             if (keyLength > 64) {
1582                 // Use MD5 of the key instead, as described in RFC 2104
1583                 md5.update(key);
1584                 key = md5.digest();
1585                 keyLength = key.length;
1586             }
1587             int i = 0;
1588             while (i < keyLength) {
1589                 ipad[i] = (byte) (key[i] ^ (byte) 0x36);
1590                 opad[i] = (byte) (key[i] ^ (byte) 0x5c);
1591                 i++;
1592             }
1593             while (i < 64) {
1594                 ipad[i] = (byte) 0x36;
1595                 opad[i] = (byte) 0x5c;
1596                 i++;
1597             }
1598 
1599             // Very important: update the digest with the ipad buffer
1600             md5.reset();
1601             md5.update(ipad);
1602 
1603         }
1604 
1605         /** Grab the current digest. This is the "answer". */
1606         byte[] getOutput() {
1607             final byte[] digest = md5.digest();
1608             md5.update(opad);
1609             return md5.digest(digest);
1610         }
1611 
1612         /** Update by adding a complete array */
1613         void update(final byte[] input) {
1614             md5.update(input);
1615         }
1616 
1617         /** Update the algorithm */
1618         void update(final byte[] input, final int offset, final int length) {
1619             md5.update(input, offset, length);
1620         }
1621 
1622     }
1623 
1624     @Override
1625     public String generateType1Msg(
1626             final String domain,
1627             final String workstation) throws NTLMEngineException {
1628         return getType1Message(workstation, domain);
1629     }
1630 
1631     @Override
1632     public String generateType3Msg(
1633             final String username,
1634             final String password,
1635             final String domain,
1636             final String workstation,
1637             final String challenge) throws NTLMEngineException {
1638         final Type2Message t2m = new Type2Message(challenge);
1639         return getType3Message(
1640                 username,
1641                 password,
1642                 workstation,
1643                 domain,
1644                 t2m.getChallenge(),
1645                 t2m.getFlags(),
1646                 t2m.getTarget(),
1647                 t2m.getTargetInfo());
1648     }
1649 
1650 }