All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jcifs.smb.NtlmUtil Maven / Gradle / Ivy

/*
 * © 2016 AgNO3 Gmbh & Co. KG
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package jcifs.smb;


import java.security.GeneralSecurityException;
import java.security.MessageDigest;

import javax.crypto.Cipher;
import javax.crypto.ShortBufferException;

import jcifs.CIFSContext;
import jcifs.util.Crypto;
import jcifs.util.Encdec;
import jcifs.util.Strings;


/**
 * Internal use only
 * 
 * @author mbechler
 * @internal
 */
public final class NtlmUtil {

    /**
     * 
     */
    private NtlmUtil () {}


    /**
     * 
     * @param responseKeyNT
     * @param serverChallenge
     * @param clientChallenge
     * @param nanos1601
     * @param avPairs
     * @return the calculated response
     */
    public static byte[] getNTLMv2Response ( byte[] responseKeyNT, byte[] serverChallenge, byte[] clientChallenge, long nanos1601, byte[] avPairs ) {
        int avPairsLength = avPairs != null ? avPairs.length : 0;
        byte[] temp = new byte[28 + avPairsLength + 4];

        Encdec.enc_uint32le(0x00000101, temp, 0); // Header
        Encdec.enc_uint32le(0x00000000, temp, 4); // Reserved
        Encdec.enc_uint64le(nanos1601, temp, 8);
        System.arraycopy(clientChallenge, 0, temp, 16, 8);
        Encdec.enc_uint32le(0x00000000, temp, 24); // Unknown
        if ( avPairs != null )
            System.arraycopy(avPairs, 0, temp, 28, avPairsLength);
        Encdec.enc_uint32le(0x00000000, temp, 28 + avPairsLength); // mystery bytes!

        return NtlmUtil.computeResponse(responseKeyNT, serverChallenge, temp, 0, temp.length);
    }


    /**
     * 
     * @param responseKeyLM
     * @param serverChallenge
     * @param clientChallenge
     * @return the calculated response
     */
    public static byte[] getLMv2Response ( byte[] responseKeyLM, byte[] serverChallenge, byte[] clientChallenge ) {
        return NtlmUtil.computeResponse(responseKeyLM, serverChallenge, clientChallenge, 0, clientChallenge.length);
    }


    static byte[] computeResponse ( byte[] responseKey, byte[] serverChallenge, byte[] clientData, int offset, int length ) {
        MessageDigest hmac = Crypto.getHMACT64(responseKey);
        hmac.update(serverChallenge);
        hmac.update(clientData, offset, length);
        byte[] mac = hmac.digest();
        byte[] ret = new byte[mac.length + clientData.length];
        System.arraycopy(mac, 0, ret, 0, mac.length);
        System.arraycopy(clientData, 0, ret, mac.length, clientData.length);
        return ret;
    }


    /**
     * 
     * @param domain
     * @param username
     * @param password
     * 
     * @return the caclulated mac
     */
    public static byte[] nTOWFv2 ( String domain, String username, String password ) {
        return nTOWFv2(domain, username, getNTHash(password));
    }


    /**
     * 
     * @param domain
     * @param username
     * @param passwordHash
     *            NT password hash
     * 
     * @return the caclulated mac
     */
    public static byte[] nTOWFv2 ( String domain, String username, byte[] passwordHash ) {
        MessageDigest hmac = Crypto.getHMACT64(passwordHash);
        hmac.update(Strings.getUNIBytes(username.toUpperCase()));
        hmac.update(Strings.getUNIBytes(domain));
        return hmac.digest();
    }


    /**
     * @param password
     * @return nt password hash
     */
    public static byte[] getNTHash ( String password ) {
        if ( password == null ) {
            throw new NullPointerException("Password parameter is required");
        }
        MessageDigest md4 = Crypto.getMD4();
        md4.update(Strings.getUNIBytes(password));
        return md4.digest();
    }


    /**
     * 
     * @param password
     * @return the calculated hash
     */
    public static byte[] nTOWFv1 ( String password ) {
        return getNTHash(password);
    }


    /**
     * 
     * @param passwordHash
     * @param serverChallenge
     * @param clientChallenge
     * @return the calculated response
     * @throws GeneralSecurityException
     */
    public static byte[] getNTLM2Response ( byte[] passwordHash, byte[] serverChallenge, byte[] clientChallenge ) throws GeneralSecurityException {
        byte[] sessionHash = new byte[8];

        MessageDigest md5 = Crypto.getMD5();;
        md5.update(serverChallenge);
        md5.update(clientChallenge, 0, 8);
        System.arraycopy(md5.digest(), 0, sessionHash, 0, 8);

        byte[] key = new byte[21];
        System.arraycopy(passwordHash, 0, key, 0, 16);
        byte[] ntResponse = new byte[24];
        NtlmUtil.E(key, sessionHash, ntResponse);
        return ntResponse;
    }


