Source Code Cross Referenced for NTLM.java in  » Web-Crawler » JoBo » com » luigidragone » net » ntlm » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Crawler » JoBo » com.luigidragone.net.ntlm 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    This program is free software; you can redistribute it and/or modify
003:         *    it under the terms of the GNU General Public License as published by
004:         *    the Free Software Foundation; either version 2 of the License, or
005:         *    (at your option) any later version.
006:         *
007:         *    This program is distributed in the hope that it will be useful,
008:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
009:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
010:         *    GNU General Public License for more details.
011:         *
012:         *    You should have received a copy of the GNU General Public License
013:         *    along with this program; if not, write to the Free Software
014:         *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
015:         */
016:
017:        /*
018:         *    NTLM.java
019:         *    Copyright (C) 2002 Luigi Dragone
020:         *
021:         */
022:
023:        package com.luigidragone.net.ntlm;
024:
025:        import java.security.*;
026:        import java.security.spec.*;
027:        import javax.crypto.*;
028:        import javax.crypto.spec.*;
029:        import java.io.*;
030:
031:        /**
032:         * <p>
033:         * This class implements the Microsoft NTLM authentication protocol.
034:         * </p>
035:         * <p>
036:         * NTLM is a Microsoft proprietary network authentication protocol used in many
037:         * situations (e.g. by the Microsoft Proxy Server to authenticate a browser).
038:         * </p>
039:         * <p>
040:         * It requires a JCE compatible MD4 hash algorithm implementation and
041:         * a DES with no-padding ECB cipher to compute the requested value. <br>
042:         * An open source JCE compatible library is Cryptix JCE and it is available
043:         * <a href="http://www.cryptix.org/">here</a>. We are assuming that the JCE provider
044:         * is correctly installed and configured. Notice that the Sun JCE implementation
045:         * proviedes the DES cipher but doesn't provide the MD4 hashing.
046:         * </p>
047:         * To perform an authentication the following information are needed:
048:         * <ul>
049:         * <li>the host name (with its own domain);</li>
050:         * <li>the user name (with its own domain);</li>
051:         * <li>the user password.</li>
052:         * </ul>
053:         * Alternatively, the user password can be replaced with its Lan Manager and
054:         * NT hashed versions. On a Windows system these data can be collected in the
055:         * registry, otherwise they can be extracted from a SAMBA password file.<br>
056:         * Notice that the host and user domain could not be the same.
057:         * </p>
058:         * <p>
059:         * To start an NTLM authentication procedure (e.g. with a proxy server) build a
060:         * request message calling {@link #formatRequest(String, String) formatRequest}
061:         * and send it to the server.<br>
062:         * Once the challenge packet has been correctly received extract from it the nonce
063:         * with {@link #getNonce(byte[]) getNonce} function and use it to compute the
064:         * reply and build the response message with
065:         * {@link #formatResponse(String, String, String, byte[], byte[], byte[]) formatResponse}
066:         * method and send it back to the server.<br>
067:         * Repeat the previous steps until the server authenticates the client's identity
068:         * or a large number of retries has been made. The check of a successful authentication
069:         * is protocol specific (e.g. code 200 in HTTP), thus it is not performed by this component.
070:         * </p>
071:         * <p>
072:         * We want to access to the page <code>http://www.server.com/page.html</code>
073:         * through an NTLM proxy <code>proxy.domain.com</code> that accepts connection on
074:         * port 80.<br>
075:         * We access to proxy from host <code>HOSTDOMAIN\\HOST<code> with the user
076:         * <code>USERDOMAIN\\user</code> (password <code>"1234567890"</code>).<br>
077: * As first step we open a socket connection to proxy server and set up the
078: * required object. Notice that we use a keep-alive connection, because NTLM
079: * authentication is connection based and the connection must be alive through the
080: * whole process.<br>
081: * <pre>
082: *     Socket s = new Socket("proxy.domain.com", 80);
083: *     s.setKeepAlive(true);
084: *     InputStream is = s.getInputStream();
085: *     OutputStream os = s.getOutputStream();
086: *     BufferedReader r = new BufferedReader(new InputStreamReader(is));
087: *     BufferedWriter w = new BufferedWriter(new OutputStreamWriter(os));
088: *
089: *     String host = "HOST";
090: *     String hostDomain = "HOSTDOMAIN";
091: *     String user = "user";
092: *     String userDomain = "USERDOMAIN";
093: *     String password = "1234567890";
094: * </pre>
095: * Then, we format a request message and send it in a HTTP compliant GET message.<br>
096: * <pre>
097: *     byte[] fstMsg = NTLM.formatRequest(host, hostDomain);
098: *     byte[] fstMsg64 = Codecs.base64Encode(fstMsg);
099: *     System.out.println("NTLM Request Packet: " + new String(fstMsg64));
100: *
101: *     w.write("GET http://www.server.com/page.html HTTP/1.0\n");
102: *     w.write("Host: www.server.com\n");
103: *     w.write("Proxy-Connection: Keep-Alive\n");
104: *     w.write("Proxy-Authorization: NTLM " + new String(fstMsg64) + "\n\n");
105: *     w.flush();
106: *     System.out.println("First Message Sent");
107: * </pre>
108: * We wait for the server response and we parse it to extract the nonce.<br>
109: * <pre>
110: *     String resp = "";
111: *     int contentLength = 0;
112: *     while((line = r.readLine()) != null)
113: *       if(line.length() == 0)
114: *         break;
115: *       if(line.startsWith("Content-Length"))
116: *         contentLength = Integer.parseInt(line.substring(line.indexOf(":") + 1).trim());
117: *       else if(line.startsWith("Proxy-Authenticate"))
118: *         resp = line.substring(line.indexOf(":") + 1).trim();
119: *     r.skip(contentLength);
120: *     System.out.println("Second Message Received");
121: *     System.out.println("Content Length: " + contentLength);
122: *     System.out.println("Proxy-Authenticate: " + resp);
123: *     resp = resp.substring(resp.indexOf(" ")).trim();
124: *     System.out.println("NTLM Chellange Packet: " + resp);
125: *     resp = Codecs.base64Decode(resp);
126: *     byte[] sndMsg = resp.getBytes();
127: *     byte[] nonce = NTLM.getNonce(sndMsg);
128: * </pre>
129: * With the nonce collected in the previous step we create a response message.<br>
130: * <pre>
131: *     byte[] trdMsg = NTLM.formatResponse(host, user, userDomain,
132: *     	NTLM.computeLMPassword(password), NTLM.computeNTPassword(password),
133: *     	nonce);
134: *     System.out.println(trdMsg.length);
135: *     byte[] trdMsg64 = Codecs.base64Encode(trdMsg);
136: *     System.out.println("NTLM Response Packet: " + new String(trdMsg64));
137: * </pre>
138: * We sent the message to the server.<br>
139: * <pre>
140: *     w.write("GET http://www.server.com/page.html HTTP/1.0\n");
141: *     w.write("Proxy-Connection: Keep-Alive\n");
142: *     w.write("Host: www.server.com\n");
143: *     w.write("Proxy-Authorization: NTLM " + new String(trdMsg64) + "\n\n");
144: *     w.flush();
145: *     System.out.println("Third Message Sent");
146: * </pre>
147: * Finally we wait the server reply.<br>
148: * <pre>
149: *     System.out.println("Server response: " + r.readLine());
150: * </pre>
151: * If the reply is like <code>"HTTP/1.0 200 OK"</code> it has worked fine, else
152: * the server response is containing a new nonce.
153: * </p>
154: * <p>
155: * Notice that despite the computing of hashed passwords and of nonce response is
156: * exactly the same of the SMB authentication protocol, the message format is slightly
157: * different. <br>
158: * Therefore, the methods {@link #computeLMPassword(String) computeLMPassword},
159: * {@link #computeNTPassword(String) computeNTPassword} and
160: * {@link #computeNTLMResponse(byte[], byte[], byte[], byte[], byte[]) computeNTLMResponse}
161: * can be used to perform a SMB authentication too.
162: * </p>
163: * <p>
164: * This implementation is based on:
165: * <ul>
166: * <li>the reverse engineering of the NTLM protocol made by Ronald Tschal&auml;r
167: * and available <a href="http://www.innovation.ch/java/ntlm.html">here</a>;</li>
168: * <li>the documentation about NTLM provided with <a href="http://www.atstake.com/research/lc3/">
169: * L0phtCrack 1.5</a>;</li>
170: * <li>the &quot;Handbook of Applied Cryptography&quot;, freely available
171: * <a href="http://www.cacr.math.uwaterloo.ca/hac/">here</a>;</li>
172: * <li>the C source code of NTLM library in the <a href="http://www.samba.org/">
173: * SAMBA Project</a>.</li>
174: * </ul>
175: * Nevertheless, because there isn't any official protocol specification publicly
176: * available there is any warranty that code works correctly and that it is
177: * conforming to Microsoft NTLM protocol.
178: * </p>
179: * <p>
180: * For implementation reasons only the public members perform argument consistency
181: * checks. The public members also catch and hide every exceptions that can be
182: * throwed (even though interfaces specify otherwise).
183: * </p>
184: *
185: * @author Luigi Dragone (<a href="mailto:luigi@luigidragone.com">luigi@luigidragone.com</a>)
186: *
187: * @version 1.0.1
188: *
189: * @see <a href="http://www.innovation.ch/java/ntlm.html">NTLM Authentication Scheme for HTTP</a>
190: * @see <a href="ftp://ftp.samba.org/pub/samba/docs/textdocs/ENCRYPTION.txt">LanMan and NT Password Encryption in Samba 2.x</a>
191: * @see <a href="http://www.cacr.math.uwaterloo.ca/hac/">&quot;Handbook of Applied Cryptography&quot;</a>
192: * @see <a href="http://java.sun.com/products/jce/">JCE</a>
193: * @see <a href="http://www.cryptix.org/">Cryptix</a>
194: */
195:        public class NTLM {
196:            protected NTLM() {
197:            }
198:
199:            /**
200:             * The magic number used to compute the Lan Manager hashed password.
201:             */
202:            protected static final byte[] MAGIC = new byte[] { 0x4B, 0x47,
203:                    0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
204:
205:            /**
206:             * <p>
207:             * Converts an unsigned byte to an unsigned integer.
208:             * </p>
209:             * <p>
210:             * Notice that Java bytes are always signed, but the cryptographic algorithms
211:             * rely on unsigned ones, that can be simulated in this way.<br>
212:             * A bit mask is employed to prevent that the signum bit is extended to MSBs.
213:             * </p>
214:             */
215:            protected static int unsignedByteToInt(byte b) {
216:                return (int) b & 0xFF;
217:            }
218:
219:            protected static byte getLoByte(char c) {
220:                return (byte) c;
221:            }
222:
223:            protected static byte getHiByte(char c) {
224:                return (byte) ((c >>> 8) & 0xFF);
225:            }
226:
227:            protected static short swapBytes(short s) {
228:                return (short) (((s << 8) & 0xFF00) | ((s >>> 8) & 0x00FF));
229:            }
230:
231:            /**
232:             * <p>
233:             * Computes an odd DES key from 56 bits represented as a 7-bytes array.
234:             * </p>
235:             * <p>
236:             * Keeps elements from index <code>offset</code> to index <code>offset + 7</code> of
237:             * supplied array.
238:             * </p>
239:             *
240:             * @param keyData a byte array containing the 56 bits used to compute the DES key
241:             * @param offset the offset of the first element of the 56-bits key data
242:             *
243:             * @return the odd DES key generated
244:             *
245:             * @exception InvalidKeyException
246:             * @exception NoSuchAlgorithmException
247:             * @exception InvalidKeySpecException
248:             */
249:            protected static Key computeDESKey(byte[] keyData, int offset)
250:                    throws InvalidKeyException, NoSuchAlgorithmException,
251:                    InvalidKeySpecException {
252:                byte[] desKeyData = new byte[8];
253:                int[] k = new int[7];
254:
255:                for (int i = 0; i < 7; i++)
256:                    k[i] = unsignedByteToInt(keyData[offset + i]);
257:
258:                desKeyData[0] = (byte) (k[0] >>> 1);
259:                desKeyData[1] = (byte) (((k[0] & 0x01) << 6) | (k[1] >>> 2));
260:                desKeyData[2] = (byte) (((k[1] & 0x03) << 5) | (k[2] >>> 3));
261:                desKeyData[3] = (byte) (((k[2] & 0x07) << 4) | (k[3] >>> 4));
262:                desKeyData[4] = (byte) (((k[3] & 0x0F) << 3) | (k[4] >>> 5));
263:                desKeyData[5] = (byte) (((k[4] & 0x1F) << 2) | (k[5] >>> 6));
264:                desKeyData[6] = (byte) (((k[5] & 0x3F) << 1) | (k[6] >>> 7));
265:                desKeyData[7] = (byte) (k[6] & 0x7F);
266:
267:                for (int i = 0; i < 8; i++)
268:                    desKeyData[i] = (byte) (unsignedByteToInt(desKeyData[i]) << 1);
269:
270:                KeySpec desKeySpec = new DESKeySpec(desKeyData);
271:                SecretKeyFactory keyFactory = SecretKeyFactory
272:                        .getInstance("DES");
273:                SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
274:                return secretKey;
275:            }
276:
277:            /**
278:             * Encrypts the 8-bytes plain text three times with the 3 56-bits DES keys and
279:             * puts the result in a 24-bytes array.
280:             *
281:             * @param keys a 21-bytes array containing 3 56-bits DES keys
282:             * @param plaintext a 8-bytes array to be encrypted
283:             *
284:             * @return a 24-bytes array containing the plaintext DES encrypted with the supplied keys
285:             *
286:             * @exception InvalidKeyException
287:             * @exception NoSuchAlgorithmException
288:             * @exception javax.crypto.NoSuchPaddingException
289:             * @exception InvalidKeySpecException
290:             * @exception BadPaddingException
291:             * @exception IllegalBlockSizeException
292:             * @exception ShortBufferException
293:             */
294:            protected static byte[] encrypt(byte[] keys, byte[] plaintext)
295:                    throws InvalidKeyException, NoSuchAlgorithmException,
296:                    javax.crypto.NoSuchPaddingException,
297:                    InvalidKeySpecException, BadPaddingException,
298:                    IllegalBlockSizeException, ShortBufferException {
299:                byte[] ciphertext = new byte[24];
300:                Cipher c = Cipher.getInstance("DES/ECB/NoPadding");
301:                Key k = computeDESKey(keys, 0);
302:                c.init(Cipher.ENCRYPT_MODE, k);
303:                c.doFinal(plaintext, 0, 8, ciphertext, 0);
304:                k = computeDESKey(keys, 7);
305:                c.init(Cipher.ENCRYPT_MODE, k);
306:                c.doFinal(plaintext, 0, 8, ciphertext, 8);
307:                k = computeDESKey(keys, 14);
308:                c.init(Cipher.ENCRYPT_MODE, k);
309:                c.doFinal(plaintext, 0, 8, ciphertext, 16);
310:                return ciphertext;
311:            }
312:
313:            /**
314:             * Computes the Lan Manager hashed version of a password.
315:             *
316:             * @param password the user password
317:             *
318:             * @return the Lan Manager hashed version of the password in a 16-bytes array
319:             *
320:             * @exception IllegalArgumentException if the supplied password is null
321:             * @exception javax.crypto.NoSuchPaddingException if there isn't any suitable padding method
322:             * @exception NoSuchAlgorithmException if there isn't any suitable cipher algorithm
323:             */
324:            public static byte[] computeLMPassword(String password)
325:                    throws IllegalArgumentException, NoSuchPaddingException,
326:                    NoSuchAlgorithmException {
327:                if (password == null)
328:                    throw new IllegalArgumentException(
329:                            "password : null value not allowed");
330:                try {
331:                    //Gets the first 14-bytes of the ASCII upper cased password
332:                    int len = password.length();
333:                    if (len > 14)
334:                        len = 14;
335:                    Cipher c = Cipher.getInstance("DES/ECB/NoPadding");
336:
337:                    byte[] lm_pw = new byte[14];
338:                    byte[] bytes = password.toUpperCase().getBytes();
339:                    int i;
340:                    for (i = 0; i < len; i++)
341:                        lm_pw[i] = bytes[i];
342:                    for (; i < 14; i++)
343:                        lm_pw[i] = 0;
344:
345:                    byte[] lm_hpw = new byte[16];
346:                    //Builds a first DES key with its first 7 bytes
347:                    Key k = computeDESKey(lm_pw, 0);
348:                    c.init(Cipher.ENCRYPT_MODE, k);
349:                    //Hashes the MAGIC number with this key into the first 8 bytes of the result
350:                    c.doFinal(MAGIC, 0, 8, lm_hpw, 0);
351:
352:                    //Repeats the work with the last 7 bytes to gets the last 8 bytes of the result
353:                    k = computeDESKey(lm_pw, 7);
354:                    c.init(Cipher.ENCRYPT_MODE, k);
355:                    c.doFinal(MAGIC, 0, 8, lm_hpw, 8);
356:
357:                    return lm_hpw;
358:                } catch (InvalidKeySpecException ex) {
359:                    return null;
360:                } catch (InvalidKeyException ex) {
361:                    return null;
362:                } catch (BadPaddingException ex) {
363:                    return null;
364:                } catch (IllegalBlockSizeException ex) {
365:                    return null;
366:                } catch (ShortBufferException ex) {
367:                    return null;
368:                }
369:            }
370:
371:            /**
372:             * Computes the NT hashed version of a password.
373:             *
374:             * @param password the user password
375:             *
376:             * @return the NT hashed version of the password in a 16-bytes array
377:             *
378:             * @exception IllegalArgumentException if the supplied password is null
379:             * @exception NoSuchAlgorithmException if there isn't any suitable cipher algorithm
380:             */
381:            public static byte[] computeNTPassword(String password)
382:                    throws IllegalArgumentException, NoSuchAlgorithmException {
383:                if (password == null)
384:                    throw new IllegalArgumentException(
385:                            "password : null value not allowed");
386:                //Gets the first 14-bytes of the UNICODE password
387:                int len = password.length();
388:                if (len > 14)
389:                    len = 14;
390:                byte[] nt_pw = new byte[2 * len];
391:                for (int i = 0; i < len; i++) {
392:                    char ch = password.charAt(i);
393:                    nt_pw[2 * i] = getLoByte(ch);
394:                    nt_pw[2 * i + 1] = getHiByte(ch);
395:                }
396:
397:                //Return its MD4 digest as the hashed version
398:                MessageDigest md = MessageDigest.getInstance("MD4");
399:                return md.digest(nt_pw);
400:            }
401:
402:            /**
403:             * <p>
404:             * Computes the NTLM response to the nonce based on the supplied hashed passwords.
405:             * </p>
406:             * <p>
407:             * If the hashed password are not available they can be computed from the cleartext password
408:             * by the means of {@link #computeLMPassword(String) computeLMPassword} and
409:             * {@link #computeNTPassword(String) computeNTPassword} methods.
410:             * </p>
411:             *
412:             * @param lmPassword a 16-bytes array containing the Lan Manager hashed password
413:             * @param ntPassword a 16-bytes array containing the Lan Manager hashed password
414:             * @param nonce a 8-bytes array representing the server's nonce
415:             * @param lmResponse a 24-bytes array that will contain the Lan Manager response after the method invocation
416:             * @param ntResponse a 24-bytes array that will contain the NT response after the method invocation
417:             *
418:             * @exception IllegalArgumentException if a parameter has an illegal size
419:             * @exception javax.crypto.NoSuchPaddingException if there isn't any suitable padding method
420:             * @exception NoSuchAlgorithmException if there isn't any suitable cipher algorithm
421:             */
422:            public static void computeNTLMResponse(byte[] lmPassword,
423:                    byte[] ntPassword, byte[] nonce, byte[] lmResponse,
424:                    byte[] ntResponse) throws IllegalArgumentException,
425:                    NoSuchPaddingException, NoSuchAlgorithmException {
426:                if (lmPassword.length != 16)
427:                    throw new IllegalArgumentException(
428:                            "lmPassword : illegal size");
429:                if (ntPassword.length != 16)
430:                    throw new IllegalArgumentException(
431:                            "ntPassword : illegal size");
432:                if (nonce.length != 8)
433:                    throw new IllegalArgumentException("nonce : illegal size");
434:                if (lmResponse.length != 24)
435:                    throw new IllegalArgumentException(
436:                            "lmResponse : illegal size");
437:                if (ntResponse.length != 24)
438:                    throw new IllegalArgumentException(
439:                            "ntResponse : illegal size");
440:                try {
441:                    //Puts the hashed passwords into 21-bytes arrays with trailing 0s
442:                    byte[] lmHPw = new byte[21];
443:                    byte[] ntHPw = new byte[21];
444:                    System.arraycopy(lmPassword, 0, lmHPw, 0, 16);
445:                    System.arraycopy(ntPassword, 0, ntHPw, 0, 16);
446:                    for (int i = 16; i < 21; i++) {
447:                        lmHPw[i] = 0;
448:                        ntHPw[i] = 0;
449:                    }
450:                    //Encrypts the nonce with the padded hashed passwords to compute the responses
451:                    System.arraycopy(encrypt(lmHPw, nonce), 0, lmResponse, 0,
452:                            24);
453:                    System.arraycopy(encrypt(ntHPw, nonce), 0, ntResponse, 0,
454:                            24);
455:                } catch (ShortBufferException ex) {
456:                } catch (IllegalBlockSizeException ex) {
457:                } catch (BadPaddingException ex) {
458:                } catch (InvalidKeySpecException ex) {
459:                } catch (InvalidKeyException ex) {
460:                }
461:            }
462:
463:            /**
464:             * <p>
465:             * Builds a request message for the host of the specified domain that can be send
466:             * to the server to start the NTLM protocol.
467:             * </p>
468:             * <p>
469:             * The returned message should be encoded according to protocol specific rules
470:             * (e.g. base 64 encoding).<br>
471:             * The message format is discussed <a href="http://www.innovation.ch/java/ntlm.html">here</a>.
472:             * </p>
473:             *
474:             * @param host the name of the host that is authenticating
475:             * @param hostDomain the name of the domain to which the host belongs
476:             *
477:             * @return the request message to send to server to open an authentication procedure
478:             *
479:             * @exception IOException if an error occurs during the message formatting
480:             *
481:             * @see <a href="http://www.innovation.ch/java/ntlm.html">NTLM Authentication Scheme for HTTP</a>
482:             *
483:             */
484:            public static byte[] formatRequest(String host, String hostDomain)
485:                    throws IOException {
486:                hostDomain = hostDomain.toUpperCase();
487:                host = host.toUpperCase();
488:                short domainLen = (short) hostDomain.length();
489:                short hostLen = (short) host.length();
490:                short hostOff = 0x20;
491:                short domainOff = (short) (hostOff + hostLen);
492:                ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
493:                DataOutputStream dataOut = new DataOutputStream(os);
494:                dataOut.writeBytes("NTLMSSP\0");
495:                dataOut.writeByte(0x01);
496:                dataOut.writeByte(0x00);
497:                dataOut.writeByte(0x00);
498:                dataOut.writeByte(0x00);
499:                dataOut.writeShort(swapBytes((short) 0xb203));
500:                dataOut.writeShort(0x0000);
501:                dataOut.writeShort(swapBytes(domainLen));
502:                dataOut.writeShort(swapBytes(domainLen));
503:                dataOut.writeShort(swapBytes(domainOff));
504:                dataOut.writeShort(0x0000);
505:                dataOut.writeShort(swapBytes(hostLen));
506:                dataOut.writeShort(swapBytes(hostLen));
507:                dataOut.writeShort(swapBytes(hostOff));
508:                dataOut.writeShort(0x0000);
509:                dataOut.write(host.getBytes());
510:                dataOut.write(hostDomain.getBytes());
511:                dataOut.flush();
512:                return os.toByteArray();
513:            }
514:
515:            /**
516:             * <p>
517:             * Extracts from the server challenge response the nonce required to perform
518:             * the authentication.
519:             * </p>
520:             * <p>
521:             * The received message should be decoded according to protocol specific rules
522:             * (e.g. base 64 encoding).<br>
523:             * The message format is discussed <a href="http://www.innovation.ch/java/ntlm.html">here</a>.
524:             * </p>
525:             *
526:             * @param msg a byte array containing the server challenge message
527:             *
528:             * @exception IllegalArgumentException if a parameter has an illegal size
529:             *
530:             * @see <a href="http://www.innovation.ch/java/ntlm.html">NTLM Authentication Scheme for HTTP</a>
531:             */
532:            public static byte[] getNonce(byte[] msg)
533:                    throws IllegalArgumentException {
534:                if (msg.length < 32)
535:                    throw new IllegalArgumentException("msg : illegal size");
536:                byte[] nonce = new byte[8];
537:                System.arraycopy(msg, 24, nonce, 0, 8);
538:                return nonce;
539:            }
540:
541:            /**
542:             * <p>
543:             * Builds the nonce response message.
544:             * </p>
545:             * <p>It requires the Lan Manager and NT hashed
546:             * version of user password, that can be computed from the cleartext version by
547:             * {@link #computeNTPassword(String) computeNTPassword} and
548:             * {@link #computeNTLMResponse(byte[], byte[], byte[], byte[], byte[]) computeNTLMResponse},
549:             * and the nonce obtained from the server by {@link #getNonce(byte[]) getNonce}.<br>
550:             * The returned message should be encoded according to protocol specific rules
551:             * (e.g. base 64 encoding).<br>
552:             * The message format is discussed <a href="http://www.innovation.ch/java/ntlm.html">here</a>.
553:             * </p>
554:             *
555:             * @param host the name of the host that is authenticating
556:             * @param user the name of the user
557:             * @param userDomain the name of the domain to which the user belongs
558:             * @param lmPassword a 16-bytes array containing the Lan Manager hashed password
559:             * @param ntPassword a 16-bytes array containing the NT hashed password
560:             * @param nonce a 8-byte array containing the nonce sent by server to reply to the request message
561:             *
562:             * @return the challenge response message to send to server to complete the authentication procedure
563:             *
564:             * @exception IOException if an error occurs during the message formatting
565:             * @exception IllegalArgumentException if a parameter has an illegal size
566:             * @exception javax.crypto.NoSuchPaddingException if there isn't any suitable padding method
567:             * @exception NoSuchAlgorithmException if there isn't any suitable cipher algorithm
568:             *
569:             * @see <a href="http://www.innovation.ch/java/ntlm.html">NTLM Authentication Scheme for HTTP</a>
570:             */
571:            public static byte[] formatResponse(String host, String user,
572:                    String userDomain, byte[] lmPassword, byte[] ntPassword,
573:                    byte[] nonce) throws IllegalArgumentException, IOException,
574:                    NoSuchAlgorithmException, NoSuchPaddingException {
575:                if (host == null)
576:                    throw new IllegalArgumentException(
577:                            "host : null value not allowed");
578:                if (user == null)
579:                    throw new IllegalArgumentException(
580:                            "user : null value not allowed");
581:                if (userDomain == null)
582:                    throw new IllegalArgumentException(
583:                            "userDomain : null value not allowed");
584:                if (lmPassword == null)
585:                    throw new IllegalArgumentException(
586:                            "lmPassword : null value not allowed");
587:                if (ntPassword == null)
588:                    throw new IllegalArgumentException(
589:                            "ntPassword : null value not allowed");
590:                if (nonce == null)
591:                    throw new IllegalArgumentException(
592:                            "nonce : null value not allowed");
593:                if (lmPassword.length != 16)
594:                    throw new IllegalArgumentException(
595:                            "lmPassword : illegal size");
596:                if (ntPassword.length != 16)
597:                    throw new IllegalArgumentException(
598:                            "ntPassword : illegal size");
599:                if (nonce.length != 8)
600:                    throw new IllegalArgumentException("nonce : illegal size");
601:
602:                byte[] lmResponse = new byte[24];
603:                byte[] ntResponse = new byte[24];
604:
605:                computeNTLMResponse(lmPassword, ntPassword, nonce, lmResponse,
606:                        ntResponse);
607:
608:                userDomain = userDomain.toUpperCase();
609:                host = host.toUpperCase();
610:                short lmRespLen = (short) 0x18;
611:                short ntRespLen = (short) 0x18;
612:                short domainLen = (short) (2 * userDomain.length());
613:                short hostLen = (short) (2 * host.length());
614:                short userLen = (short) (2 * user.length());
615:                short domainOff = (short) 0x40;
616:                short userOff = (short) (domainOff + domainLen);
617:                short hostOff = (short) (userOff + userLen);
618:                short lmRespOff = (short) (hostOff + hostLen);
619:                short ntRespOff = (short) (lmRespOff + lmRespLen);
620:                short msgLen = (short) (ntRespOff + ntRespLen);
621:                ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
622:                DataOutputStream dataOut = new DataOutputStream(os);
623:                dataOut.writeBytes("NTLMSSP\0");
624:                dataOut.writeByte(0x03);
625:                dataOut.writeByte(0x00);
626:                dataOut.writeByte(0x00);
627:                dataOut.writeByte(0x00);
628:                dataOut.writeShort(swapBytes(lmRespLen));
629:                dataOut.writeShort(swapBytes(lmRespLen));
630:                dataOut.writeShort(swapBytes(lmRespOff));
631:                dataOut.writeShort(0x0000);
632:                dataOut.writeShort(swapBytes(ntRespLen));
633:                dataOut.writeShort(swapBytes(ntRespLen));
634:                dataOut.writeShort(swapBytes(ntRespOff));
635:                dataOut.writeShort(0x0000);
636:                dataOut.writeShort(swapBytes(domainLen));
637:                dataOut.writeShort(swapBytes(domainLen));
638:                dataOut.writeShort(swapBytes(domainOff));
639:                dataOut.writeShort(0x0000);
640:                dataOut.writeShort(swapBytes(userLen));
641:                dataOut.writeShort(swapBytes(userLen));
642:                dataOut.writeShort(swapBytes(userOff));
643:                dataOut.writeShort(0x0000);
644:                dataOut.writeShort(swapBytes(hostLen));
645:                dataOut.writeShort(swapBytes(hostLen));
646:                dataOut.writeShort(swapBytes(hostOff));
647:                dataOut.writeShort(0x0000);
648:                dataOut.writeInt(0x00000000);
649:                dataOut.writeShort(swapBytes(msgLen));
650:                dataOut.writeShort(0x0000);
651:                dataOut.writeShort(0x0000); //    dataOut.writeShort(swapBytes((short)0x8201));
652:                dataOut.writeShort(0x0000);
653:
654:                for (int i = 0; i < userDomain.length(); i++)
655:                    dataOut.writeShort(swapBytes((short) userDomain.charAt(i)));
656:                for (int i = 0; i < user.length(); i++)
657:                    dataOut.writeShort(swapBytes((short) user.charAt(i)));
658:                for (int i = 0; i < host.length(); i++)
659:                    dataOut.writeShort(swapBytes((short) host.charAt(i)));
660:                dataOut.write(lmResponse);
661:                dataOut.write(ntResponse);
662:                dataOut.flush();
663:                return os.toByteArray();
664:            }
665:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.