jcifs.smb.NtlmUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcifs-ng Show documentation
Show all versions of jcifs-ng Show documentation
A pure-java CIFS/SMB client library
/*
* © 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