    /**
     * Creates the LMv2 response for the supplied information.
     *
     * @param domain
     *            The domain in which the username exists.
     * @param user
     *            The username.
     * @param password
     *            The user's password.
     * @param challenge
     *            The server challenge.
     * @param clientChallenge
     *            The client challenge (nonce).
     * @return the calculated response
     * @throws GeneralSecurityException
     */
    public static byte[] getLMv2Response ( String domain, String user, String password, byte[] challenge, byte[] clientChallenge )
            throws GeneralSecurityException {
        return getLMv2Response(domain, user, getNTHash(password), challenge, clientChallenge);
    }


    /**
     * Creates the LMv2 response for the supplied information.
     *
     * @param domain
     *            The domain in which the username exists.
     * @param user
     *            The username.
     * @param passwordHash
     *            The user's NT hash.
     * @param challenge
     *            The server challenge.
     * @param clientChallenge
     *            The client challenge (nonce).
     * @return the calculated response
     * @throws GeneralSecurityException
     */
    public static byte[] getLMv2Response ( String domain, String user, byte[] passwordHash, byte[] challenge, byte[] clientChallenge )
            throws GeneralSecurityException {
        byte[] response = new byte[24];
        MessageDigest hmac = Crypto.getHMACT64(passwordHash);
        hmac.update(Strings.getUNIBytes(user.toUpperCase()));
        hmac.update(Strings.getUNIBytes(domain.toUpperCase()));
        hmac = Crypto.getHMACT64(hmac.digest());
        hmac.update(challenge);
        hmac.update(clientChallenge);
        hmac.digest(response, 0, 16);
        System.arraycopy(clientChallenge, 0, response, 16, 8);
        return response;
    }


    /**
     * Generate the Unicode MD4 hash for the password associated with these credentials.
     * 
     * @param password
     * @param challenge
     * @return the calculated response
     * @throws GeneralSecurityException
     */
    public static byte[] getNTLMResponse ( String password, byte[] challenge ) throws GeneralSecurityException {
        return getNTLMResponse(getNTHash(password), challenge);
    }


    /**
     * Generate the Unicode MD4 hash for the password associated with these credentials.
     * 
     * @param passwordHash
     *            NT Hash
     * @param challenge
     * @return the calculated response
     * @throws GeneralSecurityException
     */
    public static byte[] getNTLMResponse ( byte[] passwordHash, byte[] challenge ) throws GeneralSecurityException {
        byte[] p21 = new byte[21];
        byte[] p24 = new byte[24];
        System.arraycopy(passwordHash, 0, p21, 0, 16);
        NtlmUtil.E(p21, challenge, p24);
        return p24;
    }


    /**
     * Generate the ANSI DES hash for the password associated with these credentials.
     * 
     * @param tc
     * @param password
     * @param challenge
     * @return the calculated response
     * @throws GeneralSecurityException
     */
    static public byte[] getPreNTLMResponse ( CIFSContext tc, String password, byte[] challenge ) throws GeneralSecurityException {
        byte[] p14 = new byte[14];
        byte[] p21 = new byte[21];
        byte[] p24 = new byte[24];
        byte[] passwordBytes = Strings.getOEMBytes(password, tc.getConfig());
        int passwordLength = passwordBytes.length;

        // Only encrypt the first 14 bytes of the password for Pre 0.12 NT LM
        if ( passwordLength > 14 ) {
            passwordLength = 14;
        }
        System.arraycopy(passwordBytes, 0, p14, 0, passwordLength);
        NtlmUtil.E(p14, NtlmUtil.S8, p21);
        NtlmUtil.E(p21, challenge, p24);
        return p24;
    }

    // KGS!@#$%
    static final byte[] S8 = {
        (byte) 0x4b, (byte) 0x47, (byte) 0x53, (byte) 0x21, (byte) 0x40, (byte) 0x23, (byte) 0x24, (byte) 0x25
    };


    /*
     * Accepts key multiple of 7
     * Returns enc multiple of 8
     * Multiple is the same like: 21 byte key gives 24 byte result
     */
    static void E ( byte[] key, byte[] data, byte[] e ) throws ShortBufferException {
        byte[] key7 = new byte[7];
        byte[] e8 = new byte[8];

        for ( int i = 0; i < key.length / 7; i++ ) {
            System.arraycopy(key, i * 7, key7, 0, 7);
            Cipher des = Crypto.getDES(key7);
            des.update(data, 0, data.length, e8);
            System.arraycopy(e8, 0, e, i * 8, 8);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy