Работа над разбором TLS пакетов
This commit is contained in:
@@ -7,6 +7,7 @@ import org.pcap4j.util.ByteArrays;
|
|||||||
import ru.serega6531.packmate.service.optimization.tls.numbers.ContentType;
|
import ru.serega6531.packmate.service.optimization.tls.numbers.ContentType;
|
||||||
import ru.serega6531.packmate.service.optimization.tls.numbers.TlsVersion;
|
import ru.serega6531.packmate.service.optimization.tls.numbers.TlsVersion;
|
||||||
import ru.serega6531.packmate.service.optimization.tls.records.ChangeCipherSpecRecord;
|
import ru.serega6531.packmate.service.optimization.tls.records.ChangeCipherSpecRecord;
|
||||||
|
import ru.serega6531.packmate.service.optimization.tls.records.HandshakeRecord;
|
||||||
import ru.serega6531.packmate.service.optimization.tls.records.TlsRecord;
|
import ru.serega6531.packmate.service.optimization.tls.records.TlsRecord;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -72,12 +73,13 @@ public class TlsPacket extends AbstractPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TlsHeader(byte[] rawData, int offset, int length) throws IllegalRawDataException {
|
private TlsHeader(byte[] rawData, int offset, int length) throws IllegalRawDataException {
|
||||||
|
//TODO check length
|
||||||
this.contentType = ContentType.getInstance(ByteArrays.getByte(rawData, CONTENT_TYPE_OFFSET + offset));
|
this.contentType = ContentType.getInstance(ByteArrays.getByte(rawData, CONTENT_TYPE_OFFSET + offset));
|
||||||
this.version = TlsVersion.getInstance(ByteArrays.getShort(rawData, VERSION_OFFSET + offset));
|
this.version = TlsVersion.getInstance(ByteArrays.getShort(rawData, VERSION_OFFSET + offset));
|
||||||
this.length = ByteArrays.getShort(rawData, LENGTH_OFFSET + offset);
|
this.length = ByteArrays.getShort(rawData, LENGTH_OFFSET + offset);
|
||||||
|
|
||||||
if (contentType == ContentType.HANDSHAKE) {
|
if (contentType == ContentType.HANDSHAKE) {
|
||||||
|
this.record = HandshakeRecord.newInstance(rawData, offset + RECORD_OFFSET, length);
|
||||||
} else if (contentType == ContentType.CHANGE_CIPHER_SPEC) {
|
} else if (contentType == ContentType.CHANGE_CIPHER_SPEC) {
|
||||||
this.record = ChangeCipherSpecRecord.newInstance(rawData, offset + RECORD_OFFSET, length);
|
this.record = ChangeCipherSpecRecord.newInstance(rawData, offset + RECORD_OFFSET, length);
|
||||||
} else if (contentType == ContentType.APPLICATION_DATA) {
|
} else if (contentType == ContentType.APPLICATION_DATA) {
|
||||||
@@ -102,6 +104,14 @@ public class TlsPacket extends AbstractPacket {
|
|||||||
public int length() {
|
public int length() {
|
||||||
return RECORD_OFFSET + length;
|
return RECORD_OFFSET + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String buildString() {
|
||||||
|
return "TLS Header [" + length() + " bytes]\n" +
|
||||||
|
" Version: " + version + "\n" +
|
||||||
|
" Type: " + contentType + "\n" +
|
||||||
|
record.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Builder extends AbstractBuilder {
|
public static final class Builder extends AbstractBuilder {
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package ru.serega6531.packmate.service.optimization.tls.numbers;
|
||||||
|
|
||||||
|
import org.pcap4j.packet.namednumber.NamedNumber;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class CipherSuite extends NamedNumber<Short, CipherSuite> {
|
||||||
|
|
||||||
|
public static final CipherSuite RESERVED_GREASE = new CipherSuite((short) 0xdada, "Reserved (GREASE)");
|
||||||
|
public static final CipherSuite TLS_AES_128_GCM_SHA256 = new CipherSuite((short) 0x1301, "TLS_AES_128_GCM_SHA256");
|
||||||
|
|
||||||
|
private static final Map<Short, CipherSuite> registry = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
registry.put(RESERVED_GREASE.value(), RESERVED_GREASE);
|
||||||
|
registry.put(TLS_AES_128_GCM_SHA256.value(), TLS_AES_128_GCM_SHA256);
|
||||||
|
//TODO add all
|
||||||
|
}
|
||||||
|
|
||||||
|
public CipherSuite(Short value, String name) {
|
||||||
|
super(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CipherSuite getInstance(Short value) {
|
||||||
|
if (registry.containsKey(value)) {
|
||||||
|
return registry.get(value);
|
||||||
|
} else {
|
||||||
|
return new CipherSuite(value, "unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(CipherSuite o) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package ru.serega6531.packmate.service.optimization.tls.numbers;
|
||||||
|
|
||||||
|
import org.pcap4j.packet.namednumber.NamedNumber;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class CompressionMethod extends NamedNumber<Byte, CompressionMethod> {
|
||||||
|
|
||||||
|
public static final CompressionMethod NULL = new CompressionMethod((byte) 0, "null");
|
||||||
|
|
||||||
|
private static final Map<Byte, CompressionMethod> registry = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
registry.put(NULL.value(), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompressionMethod(Byte value, String name) {
|
||||||
|
super(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompressionMethod getInstance(Byte value) {
|
||||||
|
if (registry.containsKey(value)) {
|
||||||
|
return registry.get(value);
|
||||||
|
} else {
|
||||||
|
return new CompressionMethod(value, "Unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(CompressionMethod o) {
|
||||||
|
return value().compareTo(o.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package ru.serega6531.packmate.service.optimization.tls.numbers;
|
||||||
|
|
||||||
|
import org.pcap4j.packet.namednumber.NamedNumber;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ExtensionType extends NamedNumber<Short, ExtensionType> {
|
||||||
|
|
||||||
|
public static final ExtensionType RESERVED_GREASE = new ExtensionType((short) 14906, "Reserved (GREASE)");
|
||||||
|
|
||||||
|
private static final Map<Short, ExtensionType> registry = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
registry.put(RESERVED_GREASE.value(), RESERVED_GREASE);
|
||||||
|
//TODO add all
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExtensionType(Short value, String name) {
|
||||||
|
super(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ExtensionType getInstance(Short value) {
|
||||||
|
if (registry.containsKey(value)) {
|
||||||
|
return registry.get(value);
|
||||||
|
} else {
|
||||||
|
return new ExtensionType(value, "Unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(ExtensionType o) {
|
||||||
|
return value().compareTo(o.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package ru.serega6531.packmate.service.optimization.tls.numbers;
|
||||||
|
|
||||||
|
import org.pcap4j.packet.namednumber.NamedNumber;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class HandshakeType extends NamedNumber<Byte, HandshakeType> {
|
||||||
|
|
||||||
|
public static final HandshakeType HELLO_REQUEST = new HandshakeType((byte) 0, "Hello Request");
|
||||||
|
public static final HandshakeType CLIENT_HELLO = new HandshakeType((byte) 1, "Client Hello");
|
||||||
|
public static final HandshakeType SERVER_HELLO = new HandshakeType((byte) 2, "Server Hello");
|
||||||
|
public static final HandshakeType CERTIFICATE = new HandshakeType((byte) 11, "Certificate");
|
||||||
|
public static final HandshakeType SERVER_KEY_EXCHANGE = new HandshakeType((byte) 12, "Server Key Excange");
|
||||||
|
public static final HandshakeType CERTIFICATE_REQUEST = new HandshakeType((byte) 13, "Certificate Request");
|
||||||
|
public static final HandshakeType SERVER_HELLO_DONE = new HandshakeType((byte) 14, "Server Hello Done");
|
||||||
|
public static final HandshakeType CERTIFICATE_VERIFY = new HandshakeType((byte) 15, "Certificate Verify");
|
||||||
|
public static final HandshakeType CLIENT_KEY_EXCHANGE = new HandshakeType((byte) 16, "Client Key Exchange");
|
||||||
|
public static final HandshakeType FINISHED = new HandshakeType((byte) 20, "Finished");
|
||||||
|
|
||||||
|
private static final Map<Byte, HandshakeType> registry = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
registry.put(HELLO_REQUEST.value(), HELLO_REQUEST);
|
||||||
|
registry.put(CLIENT_HELLO.value(), CLIENT_HELLO);
|
||||||
|
registry.put(SERVER_HELLO.value(), SERVER_HELLO);
|
||||||
|
registry.put(CERTIFICATE.value(), CERTIFICATE);
|
||||||
|
registry.put(SERVER_KEY_EXCHANGE.value(), SERVER_KEY_EXCHANGE);
|
||||||
|
registry.put(CERTIFICATE_REQUEST.value(), CERTIFICATE_REQUEST);
|
||||||
|
registry.put(SERVER_HELLO_DONE.value(), SERVER_HELLO_DONE);
|
||||||
|
registry.put(CERTIFICATE_VERIFY.value(), CERTIFICATE_VERIFY);
|
||||||
|
registry.put(CLIENT_KEY_EXCHANGE.value(), CLIENT_KEY_EXCHANGE);
|
||||||
|
registry.put(FINISHED.value(), FINISHED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HandshakeType(Byte value, String name) {
|
||||||
|
super(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandshakeType getInstance(Byte value) {
|
||||||
|
if (registry.containsKey(value)) {
|
||||||
|
return registry.get(value);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown handshake type " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(HandshakeType o) {
|
||||||
|
return value().compareTo(o.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package ru.serega6531.packmate.service.optimization.tls.records;
|
package ru.serega6531.packmate.service.optimization.tls.records;
|
||||||
|
|
||||||
import org.pcap4j.packet.IllegalRawDataException;
|
|
||||||
import org.pcap4j.util.ByteArrays;
|
import org.pcap4j.util.ByteArrays;
|
||||||
|
|
||||||
public class ChangeCipherSpecRecord extends TlsRecord {
|
public class ChangeCipherSpecRecord extends TlsRecord {
|
||||||
@@ -8,7 +7,6 @@ public class ChangeCipherSpecRecord extends TlsRecord {
|
|||||||
private byte changeCipherSpecMessage;
|
private byte changeCipherSpecMessage;
|
||||||
|
|
||||||
public static ChangeCipherSpecRecord newInstance(byte[] rawData, int offset, int length) {
|
public static ChangeCipherSpecRecord newInstance(byte[] rawData, int offset, int length) {
|
||||||
ByteArrays.validateBounds(rawData, offset, length);
|
|
||||||
return new ChangeCipherSpecRecord(rawData, offset);
|
return new ChangeCipherSpecRecord(rawData, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,4 +14,8 @@ public class ChangeCipherSpecRecord extends TlsRecord {
|
|||||||
this.changeCipherSpecMessage = ByteArrays.getByte(rawData, offset);
|
this.changeCipherSpecMessage = ByteArrays.getByte(rawData, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return " Change Cipher Spec Message: " + changeCipherSpecMessage;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package ru.serega6531.packmate.service.optimization.tls.records;
|
||||||
|
|
||||||
|
import org.pcap4j.util.ByteArrays;
|
||||||
|
import ru.serega6531.packmate.service.optimization.tls.numbers.HandshakeType;
|
||||||
|
import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ClientHelloHandshakeRecordContent;
|
||||||
|
import ru.serega6531.packmate.service.optimization.tls.records.handshakes.HandshakeRecordContent;
|
||||||
|
|
||||||
|
import static org.pcap4j.util.ByteArrays.BYTE_SIZE_IN_BYTES;
|
||||||
|
|
||||||
|
public class HandshakeRecord extends TlsRecord {
|
||||||
|
|
||||||
|
private static final int HANDSHAKE_TYPE_OFFSET = 0;
|
||||||
|
|
||||||
|
private HandshakeType handshakeType;
|
||||||
|
private HandshakeRecordContent content;
|
||||||
|
|
||||||
|
public static HandshakeRecord newInstance(byte[] rawData, int offset, int length) {
|
||||||
|
return new HandshakeRecord(rawData, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HandshakeRecord(byte[] rawData, int offset, int length) {
|
||||||
|
this.handshakeType = HandshakeType.getInstance(ByteArrays.getByte(rawData, HANDSHAKE_TYPE_OFFSET + offset));
|
||||||
|
|
||||||
|
if (handshakeType == HandshakeType.HELLO_REQUEST) {
|
||||||
|
|
||||||
|
} else if (handshakeType == HandshakeType.CLIENT_HELLO) {
|
||||||
|
this.content = ClientHelloHandshakeRecordContent.newInstance(
|
||||||
|
rawData, offset + BYTE_SIZE_IN_BYTES, length);
|
||||||
|
} else if (handshakeType == HandshakeType.SERVER_HELLO) {
|
||||||
|
|
||||||
|
} else if (handshakeType == HandshakeType.CERTIFICATE) {
|
||||||
|
|
||||||
|
} else if (handshakeType == HandshakeType.SERVER_KEY_EXCHANGE) {
|
||||||
|
|
||||||
|
} else if (handshakeType == HandshakeType.CERTIFICATE_REQUEST) {
|
||||||
|
|
||||||
|
} else if (handshakeType == HandshakeType.SERVER_HELLO_DONE) {
|
||||||
|
|
||||||
|
} else if (handshakeType == HandshakeType.CERTIFICATE_VERIFY) {
|
||||||
|
|
||||||
|
} else if (handshakeType == HandshakeType.CLIENT_KEY_EXCHANGE) {
|
||||||
|
|
||||||
|
} else if (handshakeType == HandshakeType.FINISHED) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown handshake type " + handshakeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return " Handshake type: " + handshakeType + "\n" +
|
||||||
|
content.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package ru.serega6531.packmate.service.optimization.tls.records.handshakes;
|
||||||
|
|
||||||
|
import org.pcap4j.util.ByteArrays;
|
||||||
|
import ru.serega6531.packmate.service.optimization.tls.numbers.CipherSuite;
|
||||||
|
import ru.serega6531.packmate.service.optimization.tls.numbers.CompressionMethod;
|
||||||
|
import ru.serega6531.packmate.service.optimization.tls.numbers.ExtensionType;
|
||||||
|
import ru.serega6531.packmate.service.optimization.tls.numbers.TlsVersion;
|
||||||
|
import ru.serega6531.packmate.utils.BytesUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.pcap4j.util.ByteArrays.BYTE_SIZE_IN_BYTES;
|
||||||
|
import static org.pcap4j.util.ByteArrays.SHORT_SIZE_IN_BYTES;
|
||||||
|
|
||||||
|
public class ClientHelloHandshakeRecordContent implements HandshakeRecordContent {
|
||||||
|
|
||||||
|
private static final int LENGTH_OFFSET = 0;
|
||||||
|
private static final int VERSION_OFFSET = LENGTH_OFFSET + 3;
|
||||||
|
private static final int RANDOM_OFFSET = VERSION_OFFSET + SHORT_SIZE_IN_BYTES;
|
||||||
|
private static final int SESSION_ID_LENGTH_OFFSET = RANDOM_OFFSET + 32;
|
||||||
|
private static final int SESSION_ID_OFFSET = SESSION_ID_LENGTH_OFFSET + BYTE_SIZE_IN_BYTES;
|
||||||
|
private static final int CIPHER_SUITES_LENGTH_OFFSET = SESSION_ID_OFFSET; // + sessionIdLength
|
||||||
|
private static final int CIPHER_SUITE_OFFSET =
|
||||||
|
CIPHER_SUITES_LENGTH_OFFSET + SHORT_SIZE_IN_BYTES; // + sessionIdLength + SHORT_SIZE_IN_BYTES*i
|
||||||
|
private static final int COMPRESSION_METHODS_LENGTH_OFFSET = CIPHER_SUITE_OFFSET; // + sessionIdLength + cipherSuitesLength
|
||||||
|
private static final int COMPRESSION_METHOD_OFFSET =
|
||||||
|
COMPRESSION_METHODS_LENGTH_OFFSET + BYTE_SIZE_IN_BYTES; // + sessionIdLength + cipherSuitesLength + BYTE_SIZE_IN_BYTES*i
|
||||||
|
private static final int EXTENSIONS_LENTH_OFFSET =
|
||||||
|
COMPRESSION_METHOD_OFFSET; // + sessionIdLength + cipherSuitesLength + compressionMethodsLength
|
||||||
|
private static final int EXTENSION_OFFSET = COMPRESSION_METHOD_OFFSET + SHORT_SIZE_IN_BYTES;
|
||||||
|
|
||||||
|
private int length; // 3 bytes
|
||||||
|
private TlsVersion version;
|
||||||
|
private byte[] random = new byte[32];
|
||||||
|
private byte sessionIdLength;
|
||||||
|
private byte[] sessionId;
|
||||||
|
private short cipherSuitesLength;
|
||||||
|
private List<CipherSuite> cipherSuites;
|
||||||
|
private byte compressionMethodsLength;
|
||||||
|
private List<CompressionMethod> compressionMethods;
|
||||||
|
private short extensionsLength;
|
||||||
|
|
||||||
|
public static ClientHelloHandshakeRecordContent newInstance(byte[] rawData, int offset, int length) {
|
||||||
|
return new ClientHelloHandshakeRecordContent(rawData, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientHelloHandshakeRecordContent(byte[] rawData, int offset, int length) {
|
||||||
|
this.length = BytesUtils.getThreeBytesInt(rawData, LENGTH_OFFSET + offset);
|
||||||
|
this.version = TlsVersion.getInstance(ByteArrays.getShort(rawData, VERSION_OFFSET + offset));
|
||||||
|
System.arraycopy(rawData, RANDOM_OFFSET + offset, random, 0, 32);
|
||||||
|
this.sessionIdLength = ByteArrays.getByte(rawData, SESSION_ID_LENGTH_OFFSET + offset);
|
||||||
|
this.sessionId = new byte[sessionIdLength];
|
||||||
|
|
||||||
|
if (sessionIdLength != 0) {
|
||||||
|
System.arraycopy(rawData, SESSION_ID_OFFSET + offset, sessionId, 0, sessionIdLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cipherSuitesLength = ByteArrays.getShort(rawData, CIPHER_SUITES_LENGTH_OFFSET + sessionIdLength + offset);
|
||||||
|
int cipherSuitesAmount = cipherSuitesLength / SHORT_SIZE_IN_BYTES;
|
||||||
|
this.cipherSuites = new ArrayList<>(cipherSuitesAmount);
|
||||||
|
|
||||||
|
for (int i = 0; i < cipherSuitesAmount; i++) {
|
||||||
|
this.cipherSuites.add(CipherSuite.getInstance(ByteArrays.getShort(rawData,
|
||||||
|
CIPHER_SUITE_OFFSET + SHORT_SIZE_IN_BYTES * i + sessionIdLength + offset)));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.compressionMethodsLength = ByteArrays.getByte(rawData,
|
||||||
|
COMPRESSION_METHODS_LENGTH_OFFSET + cipherSuitesLength + sessionIdLength + offset);
|
||||||
|
this.compressionMethods = new ArrayList<>(compressionMethodsLength);
|
||||||
|
|
||||||
|
for (byte i = 0; i < compressionMethodsLength; i++) {
|
||||||
|
this.compressionMethods.add(CompressionMethod.getInstance(ByteArrays.getByte(rawData,
|
||||||
|
COMPRESSION_METHOD_OFFSET + BYTE_SIZE_IN_BYTES * i + sessionIdLength + cipherSuitesLength + offset)));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.extensionsLength = ByteArrays.getShort(rawData,
|
||||||
|
COMPRESSION_METHOD_OFFSET + compressionMethodsLength + sessionIdLength + cipherSuitesLength + offset);
|
||||||
|
|
||||||
|
int cursor = EXTENSION_OFFSET + compressionMethodsLength + sessionIdLength + cipherSuitesLength + offset;
|
||||||
|
int extensionsEnd = cursor + extensionsLength;
|
||||||
|
|
||||||
|
while (cursor < extensionsEnd) {
|
||||||
|
ExtensionType extensionType = ExtensionType.getInstance(ByteArrays.getShort(rawData, cursor));
|
||||||
|
cursor += SHORT_SIZE_IN_BYTES;
|
||||||
|
short extensionLength = ByteArrays.getShort(rawData, cursor);
|
||||||
|
cursor += SHORT_SIZE_IN_BYTES;
|
||||||
|
cursor += extensionLength;
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return " Handshake length: " + length + "\n" +
|
||||||
|
" TLS version: " + version + "\n" +
|
||||||
|
" Client random: " + ByteArrays.toHexString(random, "") + "\n" +
|
||||||
|
" Session id: " + (sessionIdLength > 0 ? ByteArrays.toHexString(sessionId, "") : "null") + "\n" +
|
||||||
|
" Cipher suites: " + cipherSuites.toString() + "\n" +
|
||||||
|
" Compression methods: " + compressionMethods.toString() + "\n" +
|
||||||
|
" Extensions: TODO";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package ru.serega6531.packmate.service.optimization.tls.records.handshakes;
|
||||||
|
|
||||||
|
public interface HandshakeRecordContent {
|
||||||
|
}
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
package ru.serega6531.packmate.utils;
|
package ru.serega6531.packmate.utils;
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
import org.pcap4j.util.ByteArrays;
|
||||||
|
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
import static java.nio.ByteOrder.LITTLE_ENDIAN;
|
||||||
|
import static org.pcap4j.util.ByteArrays.BYTE_SIZE_IN_BITS;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class BytesUtils {
|
public class BytesUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array где ищем
|
* @param array где ищем
|
||||||
* @param target что ищем
|
* @param target что ищем
|
||||||
*/
|
*/
|
||||||
public int indexOf(byte[] array, byte[] target, int start, int end) {
|
public int indexOf(byte[] array, byte[] target, int start, int end) {
|
||||||
@@ -27,16 +33,16 @@ public class BytesUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array где ищем
|
* @param array где ищем
|
||||||
* @param target что ищем
|
* @param target что ищем
|
||||||
*/
|
*/
|
||||||
public boolean endsWith(byte[] array, byte[] target) {
|
public boolean endsWith(byte[] array, byte[] target) {
|
||||||
if(array.length < target.length) {
|
if (array.length < target.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < target.length; i++) {
|
for (int i = 0; i < target.length; i++) {
|
||||||
if(array[array.length - target.length + i] != target[i]) {
|
if (array[array.length - target.length + i] != target[i]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,4 +50,37 @@ public class BytesUtils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array array
|
||||||
|
* @param offset offset
|
||||||
|
* @return int value.
|
||||||
|
*/
|
||||||
|
public int getThreeBytesInt(byte[] array, int offset) {
|
||||||
|
return getThreeBytesInt(array, offset, ByteOrder.BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array array
|
||||||
|
* @param offset offset
|
||||||
|
* @param bo bo
|
||||||
|
* @return int value.
|
||||||
|
*/
|
||||||
|
public int getThreeBytesInt(byte[] array, int offset, ByteOrder bo) {
|
||||||
|
ByteArrays.validateBounds(array, offset, 3);
|
||||||
|
|
||||||
|
if (bo == null) {
|
||||||
|
throw new NullPointerException(" bo: null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bo.equals(LITTLE_ENDIAN)) {
|
||||||
|
return ((0xFF & array[offset + 2]) << (BYTE_SIZE_IN_BITS * 2))
|
||||||
|
| ((0xFF & array[offset + 1]) << (BYTE_SIZE_IN_BITS * 1))
|
||||||
|
| ((0xFF & array[offset]));
|
||||||
|
} else {
|
||||||
|
return ((0xFF & array[offset]) << (BYTE_SIZE_IN_BITS * 2))
|
||||||
|
| ((0xFF & array[offset + 1]) << (BYTE_SIZE_IN_BITS * 1))
|
||||||
|
| ((0xFF & array[offset + 2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user