alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Client.java)

This example Java source code file (Client.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

biginteger, client, math, ntlm, ntlmexception, reader, string, type, util, writer

The Client.java Java example source code

/*
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.security.ntlm;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;

/**
 * The NTLM client. Not multi-thread enabled.<p>
 * Example:
 * <pre>
 * Client client = new Client(null, "host", "dummy",
 *       "REALM", "t0pSeCr3t".toCharArray());
 * byte[] type1 = client.type1();
 * // Send type1 to server and receive response as type2
 * byte[] type3 = client.type3(type2, nonce);
 * // Send type3 to server
 * </pre>
 */
public final class Client extends NTLM {
    final private String hostname;
    final private String username;

    private String domain;    // might be updated by Type 2 msg
    private byte[] pw1, pw2;

    /**
     * Creates an NTLM Client instance.
     * @param version the NTLM version to use, which can be:
     * <ul>
     * <li>LM/NTLM: Original NTLM v1
     * <li>LM: Original NTLM v1, LM only
     * <li>NTLM: Original NTLM v1, NTLM only
     * <li>NTLM2: NTLM v1 with Client Challenge
     * <li>LMv2/NTLMv2: NTLM v2
     * <li>LMv2: NTLM v2, LM only
     * <li>NTLMv2: NTLM v2, NTLM only
     * </ul>
     * If null, "LMv2/NTLMv2" will be used.
     * @param hostname hostname of the client, can be null
     * @param username username to be authenticated, must not be null
     * @param domain domain of {@code username}, can be null
     * @param password password for {@code username}, must not be not null.
     * This method does not make any modification to this parameter, it neither
     * needs to access the content of this parameter after this method call,
     * so you are free to modify or nullify this parameter after this call.
     * @throws NTLMException if {@code username} or {@code password} is null,
     * or {@code version} is illegal.
     *
     */
    public Client(String version, String hostname, String username,
            String domain, char[] password) throws NTLMException {
        super(version);
        if ((username == null || password == null)) {
            throw new NTLMException(NTLMException.PROTOCOL,
                    "username/password cannot be null");
        }
        this.hostname = hostname;
        this.username = username;
        this.domain = domain;
        this.pw1 = getP1(password);
        this.pw2 = getP2(password);
        debug("NTLM Client: (h,u,t,version(v)) = (%s,%s,%s,%s(%s))\n",
                    hostname, username, domain, version, v.toString());
    }

    /**
     * Generates the Type 1 message
     * @return the message generated
     */
    public byte[] type1() {
        Writer p = new Writer(1, 32);
        int flags = 0x8203;
        if (hostname != null) {
            flags |= 0x2000;
        }
        if (domain != null) {
            flags |= 0x1000;
        }
        if (v != Version.NTLM) {
            flags |= 0x80000;
        }
        p.writeInt(12, flags);
        p.writeSecurityBuffer(24, hostname, false);
        p.writeSecurityBuffer(16, domain, false);
        debug("NTLM Client: Type 1 created\n");
        debug(p.getBytes());
        return p.getBytes();
    }

    /**
     * Generates the Type 3 message
     * @param type2 the responding Type 2 message from server, must not be null
     * @param nonce random 8-byte array to be used in message generation,
     * must not be null except for original NTLM v1
     * @return the message generated
     * @throws NTLMException if the incoming message is invalid, or
     * {@code nonce} is null for NTLM v1.
     */
    public byte[] type3(byte[] type2, byte[] nonce) throws NTLMException {
        if (type2 == null || (v != Version.NTLM && nonce == null)) {
            throw new NTLMException(NTLMException.PROTOCOL,
                    "type2 and nonce cannot be null");
        }
        debug("NTLM Client: Type 2 received\n");
        debug(type2);
        Reader r = new Reader(type2);
        byte[] challenge = r.readBytes(24, 8);
        int inputFlags = r.readInt(20);
        boolean unicode = (inputFlags & 1) == 1;
        String domainFromServer = r.readSecurityBuffer(12, unicode);
        if (domainFromServer != null) {
            domain = domainFromServer;
        }
        if (domain == null) {
            domain = "";
        }

        int flags = 0x88200 | (inputFlags & 3);
        Writer p = new Writer(3, 64);
        byte[] lm = null, ntlm = null;

        p.writeSecurityBuffer(28, domain, unicode);
        p.writeSecurityBuffer(36, username, unicode);
        p.writeSecurityBuffer(44, hostname, unicode);

        if (v == Version.NTLM) {
            byte[] lmhash = calcLMHash(pw1);
            byte[] nthash = calcNTHash(pw2);
            if (writeLM) lm = calcResponse (lmhash, challenge);
            if (writeNTLM) ntlm = calcResponse (nthash, challenge);
        } else if (v == Version.NTLM2) {
            byte[] nthash = calcNTHash(pw2);
            lm = ntlm2LM(nonce);
            ntlm = ntlm2NTLM(nthash, nonce, challenge);
        } else {
            byte[] nthash = calcNTHash(pw2);
            if (writeLM) lm = calcV2(nthash,
                    username.toUpperCase(Locale.US)+domain, nonce, challenge);
            if (writeNTLM) {
                byte[] alist = type2.length > 48 ?
                    r.readSecurityBuffer(40) : new byte[0];
                byte[] blob = new byte[32+alist.length];
                System.arraycopy(new byte[]{1,1,0,0,0,0,0,0}, 0, blob, 0, 8);
                // TS
                byte[] time = BigInteger.valueOf(new Date().getTime())
                        .add(new BigInteger("11644473600000"))
                        .multiply(BigInteger.valueOf(10000))
                        .toByteArray();
                for (int i=0; i<time.length; i++) {
                    blob[8+time.length-i-1] = time[i];
                }
                System.arraycopy(nonce, 0, blob, 16, 8);
                System.arraycopy(new byte[]{0,0,0,0}, 0, blob, 24, 4);
                System.arraycopy(alist, 0, blob, 28, alist.length);
                System.arraycopy(new byte[]{0,0,0,0}, 0,
                        blob, 28+alist.length, 4);
                ntlm = calcV2(nthash, username.toUpperCase(Locale.US)+domain,
                        blob, challenge);
            }
        }
        p.writeSecurityBuffer(12, lm);
        p.writeSecurityBuffer(20, ntlm);
        p.writeSecurityBuffer(52, new byte[0]);

        p.writeInt(60, flags);
        debug("NTLM Client: Type 3 created\n");
        debug(p.getBytes());
        return p.getBytes();
    }

    /**
     * Returns the domain value provided by server after the authentication
     * is complete, or the domain value provided by the client before it.
     * @return the domain
     */
    public String getDomain() {
        return domain;
    }

    /**
     * Disposes any password-derived information.
     */
    public void dispose() {
        Arrays.fill(pw1, (byte)0);
        Arrays.fill(pw2, (byte)0);
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java Client.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.