Source Code Cross Referenced for NTLM.java in  » Net » Apache-common-HttpClient » org » apache » commons » httpclient » auth » 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 » Net » Apache common HttpClient » org.apache.commons.httpclient.auth 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/auth/NTLM.java,v 1.11 2004/05/13 04:02:00 mbecke Exp $
003:         * $Revision: 480424 $
004:         * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
005:         *
006:         * ====================================================================
007:         *
008:         *  Licensed to the Apache Software Foundation (ASF) under one or more
009:         *  contributor license agreements.  See the NOTICE file distributed with
010:         *  this work for additional information regarding copyright ownership.
011:         *  The ASF licenses this file to You under the Apache License, Version 2.0
012:         *  (the "License"); you may not use this file except in compliance with
013:         *  the License.  You may obtain a copy of the License at
014:         *
015:         *      http://www.apache.org/licenses/LICENSE-2.0
016:         *
017:         *  Unless required by applicable law or agreed to in writing, software
018:         *  distributed under the License is distributed on an "AS IS" BASIS,
019:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020:         *  See the License for the specific language governing permissions and
021:         *  limitations under the License.
022:         * ====================================================================
023:         *
024:         * This software consists of voluntary contributions made by many
025:         * individuals on behalf of the Apache Software Foundation.  For more
026:         * information on the Apache Software Foundation, please see
027:         * <http://www.apache.org/>.
028:         *
029:         */
030:
031:        package org.apache.commons.httpclient.auth;
032:
033:        import java.security.InvalidKeyException;
034:        import java.security.NoSuchAlgorithmException;
035:
036:        import javax.crypto.BadPaddingException;
037:        import javax.crypto.Cipher;
038:        import javax.crypto.IllegalBlockSizeException;
039:        import javax.crypto.NoSuchPaddingException;
040:        import javax.crypto.spec.SecretKeySpec;
041:
042:        import org.apache.commons.codec.binary.Base64;
043:        import org.apache.commons.httpclient.util.EncodingUtil;
044:
045:        /**
046:         * Provides an implementation of the NTLM authentication protocol.
047:         * <p>
048:         * This class provides methods for generating authentication
049:         * challenge responses for the NTLM authentication protocol.  The NTLM
050:         * protocol is a proprietary Microsoft protocol and as such no RFC
051:         * exists for it.  This class is based upon the reverse engineering
052:         * efforts of a wide range of people.</p>
053:         *
054:         * <p>Please note that an implementation of JCE must be correctly installed and configured when
055:         * using NTLM support.</p>
056:         *
057:         * <p>This class should not be used externally to HttpClient as it's API is specifically
058:         * designed to work with HttpClient's use case, in particular it's connection management.</p>
059:         *
060:         * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
061:         * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
062:         * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
063:         *
064:         * @version $Revision: 480424 $ $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
065:         * @since 3.0
066:         */
067:        final class NTLM {
068:
069:            /** Character encoding */
070:            public static final String DEFAULT_CHARSET = "ASCII";
071:
072:            /** The current response */
073:            private byte[] currentResponse;
074:
075:            /** The current position */
076:            private int currentPosition = 0;
077:
078:            /** The character set to use for encoding the credentials */
079:            private String credentialCharset = DEFAULT_CHARSET;
080:
081:            /**
082:             * Returns the response for the given message.
083:             *
084:             * @param message the message that was received from the server.
085:             * @param username the username to authenticate with.
086:             * @param password the password to authenticate with.
087:             * @param host The host.
088:             * @param domain the NT domain to authenticate in.
089:             * @return The response.
090:             * @throws HttpException If the messages cannot be retrieved.
091:             */
092:            public final String getResponseFor(String message, String username,
093:                    String password, String host, String domain)
094:                    throws AuthenticationException {
095:
096:                final String response;
097:                if (message == null || message.trim().equals("")) {
098:                    response = getType1Message(host, domain);
099:                } else {
100:                    response = getType3Message(username, password, host,
101:                            domain, parseType2Message(message));
102:                }
103:                return response;
104:            }
105:
106:            /**
107:             * Return the cipher for the specified key.
108:             * @param key The key.
109:             * @return Cipher The cipher.
110:             * @throws AuthenticationException If the cipher cannot be retrieved.
111:             */
112:            private Cipher getCipher(byte[] key) throws AuthenticationException {
113:                try {
114:                    final Cipher ecipher = Cipher
115:                            .getInstance("DES/ECB/NoPadding");
116:                    key = setupKey(key);
117:                    ecipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key,
118:                            "DES"));
119:                    return ecipher;
120:                } catch (NoSuchAlgorithmException e) {
121:                    throw new AuthenticationException(
122:                            "DES encryption is not available.", e);
123:                } catch (InvalidKeyException e) {
124:                    throw new AuthenticationException(
125:                            "Invalid key for DES encryption.", e);
126:                } catch (NoSuchPaddingException e) {
127:                    throw new AuthenticationException(
128:                            "NoPadding option for DES is not available.", e);
129:                }
130:            }
131:
132:            /** 
133:             * Adds parity bits to the key.
134:             * @param key56 The key
135:             * @return The modified key.
136:             */
137:            private byte[] setupKey(byte[] key56) {
138:                byte[] key = new byte[8];
139:                key[0] = (byte) ((key56[0] >> 1) & 0xff);
140:                key[1] = (byte) ((((key56[0] & 0x01) << 6) | (((key56[1] & 0xff) >> 2) & 0xff)) & 0xff);
141:                key[2] = (byte) ((((key56[1] & 0x03) << 5) | (((key56[2] & 0xff) >> 3) & 0xff)) & 0xff);
142:                key[3] = (byte) ((((key56[2] & 0x07) << 4) | (((key56[3] & 0xff) >> 4) & 0xff)) & 0xff);
143:                key[4] = (byte) ((((key56[3] & 0x0f) << 3) | (((key56[4] & 0xff) >> 5) & 0xff)) & 0xff);
144:                key[5] = (byte) ((((key56[4] & 0x1f) << 2) | (((key56[5] & 0xff) >> 6) & 0xff)) & 0xff);
145:                key[6] = (byte) ((((key56[5] & 0x3f) << 1) | (((key56[6] & 0xff) >> 7) & 0xff)) & 0xff);
146:                key[7] = (byte) (key56[6] & 0x7f);
147:
148:                for (int i = 0; i < key.length; i++) {
149:                    key[i] = (byte) (key[i] << 1);
150:                }
151:                return key;
152:            }
153:
154:            /**
155:             * Encrypt the data.
156:             * @param key The key.
157:             * @param bytes The data
158:             * @return byte[] The encrypted data
159:             * @throws HttpException If {@link Cipher.doFinal(byte[])} fails
160:             */
161:            private byte[] encrypt(byte[] key, byte[] bytes)
162:                    throws AuthenticationException {
163:                Cipher ecipher = getCipher(key);
164:                try {
165:                    byte[] enc = ecipher.doFinal(bytes);
166:                    return enc;
167:                } catch (IllegalBlockSizeException e) {
168:                    throw new AuthenticationException(
169:                            "Invalid block size for DES encryption.", e);
170:                } catch (BadPaddingException e) {
171:                    throw new AuthenticationException(
172:                            "Data not padded correctly for DES encryption.", e);
173:                }
174:            }
175:
176:            /** 
177:             * Prepares the object to create a response of the given length.
178:             * @param length the length of the response to prepare.
179:             */
180:            private void prepareResponse(int length) {
181:                currentResponse = new byte[length];
182:                currentPosition = 0;
183:            }
184:
185:            /** 
186:             * Adds the given byte to the response.
187:             * @param b the byte to add.
188:             */
189:            private void addByte(byte b) {
190:                currentResponse[currentPosition] = b;
191:                currentPosition++;
192:            }
193:
194:            /** 
195:             * Adds the given bytes to the response.
196:             * @param bytes the bytes to add.
197:             */
198:            private void addBytes(byte[] bytes) {
199:                for (int i = 0; i < bytes.length; i++) {
200:                    currentResponse[currentPosition] = bytes[i];
201:                    currentPosition++;
202:                }
203:            }
204:
205:            /** 
206:             * Returns the response that has been generated after shrinking the array if
207:             * required and base64 encodes the response.
208:             * @return The response as above.
209:             */
210:            private String getResponse() {
211:                byte[] resp;
212:                if (currentResponse.length > currentPosition) {
213:                    byte[] tmp = new byte[currentPosition];
214:                    for (int i = 0; i < currentPosition; i++) {
215:                        tmp[i] = currentResponse[i];
216:                    }
217:                    resp = tmp;
218:                } else {
219:                    resp = currentResponse;
220:                }
221:                return EncodingUtil.getAsciiString(Base64.encodeBase64(resp));
222:            }
223:
224:            /**
225:             * Creates the first message (type 1 message) in the NTLM authentication sequence.
226:             * This message includes the user name, domain and host for the authentication session.
227:             *
228:             * @param host the computer name of the host requesting authentication.
229:             * @param domain The domain to authenticate with.
230:             * @return String the message to add to the HTTP request header.
231:             */
232:            public String getType1Message(String host, String domain) {
233:                host = host.toUpperCase();
234:                domain = domain.toUpperCase();
235:                byte[] hostBytes = EncodingUtil.getBytes(host, DEFAULT_CHARSET);
236:                byte[] domainBytes = EncodingUtil.getBytes(domain,
237:                        DEFAULT_CHARSET);
238:
239:                int finalLength = 32 + hostBytes.length + domainBytes.length;
240:                prepareResponse(finalLength);
241:
242:                // The initial id string.
243:                byte[] protocol = EncodingUtil.getBytes("NTLMSSP",
244:                        DEFAULT_CHARSET);
245:                addBytes(protocol);
246:                addByte((byte) 0);
247:
248:                // Type
249:                addByte((byte) 1);
250:                addByte((byte) 0);
251:                addByte((byte) 0);
252:                addByte((byte) 0);
253:
254:                // Flags
255:                addByte((byte) 6);
256:                addByte((byte) 82);
257:                addByte((byte) 0);
258:                addByte((byte) 0);
259:
260:                // Domain length (first time).
261:                int iDomLen = domainBytes.length;
262:                byte[] domLen = convertShort(iDomLen);
263:                addByte(domLen[0]);
264:                addByte(domLen[1]);
265:
266:                // Domain length (second time).
267:                addByte(domLen[0]);
268:                addByte(domLen[1]);
269:
270:                // Domain offset.
271:                byte[] domOff = convertShort(hostBytes.length + 32);
272:                addByte(domOff[0]);
273:                addByte(domOff[1]);
274:                addByte((byte) 0);
275:                addByte((byte) 0);
276:
277:                // Host length (first time).
278:                byte[] hostLen = convertShort(hostBytes.length);
279:                addByte(hostLen[0]);
280:                addByte(hostLen[1]);
281:
282:                // Host length (second time).
283:                addByte(hostLen[0]);
284:                addByte(hostLen[1]);
285:
286:                // Host offset (always 32).
287:                byte[] hostOff = convertShort(32);
288:                addByte(hostOff[0]);
289:                addByte(hostOff[1]);
290:                addByte((byte) 0);
291:                addByte((byte) 0);
292:
293:                // Host String.
294:                addBytes(hostBytes);
295:
296:                // Domain String.
297:                addBytes(domainBytes);
298:
299:                return getResponse();
300:            }
301:
302:            /** 
303:             * Extracts the server nonce out of the given message type 2.
304:             * 
305:             * @param message the String containing the base64 encoded message.
306:             * @return an array of 8 bytes that the server sent to be used when
307:             * hashing the password.
308:             */
309:            public byte[] parseType2Message(String message) {
310:                // Decode the message first.
311:                byte[] msg = Base64.decodeBase64(EncodingUtil.getBytes(message,
312:                        DEFAULT_CHARSET));
313:                byte[] nonce = new byte[8];
314:                // The nonce is the 8 bytes starting from the byte in position 24.
315:                for (int i = 0; i < 8; i++) {
316:                    nonce[i] = msg[i + 24];
317:                }
318:                return nonce;
319:            }
320:
321:            /** 
322:             * Creates the type 3 message using the given server nonce.  The type 3 message includes all the
323:             * information for authentication, host, domain, username and the result of encrypting the
324:             * nonce sent by the server using the user's password as the key.
325:             *
326:             * @param user The user name.  This should not include the domain name.
327:             * @param password The password.
328:             * @param host The host that is originating the authentication request.
329:             * @param domain The domain to authenticate within.
330:             * @param nonce the 8 byte array the server sent.
331:             * @return The type 3 message.
332:             * @throws AuthenticationException If {@encrypt(byte[],byte[])} fails.
333:             */
334:            public String getType3Message(String user, String password,
335:                    String host, String domain, byte[] nonce)
336:                    throws AuthenticationException {
337:
338:                int ntRespLen = 0;
339:                int lmRespLen = 24;
340:                domain = domain.toUpperCase();
341:                host = host.toUpperCase();
342:                user = user.toUpperCase();
343:                byte[] domainBytes = EncodingUtil.getBytes(domain,
344:                        DEFAULT_CHARSET);
345:                byte[] hostBytes = EncodingUtil.getBytes(host, DEFAULT_CHARSET);
346:                byte[] userBytes = EncodingUtil.getBytes(user,
347:                        credentialCharset);
348:                int domainLen = domainBytes.length;
349:                int hostLen = hostBytes.length;
350:                int userLen = userBytes.length;
351:                int finalLength = 64 + ntRespLen + lmRespLen + domainLen
352:                        + userLen + hostLen;
353:                prepareResponse(finalLength);
354:                byte[] ntlmssp = EncodingUtil.getBytes("NTLMSSP",
355:                        DEFAULT_CHARSET);
356:                addBytes(ntlmssp);
357:                addByte((byte) 0);
358:                addByte((byte) 3);
359:                addByte((byte) 0);
360:                addByte((byte) 0);
361:                addByte((byte) 0);
362:
363:                // LM Resp Length (twice)
364:                addBytes(convertShort(24));
365:                addBytes(convertShort(24));
366:
367:                // LM Resp Offset
368:                addBytes(convertShort(finalLength - 24));
369:                addByte((byte) 0);
370:                addByte((byte) 0);
371:
372:                // NT Resp Length (twice)
373:                addBytes(convertShort(0));
374:                addBytes(convertShort(0));
375:
376:                // NT Resp Offset
377:                addBytes(convertShort(finalLength));
378:                addByte((byte) 0);
379:                addByte((byte) 0);
380:
381:                // Domain length (twice)
382:                addBytes(convertShort(domainLen));
383:                addBytes(convertShort(domainLen));
384:
385:                // Domain offset.
386:                addBytes(convertShort(64));
387:                addByte((byte) 0);
388:                addByte((byte) 0);
389:
390:                // User Length (twice)
391:                addBytes(convertShort(userLen));
392:                addBytes(convertShort(userLen));
393:
394:                // User offset
395:                addBytes(convertShort(64 + domainLen));
396:                addByte((byte) 0);
397:                addByte((byte) 0);
398:
399:                // Host length (twice)
400:                addBytes(convertShort(hostLen));
401:                addBytes(convertShort(hostLen));
402:
403:                // Host offset
404:                addBytes(convertShort(64 + domainLen + userLen));
405:
406:                for (int i = 0; i < 6; i++) {
407:                    addByte((byte) 0);
408:                }
409:
410:                // Message length
411:                addBytes(convertShort(finalLength));
412:                addByte((byte) 0);
413:                addByte((byte) 0);
414:
415:                // Flags
416:                addByte((byte) 6);
417:                addByte((byte) 82);
418:                addByte((byte) 0);
419:                addByte((byte) 0);
420:
421:                addBytes(domainBytes);
422:                addBytes(userBytes);
423:                addBytes(hostBytes);
424:                addBytes(hashPassword(password, nonce));
425:                return getResponse();
426:            }
427:
428:            /** 
429:             * Creates the LANManager and NT response for the given password using the
430:             * given nonce.
431:             * @param password the password to create a hash for.
432:             * @param nonce the nonce sent by the server.
433:             * @return The response.
434:             * @throws HttpException If {@link #encrypt(byte[],byte[])} fails.
435:             */
436:            private byte[] hashPassword(String password, byte[] nonce)
437:                    throws AuthenticationException {
438:                byte[] passw = EncodingUtil.getBytes(password.toUpperCase(),
439:                        credentialCharset);
440:                byte[] lmPw1 = new byte[7];
441:                byte[] lmPw2 = new byte[7];
442:
443:                int len = passw.length;
444:                if (len > 7) {
445:                    len = 7;
446:                }
447:
448:                int idx;
449:                for (idx = 0; idx < len; idx++) {
450:                    lmPw1[idx] = passw[idx];
451:                }
452:                for (; idx < 7; idx++) {
453:                    lmPw1[idx] = (byte) 0;
454:                }
455:
456:                len = passw.length;
457:                if (len > 14) {
458:                    len = 14;
459:                }
460:                for (idx = 7; idx < len; idx++) {
461:                    lmPw2[idx - 7] = passw[idx];
462:                }
463:                for (; idx < 14; idx++) {
464:                    lmPw2[idx - 7] = (byte) 0;
465:                }
466:
467:                // Create LanManager hashed Password
468:                byte[] magic = { (byte) 0x4B, (byte) 0x47, (byte) 0x53,
469:                        (byte) 0x21, (byte) 0x40, (byte) 0x23, (byte) 0x24,
470:                        (byte) 0x25 };
471:
472:                byte[] lmHpw1;
473:                lmHpw1 = encrypt(lmPw1, magic);
474:
475:                byte[] lmHpw2 = encrypt(lmPw2, magic);
476:
477:                byte[] lmHpw = new byte[21];
478:                for (int i = 0; i < lmHpw1.length; i++) {
479:                    lmHpw[i] = lmHpw1[i];
480:                }
481:                for (int i = 0; i < lmHpw2.length; i++) {
482:                    lmHpw[i + 8] = lmHpw2[i];
483:                }
484:                for (int i = 0; i < 5; i++) {
485:                    lmHpw[i + 16] = (byte) 0;
486:                }
487:
488:                // Create the responses.
489:                byte[] lmResp = new byte[24];
490:                calcResp(lmHpw, nonce, lmResp);
491:
492:                return lmResp;
493:            }
494:
495:            /** 
496:             * Takes a 21 byte array and treats it as 3 56-bit DES keys.  The 8 byte
497:             * plaintext is encrypted with each key and the resulting 24 bytes are
498:             * stored in the results array.
499:             * 
500:             * @param keys The keys.
501:             * @param plaintext The plain text to encrypt.
502:             * @param results Where the results are stored.
503:             * @throws AuthenticationException If {@link #encrypt(byte[],byte[])} fails.
504:             */
505:            private void calcResp(byte[] keys, byte[] plaintext, byte[] results)
506:                    throws AuthenticationException {
507:                byte[] keys1 = new byte[7];
508:                byte[] keys2 = new byte[7];
509:                byte[] keys3 = new byte[7];
510:                for (int i = 0; i < 7; i++) {
511:                    keys1[i] = keys[i];
512:                }
513:
514:                for (int i = 0; i < 7; i++) {
515:                    keys2[i] = keys[i + 7];
516:                }
517:
518:                for (int i = 0; i < 7; i++) {
519:                    keys3[i] = keys[i + 14];
520:                }
521:                byte[] results1 = encrypt(keys1, plaintext);
522:
523:                byte[] results2 = encrypt(keys2, plaintext);
524:
525:                byte[] results3 = encrypt(keys3, plaintext);
526:
527:                for (int i = 0; i < 8; i++) {
528:                    results[i] = results1[i];
529:                }
530:                for (int i = 0; i < 8; i++) {
531:                    results[i + 8] = results2[i];
532:                }
533:                for (int i = 0; i < 8; i++) {
534:                    results[i + 16] = results3[i];
535:                }
536:            }
537:
538:            /** 
539:             * Converts a given number to a two byte array in little endian order.
540:             * @param num the number to convert.
541:             * @return The byte representation of <i>num</i> in little endian order.
542:             */
543:            private byte[] convertShort(int num) {
544:                byte[] val = new byte[2];
545:                String hex = Integer.toString(num, 16);
546:                while (hex.length() < 4) {
547:                    hex = "0" + hex;
548:                }
549:                String low = hex.substring(2, 4);
550:                String high = hex.substring(0, 2);
551:
552:                val[0] = (byte) Integer.parseInt(low, 16);
553:                val[1] = (byte) Integer.parseInt(high, 16);
554:                return val;
555:            }
556:
557:            /**
558:             * @return Returns the credentialCharset.
559:             */
560:            public String getCredentialCharset() {
561:                return credentialCharset;
562:            }
563:
564:            /**
565:             * @param credentialCharset The credentialCharset to set.
566:             */
567:            public void setCredentialCharset(String credentialCharset) {
568:                this.credentialCharset = credentialCharset;
569:            }
570:
571:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.