/* * Copyright (c) 2016 Dell EMC Software * All Rights Reserved */ package com.iwave.ext.windows.winrm.ntlm; import java.util.Arrays; import org.apache.commons.lang3.CharEncoding; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Class representing an NTLM Type 3 Message. The format of the message is as follows. * * <pre> * Description Content * 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" (0x4e544c4d53535000) * 8 NTLM Message Type long (0x03000000) * 12 LM/LMv2 Response security buffer * 20 NTLM/NTLMv2 Response security buffer * 28 Target Name security buffer * 36 User Name security buffer * 44 Workstation Name security buffer * 52 Session Key security buffer * 60 Flags long * 64 OS Version Structure 8 bytes * 72 MIC 16 bytes * 88 start of data block * </pre> * * @author Jason Forand * */ public class NTLMType3Message extends NTLMMessage { /** * The logger for this class. */ private static final Logger LOG = LoggerFactory.getLogger(NTLMType3Message.class); /** The lm response byte array. */ private byte[] lmresp; /** The ntlm response byte array. */ private byte[] ntlmresp; /** The target name byte array. */ private byte[] targetname; /** The username byte array. */ private byte[] username; /** The workstation name byte array. */ private byte[] workstationname; /** The session key byte array. */ private byte[] sessionkey; /** The type of this NTLM message. */ public static final int TYPE = 3; /** The message integrity check. */ private byte[] mic; /** * * @param lmresp * the lmresp * @param ntlmresp * the ntlmresp * @param targetname * the targetname * @param username * the username * @param workstationname * the workstationname * @param sessionkey * the sessionkey * @param flags * the flags * @param version * the version * @param mic * the message integrity check */ public NTLMType3Message(byte[] lmresp, byte[] ntlmresp, byte[] targetname, byte[] username, byte[] workstationname, byte[] sessionkey, byte[] flags, byte[] version, byte[] mic) { super(flags, version); this.lmresp = lmresp; this.ntlmresp = ntlmresp; this.targetname = targetname; this.username = username; this.workstationname = workstationname; this.sessionkey = sessionkey; this.mic = mic; } /** * @return the lmresp */ public byte[] getLmresp() { return lmresp; } /** * @param lmresp * the lmresp to set */ public void setLmresp(byte[] lmresp) { this.lmresp = lmresp; } /** * @return the ntlmresp */ public byte[] getNtlmresp() { return ntlmresp; } /** * @param ntlmresp * the ntlmresp to set */ public void setNtlmresp(byte[] ntlmresp) { this.ntlmresp = ntlmresp; } /** * @return the targetname */ public byte[] getTargetname() { return targetname; } /** * @param targetname * the targetname to set */ public void setTargetname(byte[] targetname) { this.targetname = targetname; } /** * @return the username */ public byte[] getUsername() { return username; } /** * @param username * the username to set */ public void setUsername(byte[] username) { this.username = username; } /** * @return the workstationname */ public byte[] getWorkstationname() { return workstationname; } /** * @param workstationname * the workstationname to set */ public void setWorkstationname(byte[] workstationname) { this.workstationname = workstationname; } /** * @return the sessionkey */ public byte[] getSessionkey() { return sessionkey; } /** * @param sessionkey * the sessionkey to set */ public void setSessionkey(byte[] sessionkey) { this.sessionkey = sessionkey; } /** * Returns the client challenge to the server. The location of the nonce can be found in the documentation. * * @return the client challenge */ public byte[] getNonce() { // The nonce is the first 8 bytes of the lmresp... check the doc return Arrays.copyOfRange(lmresp, 0, 8); } @Override public int getMessageType() { return TYPE; } /** * Pretty print for debugging purposes. * * @return the pretty string */ @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("TYPE 3\n"); try { builder.append("TARGET: ").append(new String(targetname, CharEncoding.UTF_16LE)).append("\n"); builder.append("WORKSTATION: ").append(new String(workstationname, CharEncoding.UTF_16LE)).append("\n"); builder.append("USER: ").append(new String(username, CharEncoding.UTF_16LE)).append("\n"); } catch (Exception e) { LOG.error("Impossible encoding exception.", e); } builder.append(getFlagsAsString()); builder.append(getVersionAsString()); return builder.toString(); } @Override public byte[] toHeaderBytes() { NTLMByteMessage message = new NTLMByteMessage(); // This is the stuff that goes into the body message.putHeader(NTLMSSP_BYTES); message.putHeader(NTLMUtils.convertInt(3)); message.putData(lmresp); message.putData(ntlmresp); message.putData(targetname); message.putData(username); message.putData(workstationname); message.putData(sessionkey); message.putHeader(getFlags()); message.putHeader(getVersion()); message.putHeader(mic); return message.getMsg(); } /** * Retrieve the mic from the type 3 message. * * @return the mic */ public byte[] getMic() { return mic; } /** * Sets the mic in the type 3 message. * * @param mic * the mic */ public void setMic(byte[] mic) { this.mic = mic; } /** * Parses a byte header and creates a type 3 message out of it. * * @param header * the byte header * @return the created message */ public static NTLMType3Message parse(byte[] header) { byte[] lmresp = NTLMUtils.getSecurityBuffer(12, header); byte[] ntlmresp = NTLMUtils.getSecurityBuffer(20, header); byte[] targetname = NTLMUtils.getSecurityBuffer(28, header); byte[] username = NTLMUtils.getSecurityBuffer(36, header); byte[] workstationname = NTLMUtils.getSecurityBuffer(44, header); byte[] sessionkey = NTLMUtils.getSecurityBuffer(52, header); byte[] flags = Arrays.copyOfRange(header, 60, 64); byte[] version = Arrays.copyOfRange(header, 64, 72); byte[] mic = Arrays.copyOfRange(header, 72, 88); return new NTLMType3Message(lmresp, ntlmresp, targetname, username, workstationname, sessionkey, flags, version, mic); } }