ntlm.java

来自「Light in the box 抓取程序。 使用HttpClient」· Java 代码 · 共 566 行 · 第 1/2 页

JAVA
566
字号
/* * $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 $ * $Revision: 480424 $ * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $ * * ==================================================================== * *  Licensed to the Apache Software Foundation (ASF) under one or more *  contributor license agreements.  See the NOTICE file distributed with *  this work for additional information regarding copyright ownership. *  The ASF licenses this file to You under the Apache License, Version 2.0 *  (the "License"); you may not use this file except in compliance with *  the License.  You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * *  Unless required by applicable law or agreed to in writing, software *  distributed under the License is distributed on an "AS IS" BASIS, *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *  See the License for the specific language governing permissions and *  limitations under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation.  For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */package org.apache.commons.httpclient.auth;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.spec.SecretKeySpec;import org.apache.commons.codec.binary.Base64;import org.apache.commons.httpclient.util.EncodingUtil;/** * Provides an implementation of the NTLM authentication protocol. * <p> * This class provides methods for generating authentication * challenge responses for the NTLM authentication protocol.  The NTLM * protocol is a proprietary Microsoft protocol and as such no RFC * exists for it.  This class is based upon the reverse engineering * efforts of a wide range of people.</p> * * <p>Please note that an implementation of JCE must be correctly installed and configured when * using NTLM support.</p> * * <p>This class should not be used externally to HttpClient as it's API is specifically * designed to work with HttpClient's use case, in particular it's connection management.</p> * * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a> * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a> * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> * * @version $Revision: 480424 $ $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $ * @since 3.0 */final class NTLM {    /** Character encoding */    public static final String DEFAULT_CHARSET = "ASCII";    /** The current response */    private byte[] currentResponse;    /** The current position */    private int currentPosition = 0;    /** The character set to use for encoding the credentials */    private String credentialCharset = DEFAULT_CHARSET;        /**     * Returns the response for the given message.     *     * @param message the message that was received from the server.     * @param username the username to authenticate with.     * @param password the password to authenticate with.     * @param host The host.     * @param domain the NT domain to authenticate in.     * @return The response.     * @throws HttpException If the messages cannot be retrieved.     */    public final String getResponseFor(String message,            String username, String password, String host, String domain)            throws AuthenticationException {                        final String response;        if (message == null || message.trim().equals("")) {            response = getType1Message(host, domain);        } else {            response = getType3Message(username, password, host, domain,                    parseType2Message(message));        }        return response;    }    /**     * Return the cipher for the specified key.     * @param key The key.     * @return Cipher The cipher.     * @throws AuthenticationException If the cipher cannot be retrieved.     */    private Cipher getCipher(byte[] key) throws AuthenticationException {        try {            final Cipher ecipher = Cipher.getInstance("DES/ECB/NoPadding");            key = setupKey(key);            ecipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "DES"));            return ecipher;        } catch (NoSuchAlgorithmException e) {            throw new AuthenticationException("DES encryption is not available.", e);        } catch (InvalidKeyException e) {            throw new AuthenticationException("Invalid key for DES encryption.", e);        } catch (NoSuchPaddingException e) {            throw new AuthenticationException(                "NoPadding option for DES is not available.", e);        }    }    /**      * Adds parity bits to the key.     * @param key56 The key     * @return The modified key.     */    private byte[] setupKey(byte[] key56) {        byte[] key = new byte[8];        key[0] = (byte) ((key56[0] >> 1) & 0xff);        key[1] = (byte) ((((key56[0] & 0x01) << 6)             | (((key56[1] & 0xff) >> 2) & 0xff)) & 0xff);        key[2] = (byte) ((((key56[1] & 0x03) << 5)             | (((key56[2] & 0xff) >> 3) & 0xff)) & 0xff);        key[3] = (byte) ((((key56[2] & 0x07) << 4)             | (((key56[3] & 0xff) >> 4) & 0xff)) & 0xff);        key[4] = (byte) ((((key56[3] & 0x0f) << 3)             | (((key56[4] & 0xff) >> 5) & 0xff)) & 0xff);        key[5] = (byte) ((((key56[4] & 0x1f) << 2)             | (((key56[5] & 0xff) >> 6) & 0xff)) & 0xff);        key[6] = (byte) ((((key56[5] & 0x3f) << 1)             | (((key56[6] & 0xff) >> 7) & 0xff)) & 0xff);        key[7] = (byte) (key56[6] & 0x7f);                for (int i = 0; i < key.length; i++) {            key[i] = (byte) (key[i] << 1);        }        return key;    }    /**     * Encrypt the data.     * @param key The key.     * @param bytes The data     * @return byte[] The encrypted data     * @throws HttpException If {@link Cipher.doFinal(byte[])} fails     */    private byte[] encrypt(byte[] key, byte[] bytes)        throws AuthenticationException {        Cipher ecipher = getCipher(key);        try {            byte[] enc = ecipher.doFinal(bytes);            return enc;        } catch (IllegalBlockSizeException e) {            throw new AuthenticationException("Invalid block size for DES encryption.", e);        } catch (BadPaddingException e) {            throw new AuthenticationException("Data not padded correctly for DES encryption.", e);        }    }    /**      * Prepares the object to create a response of the given length.     * @param length the length of the response to prepare.     */    private void prepareResponse(int length) {        currentResponse = new byte[length];        currentPosition = 0;    }    /**      * Adds the given byte to the response.     * @param b the byte to add.     */    private void addByte(byte b) {        currentResponse[currentPosition] = b;        currentPosition++;    }    /**      * Adds the given bytes to the response.     * @param bytes the bytes to add.     */    private void addBytes(byte[] bytes) {        for (int i = 0; i < bytes.length; i++) {            currentResponse[currentPosition] = bytes[i];            currentPosition++;        }    }    /**      * Returns the response that has been generated after shrinking the array if     * required and base64 encodes the response.     * @return The response as above.     */    private String getResponse() {        byte[] resp;        if (currentResponse.length > currentPosition) {            byte[] tmp = new byte[currentPosition];            for (int i = 0; i < currentPosition; i++) {                tmp[i] = currentResponse[i];            }            resp = tmp;        } else {            resp = currentResponse;        }        return EncodingUtil.getAsciiString(Base64.encodeBase64(resp));    }        /**     * Creates the first message (type 1 message) in the NTLM authentication sequence.     * This message includes the user name, domain and host for the authentication session.     *     * @param host the computer name of the host requesting authentication.     * @param domain The domain to authenticate with.     * @return String the message to add to the HTTP request header.     */    public String getType1Message(String host, String domain) {        host = host.toUpperCase();        domain = domain.toUpperCase();        byte[] hostBytes = EncodingUtil.getBytes(host, DEFAULT_CHARSET);        byte[] domainBytes = EncodingUtil.getBytes(domain, DEFAULT_CHARSET);        int finalLength = 32 + hostBytes.length + domainBytes.length;        prepareResponse(finalLength);                // The initial id string.        byte[] protocol = EncodingUtil.getBytes("NTLMSSP", DEFAULT_CHARSET);        addBytes(protocol);        addByte((byte) 0);        // Type        addByte((byte) 1);        addByte((byte) 0);        addByte((byte) 0);        addByte((byte) 0);        // Flags        addByte((byte) 6);        addByte((byte) 82);        addByte((byte) 0);        addByte((byte) 0);        // Domain length (first time).        int iDomLen = domainBytes.length;        byte[] domLen = convertShort(iDomLen);        addByte(domLen[0]);        addByte(domLen[1]);        // Domain length (second time).        addByte(domLen[0]);        addByte(domLen[1]);        // Domain offset.        byte[] domOff = convertShort(hostBytes.length + 32);        addByte(domOff[0]);        addByte(domOff[1]);        addByte((byte) 0);        addByte((byte) 0);        // Host length (first time).        byte[] hostLen = convertShort(hostBytes.length);        addByte(hostLen[0]);        addByte(hostLen[1]);        // Host length (second time).        addByte(hostLen[0]);        addByte(hostLen[1]);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?