/*
* Copyright (c) 2016 Dell EMC Software
* All Rights Reserved
*/
package com.iwave.ext.windows.winrm.ntlm;
import java.util.ArrayList;
import java.util.List;
/**
* This class exists to take care of the creation of an NTLM Header.
*/
public class NTLMByteMessage {
/** The elements of the header. */
private List<ByteArray> items;
/** Our current position in the array. */
private int position;
/** The current offset in the data portion of the array. */
private int offset;
/**
* Creates a new NTLMByteMessage.
*/
public NTLMByteMessage() {
items = new ArrayList<ByteArray>();
position = 0;
offset = 0;
}
/**
* Adds a byte array to the header section of the message.
*
* @param bytes
* the header to add
*/
public void putHeader(byte[] bytes) {
items.add(new HeaderByteArray(bytes));
}
/**
* Adds a section to the data portion of the array.
*
* @param bytes
* the data to add
*/
public void putData(byte[] bytes) {
items.add(new DataByteArray(bytes));
}
/**
* Retrieves the byte message that was created.
*
* @return the message
*/
public byte[] getMsg() {
int dataSize = 0;
for (ByteArray b : items) {
dataSize += b.getDataLength();
offset += b.getHeaderLength();
}
int initialOffset = offset;
byte[] msg = new byte[dataSize + offset];
for (ByteArray b : items) {
b.writeTo(msg);
}
if (position > initialOffset) {
throw new RuntimeException("The header section of the message overflowed it's allowable size.");
}
return msg;
}
/**
* Represents a section of the total message.
*
* @author Jason Forand
*
*/
private abstract class ByteArray {
/**
* Retrieves the length of the header section of this component.
*
* @return the length of the header
*/
public abstract int getHeaderLength();
/**
* Retrieves the length of the data section of this component.
*
* @return the length of the data
*/
public abstract int getDataLength();
/**
* Writes the element to the given byte array.
*
* @param array
* the array to write to
*/
public abstract void writeTo(byte[] array);
}
/**
* This element only has a header component.
*
* @author Jason Forand
*
*/
private class HeaderByteArray extends ByteArray {
/** The header bytes. */
private byte[] bytes;
/**
* Creates a new header for the message.
*
* @param bytes
* the bytes for the header
*/
public HeaderByteArray(byte[] bytes) {
this.bytes = bytes;
}
@Override
public int getHeaderLength() {
return bytes.length;
}
@Override
public int getDataLength() {
return 0;
}
@Override
public void writeTo(byte[] array) {
System.arraycopy(bytes, 0, array, position, bytes.length);
position += bytes.length;
}
}
/**
* This element contributes to both the header section and the data section.
*
* @author Jason Forand
*
*/
private class DataByteArray extends ByteArray {
/** The bytes to write to the data section. */
private byte[] bytes;
/** The length of the security buffer that will be added to the header. */
private static final int SECURITY_BUFFER_LENGTH = 8;
/**
* Creates a new data section for the message.
*
* @param bytes
* the bytes in the data section
*/
public DataByteArray(byte[] bytes) {
this.bytes = bytes;
}
@Override
public int getHeaderLength() {
return SECURITY_BUFFER_LENGTH;
}
@Override
public int getDataLength() {
return bytes.length;
}
@Override
public void writeTo(byte[] array) {
new HeaderByteArray(NTLMUtils.createSecurityBuffer((short) bytes.length, offset)).writeTo(array);
System.arraycopy(bytes, 0, array, offset, bytes.length);
offset += bytes.length;
}
}
}