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