diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/TlsDecryptor.java b/src/main/java/ru/serega6531/packmate/service/optimization/TlsDecryptor.java index 7b53f08..849735d 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/TlsDecryptor.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/TlsDecryptor.java @@ -20,16 +20,17 @@ import ru.serega6531.packmate.service.optimization.tls.numbers.ContentType; import ru.serega6531.packmate.service.optimization.tls.numbers.HandshakeType; import ru.serega6531.packmate.service.optimization.tls.records.ApplicationDataRecord; import ru.serega6531.packmate.service.optimization.tls.records.HandshakeRecord; -import ru.serega6531.packmate.service.optimization.tls.records.handshakes.BasicRecordContent; -import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ClientHelloHandshakeRecordContent; -import ru.serega6531.packmate.service.optimization.tls.records.handshakes.HandshakeRecordContent; -import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ServerHelloHandshakeRecordContent; +import ru.serega6531.packmate.service.optimization.tls.records.handshakes.*; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayInputStream; import java.nio.ByteBuffer; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -50,9 +51,9 @@ public class TlsDecryptor { packets.forEach(p -> tlsPackets.putAll(p, createTlsHeaders(p))); - ClientHelloHandshakeRecordContent clientHello = (ClientHelloHandshakeRecordContent) + var clientHello = (ClientHelloHandshakeRecordContent) getHandshake(tlsPackets.values(), HandshakeType.CLIENT_HELLO).orElseThrow(); - ServerHelloHandshakeRecordContent serverHello = (ServerHelloHandshakeRecordContent) + var serverHello = (ServerHelloHandshakeRecordContent) getHandshake(tlsPackets.values(), HandshakeType.SERVER_HELLO).orElseThrow(); byte[] clientRandom = clientHello.getRandom(); @@ -64,17 +65,24 @@ public class TlsDecryptor { Matcher matcher = cipherSuitePattern.matcher(cipherSuite.name()); //noinspection ResultOfMethodCallIgnored matcher.find(); - String blockCipher = matcher.group(1); + String blockCipher = matcher.group(1); //TODO использовать не только AES256 String hashAlgo = matcher.group(2); - //TODO - RSAPrivateKey privateKey = keysHolder.getKey(null); + var certificateHandshake = ((CertificateHandshakeRecordContent) + getHandshake(tlsPackets.values(), HandshakeType.CERTIFICATE).orElseThrow()); + List chain = certificateHandshake.getRawCertificates(); + byte[] rawCertificate = chain.get(0); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Certificate certificate = cf.generateCertificate(new ByteArrayInputStream(rawCertificate)); + RSAPublicKey publicKey = (RSAPublicKey) certificate.getPublicKey(); + + RSAPrivateKey privateKey = keysHolder.getKey(publicKey.getModulus()); if(privateKey == null) { - log.warn("Key for modulus not found: {}", "TODO"); + log.warn("Key for modulus not found: {}", publicKey.getModulus()); return; } - BasicRecordContent clientKeyExchange = (BasicRecordContent) + var clientKeyExchange = (BasicHandshakeRecordContent) getHandshake(tlsPackets.values(), HandshakeType.CLIENT_KEY_EXCHANGE).orElseThrow(); byte[] encryptedPreMaster = TlsKeyUtils.getClientRsaPreMaster(clientKeyExchange.getContent(), 0); @@ -110,29 +118,28 @@ public class TlsDecryptor { byte[] serverFinishedEncrypted = getFinishedData(tlsPackets, false); Cipher clientCipher = createCipher(clientEncryptionKey, clientIV, clientFinishedEncrypted); -// byte[] clientFinishedData = clientCipher.update(clientFinishedEncrypted); -// HandshakeRecord clientFinished = HandshakeRecord.newInstance(clientFinishedData, 16, clientFinishedData.length - 16); - Cipher serverCipher = createCipher(serverEncryptionKey, serverIV, serverFinishedEncrypted); -// byte[] serverFinishedData = serverCipher.update(serverFinishedEncrypted); -// HandshakeRecord serverFinished = HandshakeRecord.newInstance(serverFinishedData, 16, serverFinishedData.length - 16); - for (Map.Entry entry : tlsPackets.entries()) { - if (entry.getValue().getContentType() == ContentType.APPLICATION_DATA) { - byte[] data = ((ApplicationDataRecord) entry.getValue().getRecord()).getData(); - boolean client = entry.getKey().isIncoming(); + for (Packet packet : packets) { + List tlsData = (List) tlsPackets.get(packet); - byte[] decoded; + for (TlsPacket.TlsHeader tlsPacket : tlsData) { + if (tlsPacket.getContentType() == ContentType.APPLICATION_DATA) { + byte[] data = ((ApplicationDataRecord) tlsPacket.getRecord()).getData(); + boolean client = packet.isIncoming(); - if(client) { - decoded = clientCipher.update(data); - } else { - decoded = serverCipher.update(data); + byte[] decoded; + + if(client) { + decoded = clientCipher.update(data); + } else { + decoded = serverCipher.update(data); + } + + decoded = clearDecodedData(decoded); + String string = new String(decoded); + log.info(string); } - - decoded = clearDecodedData(decoded); - String string = new String(decoded); - System.out.println(string); } } } @@ -158,7 +165,7 @@ public class TlsDecryptor { } private byte[] getFinishedData(ListMultimap tlsPackets, boolean incoming) { - return ((BasicRecordContent) getHandshake(tlsPackets.asMap().entrySet().stream() + return ((BasicHandshakeRecordContent) getHandshake(tlsPackets.asMap().entrySet().stream() .filter(ent -> ent.getKey().isIncoming() == incoming) .map(Map.Entry::getValue) .flatMap(Collection::stream), HandshakeType.ENCRYPTED_HANDSHAKE_MESSAGE)) @@ -169,7 +176,7 @@ public class TlsDecryptor { return stream.filter(p -> p.getContentType() == ContentType.HANDSHAKE) .map(p -> ((HandshakeRecord) p.getRecord())) .filter(r -> r.getHandshakeType() == handshakeType) - .map(r -> ((BasicRecordContent) r.getContent())) + .map(r -> ((BasicHandshakeRecordContent) r.getContent())) .findFirst() .orElseThrow(); } diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HandshakeRecord.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HandshakeRecord.java index 904a576..e9a2317 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HandshakeRecord.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HandshakeRecord.java @@ -2,10 +2,7 @@ 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.BasicRecordContent; -import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ClientHelloHandshakeRecordContent; -import ru.serega6531.packmate.service.optimization.tls.records.handshakes.HandshakeRecordContent; -import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ServerHelloHandshakeRecordContent; +import ru.serega6531.packmate.service.optimization.tls.records.handshakes.*; import ru.serega6531.packmate.utils.BytesUtils; import static org.pcap4j.util.ByteArrays.BYTE_SIZE_IN_BYTES; @@ -37,7 +34,7 @@ public class HandshakeRecord implements TlsRecord { if (handshakeType == HandshakeType.ENCRYPTED_HANDSHAKE_MESSAGE) { this.handshakeLength = length; - this.content = BasicRecordContent.newInstance( + this.content = BasicHandshakeRecordContent.newInstance( rawData, offset, handshakeLength); return; } @@ -50,8 +47,11 @@ public class HandshakeRecord implements TlsRecord { } else if (handshakeType == HandshakeType.SERVER_HELLO) { this.content = ServerHelloHandshakeRecordContent.newInstance( rawData, offset + CONTENT_OFFSET, handshakeLength); + } else if (handshakeType == HandshakeType.CERTIFICATE) { + this.content = CertificateHandshakeRecordContent.newInstance( + rawData, offset + CONTENT_OFFSET, handshakeLength); } else { - this.content = BasicRecordContent.newInstance( + this.content = BasicHandshakeRecordContent.newInstance( rawData, offset + CONTENT_OFFSET, handshakeLength); } } diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicRecordContent.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicHandshakeRecordContent.java similarity index 65% rename from src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicRecordContent.java rename to src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicHandshakeRecordContent.java index 79bc6ed..a0a4b8f 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicRecordContent.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicHandshakeRecordContent.java @@ -2,7 +2,7 @@ package ru.serega6531.packmate.service.optimization.tls.records.handshakes; import org.pcap4j.util.ByteArrays; -public class BasicRecordContent implements HandshakeRecordContent { +public class BasicHandshakeRecordContent implements HandshakeRecordContent { /** * 0x0 - Content @@ -11,14 +11,14 @@ public class BasicRecordContent implements HandshakeRecordContent { private byte[] content; - public static BasicRecordContent newInstance(byte[] rawData, int offset, int length) { + public static BasicHandshakeRecordContent newInstance(byte[] rawData, int offset, int length) { if(length > 0) { ByteArrays.validateBounds(rawData, offset, length); } - return new BasicRecordContent(rawData, offset, length); + return new BasicHandshakeRecordContent(rawData, offset, length); } - public BasicRecordContent(byte[] rawData, int offset, int length) { + public BasicHandshakeRecordContent(byte[] rawData, int offset, int length) { content = new byte[length]; if (length > 0) { System.arraycopy(rawData, offset, content, 0, length); diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/CertificateHandshakeRecordContent.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/CertificateHandshakeRecordContent.java new file mode 100644 index 0000000..1acd1de --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/CertificateHandshakeRecordContent.java @@ -0,0 +1,39 @@ +package ru.serega6531.packmate.service.optimization.tls.records.handshakes; + +import org.pcap4j.util.ByteArrays; +import ru.serega6531.packmate.utils.BytesUtils; + +import java.util.ArrayList; +import java.util.List; + +public class CertificateHandshakeRecordContent implements HandshakeRecordContent { + + private static final int CERTIFICATES_LENGTH_OFFSET = 0; + private static final int CERTIFICATES_OFFSET = 3; + + private int certificatesLength; + private List rawCertificates = new ArrayList<>(); + + public static CertificateHandshakeRecordContent newInstance(byte[] rawData, int offset, int length) { + return new CertificateHandshakeRecordContent(rawData, offset, length); + } + + public CertificateHandshakeRecordContent(byte[] rawData, int offset, int length) { + this.certificatesLength = BytesUtils.getThreeBytesInt(rawData, CERTIFICATES_LENGTH_OFFSET + offset); + + int cursor = CERTIFICATES_OFFSET + offset; + while (cursor < offset + length) { + int certificateLength = BytesUtils.getThreeBytesInt(rawData, cursor); + cursor += 3; + + ByteArrays.validateBounds(rawData, cursor, certificateLength); + byte[] certData = ByteArrays.getSubArray(rawData, cursor, certificateLength); + rawCertificates.add(certData); + cursor += certificateLength; + } + } + + public List getRawCertificates() { + return rawCertificates; + } +}