diff --git a/README.md b/README.md index 846bd61..72e7be6 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ * Автоматически проводит urldecode * Разархивирует GZIP в HTTP на лету * Разархивирует сжатые WebSockets +* Расшифровывает TLS на RSA при наличии приватного ключа ![Скриншот главного окна](screenshots/Screenshot.png) ## Клонирование @@ -75,6 +76,9 @@ PACKMATE_MODE=FILE PACKMATE_PCAP_FILE=dump.pcap ``` +Чтобы использовать расшифровку TLS, нужно положить соответствующий приватный ключ, который +использовался для генерации сертификата, в папку `rsa_keys`. + ### Запуск После указания нужных настроек в env-файле, можно запустить приложение: ```bash diff --git a/README_EN.md b/README_EN.md index b8f8048..6ccab39 100644 --- a/README_EN.md +++ b/README_EN.md @@ -21,6 +21,7 @@ Advanced network traffic flow analyzer for A/D CTFs. * Can urldecode text automatically * Can automatically decompress GZIPed HTTP * Can automatically deflate WebSockets with permessages-deflate extension +* Decrypts TLS with RSA using given private key ![Main window](screenshots/Screenshot.png) ## Cloning @@ -74,6 +75,8 @@ PACKMATE_MODE=FILE PACKMATE_PCAP_FILE=dump.pcap ``` +To decrypt TLS, put the private key used to generate a certificate into the `rsa_keys` folder. + ### Launch After filling in env file you can launch the app: ```bash diff --git a/build.gradle b/build.gradle index edcca92..a46afa4 100644 --- a/build.gradle +++ b/build.gradle @@ -36,6 +36,8 @@ dependencies { compile 'org.pcap4j:pcap4j-packetfactory-static:1.8.2' compile group: 'com.google.guava', name: 'guava', version: '28.2-jre' compile group: 'org.java-websocket', name: 'Java-WebSocket', version: '1.5.0-SNAPSHOT' + compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.65' + compile group: 'org.bouncycastle', name: 'bctls-jdk15on', version: '1.65' compileOnly 'org.projectlombok:lombok' runtimeOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'org.postgresql:postgresql' diff --git a/docker/Dockerfile_app b/docker/Dockerfile_app index 18bc01d..81c66eb 100644 --- a/docker/Dockerfile_app +++ b/docker/Dockerfile_app @@ -13,7 +13,7 @@ RUN npm install && npm run build && npm cache clean --force \ WORKDIR /app/ -RUN ./gradlew --no-daemon --no-build-cache build \ +RUN ./gradlew --no-daemon --no-build-cache build -x test \ && cp build/libs/packmate-*.jar app.jar \ && ./gradlew --no-daemon clean diff --git a/frontend b/frontend index 747bade..b550034 160000 --- a/frontend +++ b/frontend @@ -1 +1 @@ -Subproject commit 747badeddfc3d576f3dec7d98490484ce75e21b3 +Subproject commit b55003488a46128f67cbce85bed1ae1b885a5410 diff --git a/rsa_keys/example.key b/rsa_keys/example.key new file mode 100644 index 0000000..3b9801a --- /dev/null +++ b/rsa_keys/example.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDWJO65om/5LMA0 +8w9Uk36h4ukQ7Qt8nbpbeHzxorl4lGwWBASEAEmDYNUcGO0CxglOE93F9BPNGn6q +Vj8Ypp3kcTGOzsXcFrd0wRpXbSwbynnmqTCYigiLzIidasfUrGul4s1fVZFdkQZS +p2Y5pEUxq1GKcAgCVwjMyWC1dhGqvTcA5ps0JoSRoA+Nzs/BeTHlTm8UvT9eD9ER +8RmYVOi1edcJ/eztj1CVydq5X27QNmwLuqsAwq38I27nlq1NU5ShqDQ16bg8IY/c +Ll4QJB7SVbrLf3dJ7KY5i7DNEoYUiJGRwDJZt+wcZLtFSzj0cn0BuEU6M0PYglUI +uQTeosUZAgMBAAECggEAehq7CJyHzoPm4QpLDoW/qh1RmfYgG6FwVqHgVIPdz9SJ +wQ/vZzkmscPwIEJSOsejHKMVTL983vGhkgz1k1/GHjEw+eYLShCl8Ov+0iUNBpew +ZIbKj9/9OYGZ0HDHmwvpocAuLJME/V4pRc3v6yQw1D6EkzSITJVGDkcxXqcBMeIA +uNVr+pwLH9vO7ybva+e3T4ROWxlecHrcB94THops4fy5+SGVILwvKaP4cRhjLfD4 +2XV4O5N0imdPAYsNNHyHbAzjvZPoCOsuH3B/tWmRHq3oOa4ZcFUNTDmO9GgfbtY/ +PHEFV34XxMjy3bK0vLxHqS9CEj1cvfq8e1NqkDTugQKBgQD6CEezGf9OFb3byBui +X3OzXWdWQ5jnodOTPb/P+y9DrORJPy1/0BcXh/cHF58kNDZvzVwTFcAjfx6bxS41 +JAddFRZjNuHXEOtFRkD3Wp4W7Atrv/yeKbpE9PCaNYtUDasL8RKcdJiHNFpN4xRl +jpQtIiQ9pikrjUXLgW0S88zzyQKBgQDbQV+DMxGS2Cee6nfMmUcGjgQd8D0cXLjk +OZSmEnk4FCvV8ZdysjirqmuitFTE+PYmOJzhlQl8lubEs4Kc7L9CfEwbK9mNN0ZG +BNdT21nFuJp7YoZzZDTHuwF0nBjQFYcdaWDW+qFqrqs9mKbmCQ5vSzql6al+pzdX +X/YS0QTO0QKBgDUMprHQdUPLByJnnb1gxTqsOa2q3/ldc3eNJXJqWAfi2fjUh8HT +k+KxPW9qyqAy1832429FMSQW55ajSn+J6moMfFiGn3ozI8fp9QTGXD5+zJmK/X1N +WzEgSyBc9ffago0hFBLQBkDBkdtur7gwfS3qTYgrBhcwfTuFdXAM/FJJAoGABIQ2 +OXel1waI2mcuDJLjuajXQN6gA6ONU3Y0L6+Vu6f+tyuA2SX+sNqT2Qgp7tzKBUOJ +R8RQK7bYDhk8iYr+7Zmt36lpk9Udp3eWD+4mzUHePMhsyJe51pttjj9g63hmDh8L +laIYDSCH+n7YgUiSeYxtKtnDWg6Lv0sEwKJ5nOECgYBsF5PoHRE4Q/Vs18qbI4t/ +zPwWWNP0sb3PYRlWLTKMBowQdDOxnXAF12txoLNhpOn9DjZdNEb2EMsqlzdNjphN +uUWZq89d5kDwKfj4ji087elcjsW79R5oqwrN8a0NimftZ4eBPbcn8Y0r5psPcSzE +36iKGM2euQYD8Ub+aDOSLQ== +-----END PRIVATE KEY----- diff --git a/src/main/java/ru/serega6531/packmate/model/CtfService.java b/src/main/java/ru/serega6531/packmate/model/CtfService.java index b3d0fed..7b0788e 100644 --- a/src/main/java/ru/serega6531/packmate/model/CtfService.java +++ b/src/main/java/ru/serega6531/packmate/model/CtfService.java @@ -16,6 +16,8 @@ public class CtfService { private String name; + private boolean decryptTls; + private boolean processChunkedEncoding; private boolean ungzipHttp; diff --git a/src/main/java/ru/serega6531/packmate/model/Packet.java b/src/main/java/ru/serega6531/packmate/model/Packet.java index f306c7f..e1690da 100644 --- a/src/main/java/ru/serega6531/packmate/model/Packet.java +++ b/src/main/java/ru/serega6531/packmate/model/Packet.java @@ -55,6 +55,8 @@ public class Packet { private boolean webSocketParsed; + private boolean tlsDecrypted; + private byte[] content; @Transient diff --git a/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java b/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java index c899a17..0802e91 100644 --- a/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java +++ b/src/main/java/ru/serega6531/packmate/pcap/LivePcapWorker.java @@ -39,16 +39,18 @@ public class LivePcapWorker extends AbstractPcapWorker { applyFilter(); - try { - log.info("Intercept started"); - pcap.loop(-1, this, loopExecutorService); - } catch (InterruptedException ignored) { - Thread.currentThread().interrupt(); - // выходим - } catch (Exception e) { - log.error("Error while capturing packet", e); - stop(); - } + loopExecutorService.execute(() -> { + try { + log.info("Intercept started"); + pcap.loop(-1, this); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + // выходим + } catch (Exception e) { + log.error("Error while capturing packet", e); + stop(); + } + }); } @SneakyThrows diff --git a/src/main/java/ru/serega6531/packmate/service/StreamService.java b/src/main/java/ru/serega6531/packmate/service/StreamService.java index ed9fb36..9e8a77f 100644 --- a/src/main/java/ru/serega6531/packmate/service/StreamService.java +++ b/src/main/java/ru/serega6531/packmate/service/StreamService.java @@ -15,6 +15,7 @@ import ru.serega6531.packmate.model.pojo.Pagination; import ru.serega6531.packmate.model.pojo.SubscriptionMessage; import ru.serega6531.packmate.model.pojo.UnfinishedStream; import ru.serega6531.packmate.repository.StreamRepository; +import ru.serega6531.packmate.service.optimization.RsaKeysHolder; import ru.serega6531.packmate.service.optimization.StreamOptimizer; import java.util.HashSet; @@ -33,6 +34,7 @@ public class StreamService { private final ServicesService servicesService; private final CountingService countingService; private final SubscriptionService subscriptionService; + private final RsaKeysHolder keysHolder; private final boolean ignoreEmptyPackets; @@ -44,12 +46,14 @@ public class StreamService { ServicesService servicesService, CountingService countingService, SubscriptionService subscriptionService, + RsaKeysHolder keysHolder, @Value("${ignore-empty-packets}") boolean ignoreEmptyPackets) { this.repository = repository; this.patternService = patternService; this.servicesService = servicesService; this.countingService = countingService; this.subscriptionService = subscriptionService; + this.keysHolder = keysHolder; this.ignoreEmptyPackets = ignoreEmptyPackets; } @@ -94,7 +98,7 @@ public class StreamService { countingService.countStream(service.getPort(), packets.size()); - packets = new StreamOptimizer(service, packets).optimizeStream(); + packets = new StreamOptimizer(keysHolder, service, packets).optimizeStream(); processUserAgent(packets, stream); Stream savedStream = save(stream); diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/HttpChunksProcessor.java b/src/main/java/ru/serega6531/packmate/service/optimization/HttpChunksProcessor.java index c9ecb53..a0cfa68 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/HttpChunksProcessor.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/HttpChunksProcessor.java @@ -137,6 +137,7 @@ public class HttpChunksProcessor { .timestamp(packets.get(0).getTimestamp()) .ungzipped(false) .webSocketParsed(false) + .tlsDecrypted(packets.get(0).isTlsDecrypted()) .content(output.toByteArray()) .build(); diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/HttpGzipProcessor.java b/src/main/java/ru/serega6531/packmate/service/optimization/HttpGzipProcessor.java index 1ab260a..7b868eb 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/HttpGzipProcessor.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/HttpGzipProcessor.java @@ -105,6 +105,7 @@ public class HttpGzipProcessor { .timestamp(cut.get(0).getTimestamp()) .ungzipped(true) .webSocketParsed(false) + .tlsDecrypted(cut.get(0).isTlsDecrypted()) .content(newContent) .build(); } catch (ZipException e) { diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/PacketsMerger.java b/src/main/java/ru/serega6531/packmate/service/optimization/PacketsMerger.java index 40a03d4..498492a 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/PacketsMerger.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/PacketsMerger.java @@ -50,7 +50,8 @@ public class PacketsMerger { final long timestamp = cut.get(0).getTimestamp(); final boolean ungzipped = cut.stream().anyMatch(Packet::isUngzipped); final boolean webSocketParsed = cut.stream().anyMatch(Packet::isWebSocketParsed); - boolean incoming = cut.get(0).isIncoming(); + final boolean tlsDecrypted = cut.get(0).isTlsDecrypted(); + final boolean incoming = cut.get(0).isIncoming(); //noinspection OptionalGetWithoutIsPresent final byte[] content = PacketUtils.mergePackets(cut).get(); @@ -60,6 +61,7 @@ public class PacketsMerger { .timestamp(timestamp) .ungzipped(ungzipped) .webSocketParsed(webSocketParsed) + .tlsDecrypted(tlsDecrypted) .content(content) .build()); } diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/RsaKeysHolder.java b/src/main/java/ru/serega6531/packmate/service/optimization/RsaKeysHolder.java new file mode 100644 index 0000000..4817360 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/RsaKeysHolder.java @@ -0,0 +1,75 @@ +package ru.serega6531.packmate.service.optimization; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.file.Files; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@Service +@Slf4j +public class RsaKeysHolder { + + // Key: N from RSA public key + private final Map keys = new HashMap<>(); + + public RSAPrivateKey getKey(BigInteger modulus) { + return keys.get(modulus); + } + + @EventListener(ApplicationReadyEvent.class) + public void afterStartup(ApplicationReadyEvent event) { + log.info("Loading RSA keys..."); + File dir = new File("rsa_keys"); + if (dir.exists() && dir.isDirectory()) { + for (File keyFile : Objects.requireNonNull(dir.listFiles())) { + addKey(keyFile); + } + } + } + + @SneakyThrows + public void addKey(File keyFile) { + if (!keyFile.exists()) { + throw new IllegalArgumentException("Key file does not exist"); + } + + try { + RSAPrivateKey privateKey = loadFromFile(keyFile); + keys.put(privateKey.getModulus(), privateKey); + String n = privateKey.getModulus().toString(); + log.info("Loaded RSA key with N={}...", n.substring(0, Math.min(n.length(), 8))); + } catch (IOException | InvalidKeySpecException e) { + log.error("Error loading rsa key", e); + } + } + + private RSAPrivateKey loadFromFile(File keyFile) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException { + String content = Files.readString(keyFile.toPath()); + + content = content.replaceAll("-----BEGIN (RSA )?PRIVATE KEY-----", "") + .replaceAll("-----END (RSA )?PRIVATE KEY-----", "") + .replace("\n", ""); + + byte[] keyBytes = Base64.getDecoder().decode(content); + + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory kf = KeyFactory.getInstance("RSA"); + return (RSAPrivateKey) kf.generatePrivate(spec); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/StreamOptimizer.java b/src/main/java/ru/serega6531/packmate/service/optimization/StreamOptimizer.java index c54e2a7..5d735dd 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/StreamOptimizer.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/StreamOptimizer.java @@ -12,6 +12,7 @@ import java.util.List; @Slf4j public class StreamOptimizer { + private final RsaKeysHolder keysHolder; private final CtfService service; private List packets; @@ -19,29 +20,72 @@ public class StreamOptimizer { * Вызвать для выполнения оптимизаций на переданном списке пакетов. */ public List optimizeStream() { + if (service.isDecryptTls()) { + try { + decryptTls(); + } catch (Exception e) { + log.warn("Error optimizing stream (tls)", e); + return packets; + } + } + if (service.isProcessChunkedEncoding()) { - processChunkedEncoding(); + try { + processChunkedEncoding(); + } catch (Exception e) { + log.warn("Error optimizing stream (chunks)", e); + return packets; + } } if (service.isUngzipHttp()) { - unpackGzip(); + try { + unpackGzip(); + } catch (Exception e) { + log.warn("Error optimizing stream (gzip)", e); + return packets; + } } if (service.isParseWebSockets()) { - parseWebSockets(); + try { + parseWebSockets(); + } catch (Exception e) { + log.warn("Error optimizing stream (websocketss)", e); + return packets; + } } if (service.isUrldecodeHttpRequests()) { - urldecodeRequests(); + try { + urldecodeRequests(); + } catch (Exception e) { + log.warn("Error optimizing stream (urldecode)", e); + return packets; + } } if (service.isMergeAdjacentPackets()) { - mergeAdjacentPackets(); + try { + mergeAdjacentPackets(); + } catch (Exception e) { + log.warn("Error optimizing stream (adjacent)", e); + return packets; + } } return packets; } + private void decryptTls() { + final TlsDecryptor tlsDecryptor = new TlsDecryptor(packets, keysHolder); + tlsDecryptor.decryptTls(); + + if (tlsDecryptor.isParsed()) { + packets = tlsDecryptor.getParsedPackets(); + } + } + /** * Сжать соседние пакеты в одном направлении в один. * Выполняется после других оптимизаций чтобы правильно определять границы пакетов. diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/TlsDecryptor.java b/src/main/java/ru/serega6531/packmate/service/optimization/TlsDecryptor.java new file mode 100644 index 0000000..e492285 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/TlsDecryptor.java @@ -0,0 +1,301 @@ +package ru.serega6531.packmate.service.optimization; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ArrayUtils; +import org.bouncycastle.tls.ExporterLabel; +import org.bouncycastle.tls.PRFAlgorithm; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsSecret; +import org.pcap4j.packet.IllegalRawDataException; +import org.pcap4j.util.ByteArrays; +import ru.serega6531.packmate.model.Packet; +import ru.serega6531.packmate.service.optimization.tls.TlsPacket; +import ru.serega6531.packmate.service.optimization.tls.keys.TlsKeyUtils; +import ru.serega6531.packmate.service.optimization.tls.numbers.CipherSuite; +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.*; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayInputStream; +import java.nio.ByteBuffer; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Slf4j +@RequiredArgsConstructor +public class TlsDecryptor { + + private static final Pattern cipherSuitePattern = Pattern.compile("TLS_RSA_WITH_([A-Z0-9_]+)_([A-Z0-9]+)"); + + private final List packets; + private final RsaKeysHolder keysHolder; + + @Getter + private boolean parsed = false; + private List result; + + private ListMultimap tlsPackets; + private byte[] clientRandom; + private byte[] serverRandom; + + public void decryptTls() { + tlsPackets = ArrayListMultimap.create(packets.size(), 1); + + try { + for (Packet p : packets) { + tlsPackets.putAll(p, createTlsHeaders(p)); + } + } catch (IllegalRawDataException e) { + log.warn("Failed to parse TLS packets", e); + return; + } + + var clientHelloOpt = getHandshake(HandshakeType.CLIENT_HELLO); + var serverHelloOpt = getHandshake(HandshakeType.SERVER_HELLO); + + if (clientHelloOpt.isEmpty() || serverHelloOpt.isEmpty()) { + return; + } + + var clientHello = (ClientHelloHandshakeRecordContent) clientHelloOpt.get(); + var serverHello = (ServerHelloHandshakeRecordContent) serverHelloOpt.get(); + + CipherSuite cipherSuite = serverHello.getCipherSuite(); + + if (cipherSuite.name().startsWith("TLS_RSA_WITH_")) { + Matcher matcher = cipherSuitePattern.matcher(cipherSuite.name()); + //noinspection ResultOfMethodCallIgnored + matcher.find(); + String blockCipher = matcher.group(1); //TODO использовать не только AES256 + String hashAlgo = matcher.group(2); + + clientRandom = clientHello.getRandom(); + serverRandom = serverHello.getRandom(); + + decryptTlsRsa(blockCipher, hashAlgo); + } + } + + @SneakyThrows + private void decryptTlsRsa(String blockCipher, String hashAlgo) { + String[] blockCipherParts = blockCipher.split("_"); + String blockCipherAlgo = blockCipherParts[0]; + int blockCipherSize = Integer.parseInt(blockCipherParts[1]); + String blockCipherMode = blockCipherParts[2]; + + if (!blockCipherAlgo.equals("AES")) { + return; + } + + int keyLength = blockCipherSize / 8; + + Optional publicKeyOpt = getRsaPublicKey(); + + if (publicKeyOpt.isEmpty()) { + return; + } + + RSAPublicKey publicKey = publicKeyOpt.get(); + RSAPrivateKey privateKey = keysHolder.getKey(publicKey.getModulus()); + if (privateKey == null) { + String n = publicKey.getModulus().toString(); + log.warn("Key for modulus not found: {}...", n.substring(0, Math.min(n.length(), 8))); + return; + } + + Optional preMasterOptional = getPreMaster(privateKey); + if (preMasterOptional.isEmpty()) { + return; + } + + BcTlsSecret preMaster = preMasterOptional.get(); + + byte[] randomCS = ArrayUtils.addAll(clientRandom, serverRandom); + byte[] randomSC = ArrayUtils.addAll(serverRandom, clientRandom); + + TlsSecret masterSecret = preMaster.deriveUsingPRF( + PRFAlgorithm.tls_prf_sha256, ExporterLabel.master_secret, randomCS, 48); + byte[] expanded = masterSecret.deriveUsingPRF( + PRFAlgorithm.tls_prf_sha256, ExporterLabel.key_expansion, randomSC, 72 + keyLength * 2).extract(); // для sha256 + + byte[] clientMacKey = new byte[20]; + byte[] serverMacKey = new byte[20]; + byte[] clientEncryptionKey = new byte[keyLength]; + byte[] serverEncryptionKey = new byte[keyLength]; + byte[] clientIV = new byte[16]; + byte[] serverIV = new byte[16]; + + ByteBuffer bb = ByteBuffer.wrap(expanded); + bb.get(clientMacKey); + bb.get(serverMacKey); + bb.get(clientEncryptionKey); + bb.get(serverEncryptionKey); + bb.get(clientIV); + bb.get(serverIV); + + Optional clientCipherOpt = createCipher(blockCipherMode, clientEncryptionKey, clientIV); + Optional serverCipherOpt = createCipher(blockCipherMode, serverEncryptionKey, serverIV); + + if (clientCipherOpt.isEmpty() || serverCipherOpt.isEmpty()) { + return; + } + + Cipher clientCipher = clientCipherOpt.get(); + Cipher serverCipher = serverCipherOpt.get(); + + result = new ArrayList<>(packets.size()); + + for (Packet packet : packets) { + List tlsData = tlsPackets.get(packet); + + for (TlsPacket.TlsHeader tlsPacket : tlsData) { + if (tlsPacket.getContentType() == ContentType.APPLICATION_DATA) { + byte[] data = ((ApplicationDataRecord) tlsPacket.getRecord()).getData(); + boolean client = packet.isIncoming(); + + Cipher cipher = client ? clientCipher : serverCipher; + byte[] decoded = cipher.doFinal(data); + + decoded = clearDecodedData(decoded); + + result.add(Packet.builder() + .content(decoded) + .incoming(packet.isIncoming()) + .timestamp(packet.getTimestamp()) + .ungzipped(false) + .webSocketParsed(false) + .tlsDecrypted(true) + .ttl(packet.getTtl()) + .build()); + } + } + } + + parsed = true; + } + + @SneakyThrows(value = {NoSuchAlgorithmException.class, NoSuchPaddingException.class}) + private Optional getPreMaster(RSAPrivateKey privateKey) { + Optional opt = getHandshake(HandshakeType.CLIENT_KEY_EXCHANGE); + + if (opt.isEmpty()) { + return Optional.empty(); + } + + var clientKeyExchange = (BasicHandshakeRecordContent) opt.get(); + + try { + byte[] encryptedPreMaster = TlsKeyUtils.getClientRsaPreMaster(clientKeyExchange.getContent(), 0); + + Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + rsa.init(Cipher.DECRYPT_MODE, privateKey); + byte[] preMaster = rsa.doFinal(encryptedPreMaster); + return Optional.of(new BcTlsSecret(new BcTlsCrypto(null), preMaster)); + } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { + log.warn("Failed do get pre-master key", e); + return Optional.empty(); + } + } + + private Optional getRsaPublicKey() { + var certificateHandshakeOpt = getHandshake(HandshakeType.CERTIFICATE); + + if (certificateHandshakeOpt.isEmpty()) { + return Optional.empty(); + } + + var certificateHandshake = (CertificateHandshakeRecordContent) certificateHandshakeOpt.get(); + List chain = certificateHandshake.getRawCertificates(); + byte[] rawCertificate = chain.get(0); + + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Certificate certificate = cf.generateCertificate(new ByteArrayInputStream(rawCertificate)); + RSAPublicKey publicKey = (RSAPublicKey) certificate.getPublicKey(); + return Optional.of(publicKey); + } catch (CertificateException e) { + log.warn("Error while getting certificate", e); + return Optional.empty(); + } + } + + @SneakyThrows(value = {NoSuchAlgorithmException.class, NoSuchPaddingException.class}) + private Optional createCipher(String mode, byte[] key, byte[] iv) { + Cipher cipher = Cipher.getInstance("AES/" + mode + "/PKCS5Padding"); + SecretKeySpec serverSkeySpec = new SecretKeySpec(key, "AES"); + IvParameterSpec serverIvParameterSpec = new IvParameterSpec(iv); + + try { + cipher.init(Cipher.DECRYPT_MODE, serverSkeySpec, serverIvParameterSpec); + + return Optional.of(cipher); + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + log.warn("Error decrypting TLS", e); + return Optional.empty(); + } + } + + private byte[] clearDecodedData(byte[] decoded) { + int start = 16; + int end = decoded.length - 21; // почему?) + decoded = ByteArrays.getSubArray(decoded, start, end - start); + return decoded; + } + + private Optional getHandshake(HandshakeType handshakeType) { + return tlsPackets.values().stream() + .filter(p -> p.getContentType() == ContentType.HANDSHAKE) + .map(p -> ((HandshakeRecord) p.getRecord())) + .filter(r -> r.getHandshakeType() == handshakeType) + .map(HandshakeRecord::getContent) + .findFirst(); + } + + private List createTlsHeaders(Packet p) throws IllegalRawDataException { + List headers = new ArrayList<>(); + TlsPacket tlsPacket = TlsPacket.newPacket(p.getContent(), 0, p.getContent().length); + + headers.add(tlsPacket.getHeader()); + + while (tlsPacket.getPayload() != null) { + tlsPacket = (TlsPacket) tlsPacket.getPayload(); + headers.add(tlsPacket.getHeader()); + } + + return headers; + } + + public List getParsedPackets() { + if (!parsed) { + throw new IllegalStateException("TLS is not parsed"); + } + + return result; + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/WebSocketsParser.java b/src/main/java/ru/serega6531/packmate/service/optimization/WebSocketsParser.java index de38248..1acc9c3 100644 --- a/src/main/java/ru/serega6531/packmate/service/optimization/WebSocketsParser.java +++ b/src/main/java/ru/serega6531/packmate/service/optimization/WebSocketsParser.java @@ -104,7 +104,7 @@ public class WebSocketsParser { } private void parse(final List wsPackets, final List handshakes, Draft_6455 draft) { - List> sides = sliceToSides(wsPackets); + List> sides = PacketUtils.sliceToSides(wsPackets); parsedPackets = new ArrayList<>(handshakes); for (List side : sides) { @@ -132,6 +132,7 @@ public class WebSocketsParser { .ttl(lastPacket.getTtl()) .ungzipped(lastPacket.isUngzipped()) .webSocketParsed(true) + .tlsDecrypted(lastPacket.isTlsDecrypted()) .build() ); } @@ -149,31 +150,6 @@ public class WebSocketsParser { return parsedPackets; } - private List> sliceToSides(List packets) { - List> result = new ArrayList<>(); - List side = new ArrayList<>(); - boolean incoming = true; - - for (Packet packet : packets) { - if(packet.isIncoming() != incoming) { - incoming = packet.isIncoming(); - - if(!side.isEmpty()) { - result.add(side); - side = new ArrayList<>(); - } - } - - side.add(packet); - } - - if(!side.isEmpty()) { - result.add(side); - } - - return result; - } - private String getHandshake(final List packets) { final String handshake = PacketUtils.mergePackets(packets) .map(String::new) diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/TlsPacket.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/TlsPacket.java new file mode 100644 index 0000000..34b1c14 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/TlsPacket.java @@ -0,0 +1,172 @@ +package ru.serega6531.packmate.service.optimization.tls; + +import org.pcap4j.packet.AbstractPacket; +import org.pcap4j.packet.IllegalRawDataException; +import org.pcap4j.packet.Packet; +import org.pcap4j.util.ByteArrays; +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.records.*; + +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 TlsPacket extends AbstractPacket { + + private final TlsPacket.TlsHeader header; + private final Packet payload; + + public static TlsPacket newPacket(byte[] rawData, int offset, int length) throws IllegalRawDataException { + ByteArrays.validateBounds(rawData, offset, length); + return new TlsPacket(rawData, offset, length); + } + + private TlsPacket(byte[] rawData, int offset, int length) throws IllegalRawDataException { + this.header = new TlsPacket.TlsHeader(rawData, offset, length); + + int payloadLength = length - header.length(); + if (payloadLength > 0) { + this.payload = TlsPacket.newPacket(rawData, offset + header.length(), payloadLength); + } else { + this.payload = null; + } + } + + private TlsPacket(TlsPacket.Builder builder) { + if (builder == null) { + throw new NullPointerException("builder: null"); + } + + this.payload = builder.payloadBuilder != null ? builder.payloadBuilder.build() : null; + this.header = new TlsPacket.TlsHeader(builder); + } + + @Override + public TlsHeader getHeader() { + return header; + } + + @Override + public Packet getPayload() { + return payload; + } + + @Override + public Builder getBuilder() { + return new Builder(this); + } + + @Override + protected String buildString() { + StringBuilder sb = new StringBuilder(getHeader().toString()); + + TlsPacket p = (TlsPacket) getPayload(); + + if (p != null) { + sb.append('\n'); + sb.append(p.toString()); + } + + return sb.toString(); + } + + public static final class TlsHeader extends AbstractHeader { + + /* + 0x0 - Content Type + 0x1 - Version + 0x3 - Length + 0x5 - Record content + */ + + private static final int CONTENT_TYPE_OFFSET = 0; + private static final int VERSION_OFFSET = CONTENT_TYPE_OFFSET + BYTE_SIZE_IN_BYTES; + private static final int LENGTH_OFFSET = VERSION_OFFSET + SHORT_SIZE_IN_BYTES; + private static final int RECORD_OFFSET = LENGTH_OFFSET + SHORT_SIZE_IN_BYTES; + + private ContentType contentType; + private TlsVersion version; + private short recordLength; + private TlsRecord record; + + private TlsHeader(Builder builder) { + //TODO + } + + private TlsHeader(byte[] rawData, int offset, int length) throws IllegalRawDataException { + ByteArrays.validateBounds(rawData, offset, RECORD_OFFSET); + this.contentType = ContentType.getInstance(ByteArrays.getByte(rawData, CONTENT_TYPE_OFFSET + offset)); + this.version = TlsVersion.getInstance(ByteArrays.getShort(rawData, VERSION_OFFSET + offset)); + this.recordLength = ByteArrays.getShort(rawData, LENGTH_OFFSET + offset); + + if (contentType == ContentType.HANDSHAKE) { + this.record = HandshakeRecord.newInstance(rawData, offset + RECORD_OFFSET, recordLength); + } else if (contentType == ContentType.CHANGE_CIPHER_SPEC) { + this.record = ChangeCipherSpecRecord.newInstance(rawData, offset + RECORD_OFFSET, recordLength); + } else if (contentType == ContentType.APPLICATION_DATA) { + this.record = ApplicationDataRecord.newInstance(rawData, offset + RECORD_OFFSET, recordLength); + } else if (contentType == ContentType.ALERT) { + this.record = AlertRecord.newInstance(rawData, offset + RECORD_OFFSET, recordLength); + } else if (contentType == ContentType.HEARTBEAT) { + this.record = HeartbeatRecord.newInstance(rawData, offset + RECORD_OFFSET, recordLength); + } else { + throw new IllegalArgumentException("Unknown content type: " + contentType); + } + } + + public ContentType getContentType() { + return contentType; + } + + public TlsVersion getVersion() { + return version; + } + + public TlsRecord getRecord() { + return record; + } + + @Override + protected List getRawFields() { + List rawFields = new ArrayList<>(); + rawFields.add(new byte[]{contentType.value()}); + rawFields.add(ByteArrays.toByteArray(version.value())); + rawFields.add(ByteArrays.toByteArray(recordLength)); + //TODO + return rawFields; + } + + @Override + public int length() { + return RECORD_OFFSET + recordLength; + } + + @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 { + + private Packet.Builder payloadBuilder; + + public Builder() { + } + + public Builder(TlsPacket packet) { + this.payloadBuilder = packet.payload != null ? packet.payload.getBuilder() : null; + } + + @Override + public Packet build() { + return new TlsPacket(this); + } + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/TlsExtension.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/TlsExtension.java new file mode 100644 index 0000000..eb0bade --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/TlsExtension.java @@ -0,0 +1,49 @@ +package ru.serega6531.packmate.service.optimization.tls.extensions; + +import org.pcap4j.util.ByteArrays; +import ru.serega6531.packmate.service.optimization.tls.extensions.keyshare.KeyShareExtension; +import ru.serega6531.packmate.service.optimization.tls.numbers.ExtensionType; + +public abstract class TlsExtension { + + /* + 0x0 - Type + 0x2 - Length + 0x4 - Content + 0x4+length - End + */ + + protected ExtensionType type; + protected short extensionLength; + + public static TlsExtension newInstance(ExtensionType type, byte[] rawData, int offset, + short extensionLength, boolean client) { + if (extensionLength > 0) { + ByteArrays.validateBounds(rawData, offset, extensionLength); + } + + if (type == ExtensionType.KEY_SHARE) { + return KeyShareExtension.newInstance(type, rawData, offset, extensionLength, client); + } else { + return new UnimplementedTlsExtension(type, rawData, offset, extensionLength); + } + } + + public TlsExtension(ExtensionType type, short extensionLength) { + this.type = type; + this.extensionLength = extensionLength; + } + + public ExtensionType getType() { + return type; + } + + public short getLength() { + return extensionLength; + } + + @Override + public String toString() { + return type.name(); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/UnimplementedTlsExtension.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/UnimplementedTlsExtension.java new file mode 100644 index 0000000..3ca5171 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/UnimplementedTlsExtension.java @@ -0,0 +1,24 @@ +package ru.serega6531.packmate.service.optimization.tls.extensions; + +import ru.serega6531.packmate.service.optimization.tls.numbers.ExtensionType; + +public class UnimplementedTlsExtension extends TlsExtension { + + private byte[] data; + + public UnimplementedTlsExtension(ExtensionType type, byte[] rawData, int offset, short extensionLength) { + super(type, extensionLength); + + data = new byte[extensionLength]; + System.arraycopy(rawData, offset, data, 0, extensionLength); + } + + @Override + public String toString() { + if(extensionLength > 0) { + return type.name() + " [" + extensionLength + " bytes]"; + } else { + return type.name(); + } + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/ClientKeyShareExtension.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/ClientKeyShareExtension.java new file mode 100644 index 0000000..c834da3 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/ClientKeyShareExtension.java @@ -0,0 +1,23 @@ +package ru.serega6531.packmate.service.optimization.tls.extensions.keyshare; + +import org.pcap4j.util.ByteArrays; +import ru.serega6531.packmate.service.optimization.tls.numbers.ExtensionType; + +import static org.pcap4j.util.ByteArrays.SHORT_SIZE_IN_BYTES; + +public class ClientKeyShareExtension extends KeyShareExtension { + + private static final int KEY_SHARE_LENGTH_OFFSET = 0; + private static final int KEY_SHARE_ENTRY_OFFSET = KEY_SHARE_LENGTH_OFFSET + SHORT_SIZE_IN_BYTES; + + private short keyShareLength; + + public ClientKeyShareExtension(ExtensionType type, byte[] rawData, int offset, short extensionLength) { + super(type, extensionLength); + this.keyShareLength = ByteArrays.getShort(rawData, KEY_SHARE_LENGTH_OFFSET + offset); // the field is not always there + int cursor = KEY_SHARE_ENTRY_OFFSET + offset; + ByteArrays.validateBounds(rawData, cursor, keyShareLength); + readEntries(rawData, KEY_SHARE_ENTRY_OFFSET + offset, offset + keyShareLength); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/KeyShareEntry.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/KeyShareEntry.java new file mode 100644 index 0000000..6a12095 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/KeyShareEntry.java @@ -0,0 +1,33 @@ +package ru.serega6531.packmate.service.optimization.tls.extensions.keyshare; + +import org.pcap4j.util.ByteArrays; +import ru.serega6531.packmate.service.optimization.tls.numbers.KeyGroup; + +import static org.pcap4j.util.ByteArrays.SHORT_SIZE_IN_BYTES; + +public class KeyShareEntry { + + private static final int GROUP_OFFSET = 0; + private static final int KEY_EXHANGE_LENGTH_OFFSET = GROUP_OFFSET + SHORT_SIZE_IN_BYTES; + private static final int KEY_EXCHANGE_OFFSET = KEY_EXHANGE_LENGTH_OFFSET + SHORT_SIZE_IN_BYTES; + + private KeyGroup group; + private short keyExhangeLength; + private byte[] keyExchange; + + public KeyShareEntry(byte[] rawData, int offset) { + this.group = KeyGroup.getInstance(ByteArrays.getShort(rawData, GROUP_OFFSET + offset)); + this.keyExhangeLength = ByteArrays.getShort(rawData, KEY_EXHANGE_LENGTH_OFFSET + offset); + keyExchange = new byte[keyExhangeLength]; + System.arraycopy(rawData, KEY_EXCHANGE_OFFSET + offset, keyExchange, 0, keyExhangeLength); + } + + public int size() { + return SHORT_SIZE_IN_BYTES + SHORT_SIZE_IN_BYTES + keyExhangeLength; + } + + @Override + public String toString() { + return group.name(); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/KeyShareExtension.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/KeyShareExtension.java new file mode 100644 index 0000000..354839d --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/KeyShareExtension.java @@ -0,0 +1,46 @@ +package ru.serega6531.packmate.service.optimization.tls.extensions.keyshare; + +import org.pcap4j.util.ByteArrays; +import ru.serega6531.packmate.service.optimization.tls.extensions.TlsExtension; +import ru.serega6531.packmate.service.optimization.tls.numbers.ExtensionType; + +import java.util.ArrayList; +import java.util.List; + +public abstract class KeyShareExtension extends TlsExtension { + + private final List entries = new ArrayList<>(); + + public static KeyShareExtension newInstance(ExtensionType type, byte[] rawData, int offset, + short extensionLength, boolean client) { + ByteArrays.validateBounds(rawData, offset, extensionLength); + + if(client) { + return new ClientKeyShareExtension(type, rawData, offset, extensionLength); + } else { + return new ServerKeyShareExtension(type, rawData, offset, extensionLength); + } + } + + protected KeyShareExtension(ExtensionType type, short extensionLength) { + super(type, extensionLength); + } + + protected void readEntries(byte[] rawData, int cursor, int end) { + while (cursor < end) { + KeyShareEntry entry = readEntry(rawData, cursor); + cursor += entry.size(); + } + } + + protected KeyShareEntry readEntry(byte[] rawData, int cursor) { + KeyShareEntry entry = new KeyShareEntry(rawData, cursor); + entries.add(entry); + return entry; + } + + @Override + public String toString() { + return type.name() + " " + entries.toString(); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/ServerKeyShareExtension.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/ServerKeyShareExtension.java new file mode 100644 index 0000000..e5daa52 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/extensions/keyshare/ServerKeyShareExtension.java @@ -0,0 +1,14 @@ +package ru.serega6531.packmate.service.optimization.tls.extensions.keyshare; + +import ru.serega6531.packmate.service.optimization.tls.numbers.ExtensionType; + +public class ServerKeyShareExtension extends KeyShareExtension { + + private static final int KEY_SHARE_ENTRY_OFFSET = 0; + + public ServerKeyShareExtension(ExtensionType type, byte[] rawData, int offset, short extensionLength) { + super(type, extensionLength); + readEntry(rawData, KEY_SHARE_ENTRY_OFFSET + offset); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/DhClientParams.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/DhClientParams.java new file mode 100644 index 0000000..2b3f9b2 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/DhClientParams.java @@ -0,0 +1,42 @@ +package ru.serega6531.packmate.service.optimization.tls.keys; + +import ru.serega6531.packmate.service.optimization.tls.keys.enums.SignatureScheme; + +public class DhClientParams { + + private final byte[] p; + private final byte[] g; + private final byte[] pubkey; + private final SignatureScheme signatureScheme; + private final byte[] signature; + + public DhClientParams(byte[] p, byte[] g, byte[] pubkey, + SignatureScheme signatureScheme, + byte[] signature) { + this.p = p; + this.g = g; + this.pubkey = pubkey; + this.signatureScheme = signatureScheme; + this.signature = signature; + } + + public byte[] getP() { + return p; + } + + public byte[] getG() { + return g; + } + + public byte[] getPubkey() { + return pubkey; + } + + public SignatureScheme getSignatureScheme() { + return signatureScheme; + } + + public byte[] getSignature() { + return signature; + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/EcdheServerParams.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/EcdheServerParams.java new file mode 100644 index 0000000..4150e31 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/EcdheServerParams.java @@ -0,0 +1,44 @@ +package ru.serega6531.packmate.service.optimization.tls.keys; + +import ru.serega6531.packmate.service.optimization.tls.keys.enums.CurveType; +import ru.serega6531.packmate.service.optimization.tls.keys.enums.NamedCurve; +import ru.serega6531.packmate.service.optimization.tls.keys.enums.SignatureScheme; + +public class EcdheServerParams { + + private final CurveType curveType; + private final NamedCurve namedCurve; + private final byte[] pubkey; + private final SignatureScheme signatureScheme; + private final byte[] signature; + + public EcdheServerParams(CurveType curveType, NamedCurve namedCurve, byte[] pubkey, + SignatureScheme signatureScheme, + byte[] signature) { + this.curveType = curveType; + this.namedCurve = namedCurve; + this.pubkey = pubkey; + this.signatureScheme = signatureScheme; + this.signature = signature; + } + + public CurveType getCurveType() { + return curveType; + } + + public NamedCurve getNamedCurve() { + return namedCurve; + } + + public byte[] getPubkey() { + return pubkey; + } + + public SignatureScheme getSignatureScheme() { + return signatureScheme; + } + + public byte[] getSignature() { + return signature; + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/TlsKeyUtils.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/TlsKeyUtils.java new file mode 100644 index 0000000..faed1af --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/TlsKeyUtils.java @@ -0,0 +1,108 @@ +package ru.serega6531.packmate.service.optimization.tls.keys; + +import ru.serega6531.packmate.service.optimization.tls.keys.enums.CurveType; +import ru.serega6531.packmate.service.optimization.tls.keys.enums.NamedCurve; +import ru.serega6531.packmate.service.optimization.tls.keys.enums.SignatureScheme; + +import java.nio.ByteBuffer; + +/** + * It is impossible to determine key format just by KeyExchange record, + * so you can use this class when analyzing tls traffic. + */ +public final class TlsKeyUtils { + + // https://wiki.osdev.org/TLS_Handshake + + public static DhClientParams parseServerDH(byte[] rawData, int offset) { + ByteBuffer bb = ByteBuffer.wrap(rawData).position(offset); + + short pLength = bb.getShort(); + byte[] p = new byte[pLength]; + bb.get(p); + + short gLength = bb.getShort(); + byte[] g = new byte[gLength]; + bb.get(g); + + short pubKeyLength = bb.getShort(); + byte[] pubKey = new byte[pubKeyLength]; // aka Ys + bb.get(pubKey); + + SignatureScheme signatureScheme = SignatureScheme.findByValue(bb.getShort()); + + if (signatureScheme == null) { + throw new IllegalArgumentException("Unknown signature scheme"); + } + + short signatureLength = bb.getShort(); + byte[] signature = new byte[signatureLength]; + + bb.get(signature); + + return new DhClientParams(p, g, pubKey, signatureScheme, signature); + } + + /** + * @param rawData Handshake record content + */ + public static EcdheServerParams parseServerECDHE(byte[] rawData, int offset) { + ByteBuffer bb = ByteBuffer.wrap(rawData).position(offset); + + byte curveTypeId = bb.get(); + if(curveTypeId != 0x03) { + throw new IllegalArgumentException("Unsupported curve type"); + } + + CurveType curveType = CurveType.NAMED; + NamedCurve namedCurve = NamedCurve.findByValue(bb.getShort()); + + if (namedCurve == null) { + throw new IllegalArgumentException("Unsupported named curve"); + } + + byte pubkeyLength = bb.get(); + byte[] pubkey = new byte[pubkeyLength]; + bb.get(pubkey); + + SignatureScheme signatureScheme = SignatureScheme.findByValue(bb.getShort()); + + if (signatureScheme == null) { + throw new IllegalArgumentException("Unknown signature scheme"); + } + + short signatureLength = bb.getShort(); + byte[] signature = new byte[signatureLength]; + + bb.get(signature); + + return new EcdheServerParams(curveType, namedCurve, pubkey, signatureScheme, signature); + } + + // https://ldapwiki.com/wiki/ClientKeyExchange + + /** + * Suitable for both DH and ECDHE + * @param rawData Handshake record content + */ + public static byte[] getClientDHPubkey(byte[] rawData, int offset) { + ByteBuffer bb = ByteBuffer.wrap(rawData).position(offset); + + byte length = bb.get(); + byte[] pubkey = new byte[length]; + bb.get(pubkey); + + return pubkey; + } + + public static byte[] getClientRsaPreMaster(byte[] rawData, int offset) { + ByteBuffer bb = ByteBuffer.wrap(rawData).position(offset); + + int length = bb.getShort(); + byte[] encryptedPreMaster = new byte[length]; + bb.get(encryptedPreMaster); + + return encryptedPreMaster; + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/enums/CurveType.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/enums/CurveType.java new file mode 100644 index 0000000..3eb2602 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/enums/CurveType.java @@ -0,0 +1,16 @@ +package ru.serega6531.packmate.service.optimization.tls.keys.enums; + +public enum CurveType { + + NAMED((byte) 0x03); + + private final byte value; + + CurveType(byte value) { + this.value = value; + } + + public byte getValue() { + return value; + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/enums/NamedCurve.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/enums/NamedCurve.java new file mode 100644 index 0000000..62fb51a --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/enums/NamedCurve.java @@ -0,0 +1,57 @@ +package ru.serega6531.packmate.service.optimization.tls.keys.enums; + +import java.util.HashMap; +import java.util.Map; + +public enum NamedCurve { + + SECT163K1((short) 1), + SECT163R1((short) 2), + SECT163R2((short) 3), + SECT193R1((short) 4), + SECT193R2((short) 5), + SECT233K1((short) 6), + SECT233R1((short) 7), + SECT239K1((short) 8), + SECT283K1((short) 9), + SECT283R1((short) 10), + SECT409K1((short) 11), + SECT409R1((short) 12), + SECT571K1((short) 13), + SECT571R1((short) 14), + SECP160K1((short) 15), + SECP160R1((short) 16), + SECP160R2((short) 17), + SECP192K1((short) 18), + SECP192R1((short) 19), + SECP224K1((short) 20), + SECP224R1((short) 21), + SECP256K1((short) 22), + SECP256R1((short) 23), + SECP384R1((short) 24), + SECP521R1((short) 25), + X25519((short) 29), + X448((short) 30); + + private final short value; + + private static final Map map = new HashMap<>(); + + NamedCurve(short value) { + this.value = value; + } + + static { + for (NamedCurve curve : values()) { + map.put(curve.getValue(), curve); + } + } + + public short getValue() { + return value; + } + + public static NamedCurve findByValue(short value) { + return map.get(value); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/enums/SignatureScheme.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/enums/SignatureScheme.java new file mode 100644 index 0000000..58a1ba9 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/keys/enums/SignatureScheme.java @@ -0,0 +1,58 @@ +package ru.serega6531.packmate.service.optimization.tls.keys.enums; + +import java.util.HashMap; +import java.util.Map; + +public enum SignatureScheme { + + /* RSASSA-PKCS1-v1_5 algorithms */ + RSA_PKCS1_SHA256((short) 0x0401), + RSA_PKCS1_SHA384((short) 0x0501), + RSA_PKCS1_SHA512((short) 0x0601), + + /* ECDSA algorithms */ + ECDSA_SECP256R1_SHA256((short) 0x0403), + ECDSA_SECP384R1_SHA384((short) 0x0503), + ECDSA_SECP521R1_SHA512((short) 0x0603), + + /* RSASSA-PSS algorithms with public key OID RSAEncryption */ + RSA_PSS_RSAE_SHA256((short) 0x0804), + RSA_PSS_RSAE_SHA384((short) 0x0805), + RSA_PSS_RSAE_SHA512((short) 0x0806), + + /* EDDSA algorithms */ + ED25519((short) 0x0807), + ED448((short) 0x0808), + + /* RSASSA-PSS algorithms with public key OID RSASSA-PSS */ + RSA_PSS_PSS_SHA256((short) 0x0809), + RSA_PSS_PSS_SHA384((short) 0x080a), + RSA_PSS_PSS_SHA512((short) 0x080b), + + /* Legacy algorithms */ + RSA_PKCS1_SHA1((short) 0x0201), + ECDSA_SHA1((short) 0x0203); + + private final short value; + + private static final Map map = new HashMap<>(); + + SignatureScheme(short value) { + this.value = value; + } + + static { + for (SignatureScheme curve : values()) { + map.put(curve.getValue(), curve); + } + } + + public short getValue() { + return value; + } + + public static SignatureScheme findByValue(short value) { + return map.get(value); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/AlertDescription.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/AlertDescription.java new file mode 100644 index 0000000..a56a3c4 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/AlertDescription.java @@ -0,0 +1,65 @@ +package ru.serega6531.packmate.service.optimization.tls.numbers; + +import org.pcap4j.packet.namednumber.NamedNumber; + +import java.util.HashMap; +import java.util.Map; + +public class AlertDescription extends NamedNumber { + + private static final Map registry = new HashMap<>(); + + public static AlertDescription close_notify = new AlertDescription((byte) 0, "close_notify"); + public static AlertDescription unexpected_message = new AlertDescription((byte) 10, "unexpected_message"); + public static AlertDescription bad_record_mac = new AlertDescription((byte) 20, "bad_record_mac"); + public static AlertDescription decryption_failed_RESERVED = new AlertDescription((byte) 21, "decryption_failed_RESERVED"); + public static AlertDescription record_overflow = new AlertDescription((byte) 22, "record_overflow"); + public static AlertDescription decompression_failure_RESERVED = new AlertDescription((byte) 30, "decompression_failure_RESERVED"); + public static AlertDescription handshake_failure = new AlertDescription((byte) 40, "handshake_failure"); + public static AlertDescription no_certificate_RESERVED = new AlertDescription((byte) 41, "no_certificate_RESERVED"); + public static AlertDescription bad_certificate = new AlertDescription((byte) 42, "bad_certificate"); + public static AlertDescription unsupported_certificate = new AlertDescription((byte) 43, "unsupported_certificate"); + public static AlertDescription certificate_revoked = new AlertDescription((byte) 44, "certificate_revoked"); + public static AlertDescription certificate_expired = new AlertDescription((byte) 45, "certificate_expired"); + public static AlertDescription certificate_unknown = new AlertDescription((byte) 46, "certificate_unknown"); + public static AlertDescription illegal_parameter = new AlertDescription((byte) 47, "illegal_parameter"); + public static AlertDescription unknown_ca = new AlertDescription((byte) 48, "unknown_ca"); + public static AlertDescription access_denied = new AlertDescription((byte) 49, "access_denied"); + public static AlertDescription decode_error = new AlertDescription((byte) 50, "decode_error"); + public static AlertDescription decrypt_error = new AlertDescription((byte) 51, "decrypt_error"); + public static AlertDescription export_restriction_RESERVED = new AlertDescription((byte) 60, "export_restriction_RESERVED"); + public static AlertDescription protocol_version = new AlertDescription((byte) 70, "protocol_version"); + public static AlertDescription insufficient_security = new AlertDescription((byte) 71, "insufficient_security"); + public static AlertDescription internal_error = new AlertDescription((byte) 80, "internal_error"); + public static AlertDescription inappropriate_fallback = new AlertDescription((byte) 86, "inappropriate_fallback"); + public static AlertDescription user_canceled = new AlertDescription((byte) 90, "user_canceled"); + public static AlertDescription no_renegotiation_RESERVED = new AlertDescription((byte) 100, "no_renegotiation_RESERVED"); + public static AlertDescription missing_extension = new AlertDescription((byte) 109, "missing_extension"); + public static AlertDescription unsupported_extension = new AlertDescription((byte) 110, "unsupported_extension"); + public static AlertDescription certificate_unobtainable_RESERVED = new AlertDescription((byte) 111, "certificate_unobtainable_RESERVED"); + public static AlertDescription unrecognized_name = new AlertDescription((byte) 112, "unrecognized_name"); + public static AlertDescription bad_certificate_status_response = new AlertDescription((byte) 113, "bad_certificate_status_response"); + public static AlertDescription bad_certificate_hash_value_RESERVED = new AlertDescription((byte) 114, "bad_certificate_hash_value_RESERVED"); + public static AlertDescription unknown_psk_identity = new AlertDescription((byte) 115, "unknown_psk_identity"); + public static AlertDescription certificate_required = new AlertDescription((byte) 116, "certificate_required"); + public static AlertDescription no_application_protocol = new AlertDescription((byte) 120, "no_application_protocol"); + + public AlertDescription(Byte value, String name) { + super(value, name); + registry.put(value, this); + } + + public static AlertDescription getInstance(Byte value) { + if (registry.containsKey(value)) { + return registry.get(value); + } else { + throw new IllegalArgumentException("Unknown alert description: " + value); + } + } + + @Override + public int compareTo(AlertDescription o) { + return value().compareTo(o.value()); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/AlertLevel.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/AlertLevel.java new file mode 100644 index 0000000..e33f489 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/AlertLevel.java @@ -0,0 +1,32 @@ +package ru.serega6531.packmate.service.optimization.tls.numbers; + +import org.pcap4j.packet.namednumber.NamedNumber; + +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("unused") +public class AlertLevel extends NamedNumber { + + private static final Map registry = new HashMap<>(); + + public static final AlertLevel WARNING = new AlertLevel((byte) 1, "warning"); + public static final AlertLevel FATAL = new AlertLevel((byte) 2, "fatal"); + + public static final AlertLevel ENCRYPTED_ALERT = new AlertLevel((byte) 0, "encrypted alert"); + + public AlertLevel(Byte value, String name) { + super(value, name); + registry.put(value, this); + } + + public static AlertLevel getInstance(Byte value) { + return registry.getOrDefault(value, ENCRYPTED_ALERT); + } + + @Override + public int compareTo(AlertLevel o) { + return value().compareTo(o.value()); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/CipherSuite.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/CipherSuite.java new file mode 100644 index 0000000..c92da5c --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/CipherSuite.java @@ -0,0 +1,741 @@ +package ru.serega6531.packmate.service.optimization.tls.numbers; + +import org.pcap4j.packet.namednumber.NamedNumber; + +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("unused") +public class CipherSuite extends NamedNumber { + + private static final Map registry = new HashMap<>(); + + // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml + + public static final CipherSuite TLS_NULL_WITH_NULL_NULL = + new CipherSuite((short) 0x0000, "TLS_NULL_WITH_NULL_NULL"); + public static final CipherSuite TLS_RSA_WITH_NULL_MD5 = + new CipherSuite((short) 0x0001, "TLS_RSA_WITH_NULL_MD5"); + public static final CipherSuite TLS_RSA_WITH_NULL_SHA = + new CipherSuite((short) 0x0002, "TLS_RSA_WITH_NULL_SHA"); + public static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = + new CipherSuite((short) 0x0003, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"); + public static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 = + new CipherSuite((short) 0x0004, "TLS_RSA_WITH_RC4_128_MD5"); + public static final CipherSuite TLS_RSA_WITH_RC4_128_SHA = + new CipherSuite((short) 0x0005, "TLS_RSA_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = + new CipherSuite((short) 0x0006, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"); + public static final CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA = + new CipherSuite((short) 0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA"); + public static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite((short) 0x0008, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA = + new CipherSuite((short) 0x0009, "TLS_RSA_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0x000A, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite((short) 0x000B, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = + new CipherSuite((short) 0x000C, "TLS_DH_DSS_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0x000D, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite((short) 0x000E, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = + new CipherSuite((short) 0x000F, "TLS_DH_RSA_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite((short) 0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = + new CipherSuite((short) 0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite((short) 0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = + new CipherSuite((short) 0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = + new CipherSuite((short) 0x0017, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"); + public static final CipherSuite TLS_DH_anon_WITH_RC4_128_MD5 = + new CipherSuite((short) 0x0018, "TLS_DH_anon_WITH_RC4_128_MD5"); + public static final CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite((short) 0x0019, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA = + new CipherSuite((short) 0x001A, "TLS_DH_anon_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0x001B, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_KRB5_WITH_DES_CBC_SHA = + new CipherSuite((short) 0x001E, "TLS_KRB5_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0x001F, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_KRB5_WITH_RC4_128_SHA = + new CipherSuite((short) 0x0020, "TLS_KRB5_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_KRB5_WITH_IDEA_CBC_SHA = + new CipherSuite((short) 0x0021, "TLS_KRB5_WITH_IDEA_CBC_SHA"); + public static final CipherSuite TLS_KRB5_WITH_DES_CBC_MD5 = + new CipherSuite((short) 0x0022, "TLS_KRB5_WITH_DES_CBC_MD5"); + public static final CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_MD5 = + new CipherSuite((short) 0x0023, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5"); + public static final CipherSuite TLS_KRB5_WITH_RC4_128_MD5 = + new CipherSuite((short) 0x0024, "TLS_KRB5_WITH_RC4_128_MD5"); + public static final CipherSuite TLS_KRB5_WITH_IDEA_CBC_MD5 = + new CipherSuite((short) 0x0025, "TLS_KRB5_WITH_IDEA_CBC_MD5"); + public static final CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = + new CipherSuite((short) 0x0026, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA"); + public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = + new CipherSuite((short) 0x0027, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"); + public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_SHA = + new CipherSuite((short) 0x0028, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA"); + public static final CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = + new CipherSuite((short) 0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"); + public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = + new CipherSuite((short) 0x002A, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"); + public static final CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = + new CipherSuite((short) 0x002B, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"); + public static final CipherSuite TLS_PSK_WITH_NULL_SHA = + new CipherSuite((short) 0x002C, "TLS_PSK_WITH_NULL_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_NULL_SHA = + new CipherSuite((short) 0x002D, "TLS_DHE_PSK_WITH_NULL_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_NULL_SHA = + new CipherSuite((short) 0x002E, "TLS_RSA_PSK_WITH_NULL_SHA"); + public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0x002F, "TLS_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0x003A, "TLS_DH_anon_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_NULL_SHA256 = + new CipherSuite((short) 0x003B, "TLS_RSA_WITH_NULL_SHA256"); + public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0x003C, "TLS_RSA_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA256 = + new CipherSuite((short) 0x003D, "TLS_RSA_WITH_AES_256_CBC_SHA256"); + public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0x003E, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0x003F, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = + new CipherSuite((short) 0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = + new CipherSuite((short) 0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = + new CipherSuite((short) 0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = + new CipherSuite((short) 0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = + new CipherSuite((short) 0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA"); + public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = + new CipherSuite((short) 0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = + new CipherSuite((short) 0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"); + public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = + new CipherSuite((short) 0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = + new CipherSuite((short) 0x006A, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = + new CipherSuite((short) 0x006B, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"); + public static final CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0x006C, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA256 = + new CipherSuite((short) 0x006D, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"); + public static final CipherSuite TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = + new CipherSuite((short) 0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = + new CipherSuite((short) 0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = + new CipherSuite((short) 0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = + new CipherSuite((short) 0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = + new CipherSuite((short) 0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA"); + public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = + new CipherSuite((short) 0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA"); + public static final CipherSuite TLS_PSK_WITH_RC4_128_SHA = + new CipherSuite((short) 0x008A, "TLS_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0x008B, "TLS_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0x008C, "TLS_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0x008D, "TLS_PSK_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_RC4_128_SHA = + new CipherSuite((short) 0x008E, "TLS_DHE_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0x008F, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_RC4_128_SHA = + new CipherSuite((short) 0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_SEED_CBC_SHA = + new CipherSuite((short) 0x0096, "TLS_RSA_WITH_SEED_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_SEED_CBC_SHA = + new CipherSuite((short) 0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_SEED_CBC_SHA = + new CipherSuite((short) 0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_SEED_CBC_SHA = + new CipherSuite((short) 0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_SEED_CBC_SHA = + new CipherSuite((short) 0x009A, "TLS_DHE_RSA_WITH_SEED_CBC_SHA"); + public static final CipherSuite TLS_DH_anon_WITH_SEED_CBC_SHA = + new CipherSuite((short) 0x009B, "TLS_DH_anon_WITH_SEED_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0x009C, "TLS_RSA_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_RSA_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0x009D, "TLS_RSA_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0x009E, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0x009F, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0x00A0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0x00A1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0x00A2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0x00A3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0x00A4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0x00A5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_DH_anon_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0x00A6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_DH_anon_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0x00A7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_PSK_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0x00A8, "TLS_PSK_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_PSK_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0x00A9, "TLS_PSK_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0x00AA, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0x00AB, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0x00AC, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0x00AD, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0x00AE, "TLS_PSK_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA384 = + new CipherSuite((short) 0x00AF, "TLS_PSK_WITH_AES_256_CBC_SHA384"); + public static final CipherSuite TLS_PSK_WITH_NULL_SHA256 = + new CipherSuite((short) 0x00B0, "TLS_PSK_WITH_NULL_SHA256"); + public static final CipherSuite TLS_PSK_WITH_NULL_SHA384 = + new CipherSuite((short) 0x00B1, "TLS_PSK_WITH_NULL_SHA384"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0x00B2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = + new CipherSuite((short) 0x00B3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"); + public static final CipherSuite TLS_DHE_PSK_WITH_NULL_SHA256 = + new CipherSuite((short) 0x00B4, "TLS_DHE_PSK_WITH_NULL_SHA256"); + public static final CipherSuite TLS_DHE_PSK_WITH_NULL_SHA384 = + new CipherSuite((short) 0x00B5, "TLS_DHE_PSK_WITH_NULL_SHA384"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0x00B6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = + new CipherSuite((short) 0x00B7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"); + public static final CipherSuite TLS_RSA_PSK_WITH_NULL_SHA256 = + new CipherSuite((short) 0x00B8, "TLS_RSA_PSK_WITH_NULL_SHA256"); + public static final CipherSuite TLS_RSA_PSK_WITH_NULL_SHA384 = + new CipherSuite((short) 0x00B9, "TLS_RSA_PSK_WITH_NULL_SHA384"); + public static final CipherSuite TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0x00BA, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0x00BB, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0x00BC, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0x00BD, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0x00BE, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0x00BF, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = + new CipherSuite((short) 0x00C0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256"); + public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = + new CipherSuite((short) 0x00C1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256"); + public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = + new CipherSuite((short) 0x00C2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256"); + public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = + new CipherSuite((short) 0x00C3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256"); + public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = + new CipherSuite((short) 0x00C4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256"); + public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = + new CipherSuite((short) 0x00C5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"); + public static final CipherSuite TLS_EMPTY_RENEGOTIATION_INFO_SCSV = + new CipherSuite((short) 0x00FF, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"); + public static final CipherSuite RESERVED_GREASE_0x0A0A = + new CipherSuite((short) 0x0A0A, "Reserved (GREASE)"); + public static final CipherSuite TLS_AES_128_GCM_SHA256 = + new CipherSuite((short) 0x1301, "TLS_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_AES_256_GCM_SHA384 = + new CipherSuite((short) 0x1302, "TLS_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_CHACHA20_POLY1305_SHA256 = + new CipherSuite((short) 0x1303, "TLS_CHACHA20_POLY1305_SHA256"); + public static final CipherSuite TLS_AES_128_CCM_SHA256 = + new CipherSuite((short) 0x1304, "TLS_AES_128_CCM_SHA256"); + public static final CipherSuite RESERVED_GREASE_0x1A1A = + new CipherSuite((short) 0x1A1A, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0x2A2A = + new CipherSuite((short) 0x2A2A, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0x3A3A = + new CipherSuite((short) 0x3A3A, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0x4A4A = + new CipherSuite((short) 0x4A4A, "Reserved (GREASE)"); + public static final CipherSuite TLS_FALLBACK_SCSV = + new CipherSuite((short) 0x5600, "TLS_FALLBACK_SCSV"); + public static final CipherSuite RESERVED_GREASE_0x5A5A = + new CipherSuite((short) 0x5A5A, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0x6A6A = + new CipherSuite((short) 0x6A6A, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0x7A7A = + new CipherSuite((short) 0x7A7A, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0x8A8A = + new CipherSuite((short) 0x8A8A, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0x9A9A = + new CipherSuite((short) 0x9A9A, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0xAAAA = + new CipherSuite((short) 0xAAAA, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0xBABA = + new CipherSuite((short) 0xBABA, "Reserved (GREASE)"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_NULL_SHA = + new CipherSuite((short) 0xC001, "TLS_ECDH_ECDSA_WITH_NULL_SHA"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_RC4_128_SHA = + new CipherSuite((short) 0xC002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0xC003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0xC004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0xC005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_NULL_SHA = + new CipherSuite((short) 0xC006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = + new CipherSuite((short) 0xC007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0xC008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0xC009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0xC00A, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_ECDH_RSA_WITH_NULL_SHA = + new CipherSuite((short) 0xC00B, "TLS_ECDH_RSA_WITH_NULL_SHA"); + public static final CipherSuite TLS_ECDH_RSA_WITH_RC4_128_SHA = + new CipherSuite((short) 0xC00C, "TLS_ECDH_RSA_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0xC00D, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0xC00E, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0xC00F, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_NULL_SHA = + new CipherSuite((short) 0xC010, "TLS_ECDHE_RSA_WITH_NULL_SHA"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_RC4_128_SHA = + new CipherSuite((short) 0xC011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0xC012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0xC013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0xC014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_ECDH_anon_WITH_NULL_SHA = + new CipherSuite((short) 0xC015, "TLS_ECDH_anon_WITH_NULL_SHA"); + public static final CipherSuite TLS_ECDH_anon_WITH_RC4_128_SHA = + new CipherSuite((short) 0xC016, "TLS_ECDH_anon_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0xC017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_ECDH_anon_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0xC018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_ECDH_anon_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0xC019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0xC01A, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0xC01B, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0xC01C, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0xC01D, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0xC01E, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0xC01F, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0xC020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0xC021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0xC022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0xC023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = + new CipherSuite((short) 0xC024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0xC025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = + new CipherSuite((short) 0xC026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0xC027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = + new CipherSuite((short) 0xC028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0xC029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = + new CipherSuite((short) 0xC02A, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0xC02B, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0xC02C, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0xC02D, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0xC02E, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0xC02F, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0xC030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0xC031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0xC032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_RC4_128_SHA = + new CipherSuite((short) 0xC033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite((short) 0xC034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite((short) 0xC035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite((short) 0xC036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = + new CipherSuite((short) 0xC037, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = + new CipherSuite((short) 0xC038, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA = + new CipherSuite((short) 0xC039, "TLS_ECDHE_PSK_WITH_NULL_SHA"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA256 = + new CipherSuite((short) 0xC03A, "TLS_ECDHE_PSK_WITH_NULL_SHA256"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA384 = + new CipherSuite((short) 0xC03B, "TLS_ECDHE_PSK_WITH_NULL_SHA384"); + public static final CipherSuite TLS_RSA_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC03C, "TLS_RSA_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_RSA_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC03D, "TLS_RSA_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC03E, "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC03F, "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC040, "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC041, "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC042, "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC043, "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC044, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC045, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC046, "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC047, "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC048, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC049, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC04A, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC04B, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC04C, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC04D, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC04E, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC04F, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_RSA_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC050, "TLS_RSA_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_RSA_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC051, "TLS_RSA_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC052, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC053, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC054, "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC055, "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC056, "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC057, "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC058, "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC059, "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC05A, "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC05B, "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC05C, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC05D, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC05E, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC05F, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC060, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC061, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC062, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC063, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_PSK_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC064, "TLS_PSK_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_PSK_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC065, "TLS_PSK_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC066, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC067, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC068, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC069, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_PSK_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC06A, "TLS_PSK_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_PSK_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC06B, "TLS_PSK_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC06C, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC06D, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC06E, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256"); + public static final CipherSuite TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC06F, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC074, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC075, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC076, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC077, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC078, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC079, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384"); + public static final CipherSuite TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC07A, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC07B, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC07C, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC07D, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC07E, "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC07F, "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC080, "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC081, "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC082, "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC083, "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC084, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC085, "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC086, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC087, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC088, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC089, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC08A, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC08B, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC08C, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC08D, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC08E, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC08F, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC090, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC091, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = + new CipherSuite((short) 0xC092, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256"); + public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = + new CipherSuite((short) 0xC093, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384"); + public static final CipherSuite TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC094, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC095, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384"); + public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC096, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC097, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"); + public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC098, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = + new CipherSuite((short) 0xC09A, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = + new CipherSuite((short) 0xC09B, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"); + public static final CipherSuite TLS_RSA_WITH_AES_128_CCM = + new CipherSuite((short) 0xC09C, "TLS_RSA_WITH_AES_128_CCM"); + public static final CipherSuite TLS_RSA_WITH_AES_256_CCM = + new CipherSuite((short) 0xC09D, "TLS_RSA_WITH_AES_256_CCM"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CCM = + new CipherSuite((short) 0xC09E, "TLS_DHE_RSA_WITH_AES_128_CCM"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CCM = + new CipherSuite((short) 0xC09F, "TLS_DHE_RSA_WITH_AES_256_CCM"); + public static final CipherSuite TLS_RSA_WITH_AES_128_CCM_8 = + new CipherSuite((short) 0xC0A0, "TLS_RSA_WITH_AES_128_CCM_8"); + public static final CipherSuite TLS_RSA_WITH_AES_256_CCM_8 = + new CipherSuite((short) 0xC0A1, "TLS_RSA_WITH_AES_256_CCM_8"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CCM_8 = + new CipherSuite((short) 0xC0A2, "TLS_DHE_RSA_WITH_AES_128_CCM_8"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CCM_8 = + new CipherSuite((short) 0xC0A3, "TLS_DHE_RSA_WITH_AES_256_CCM_8"); + public static final CipherSuite TLS_PSK_WITH_AES_128_CCM = + new CipherSuite((short) 0xC0A4, "TLS_PSK_WITH_AES_128_CCM"); + public static final CipherSuite TLS_PSK_WITH_AES_256_CCM = + new CipherSuite((short) 0xC0A5, "TLS_PSK_WITH_AES_256_CCM"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CCM = + new CipherSuite((short) 0xC0A6, "TLS_DHE_PSK_WITH_AES_128_CCM"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CCM = + new CipherSuite((short) 0xC0A7, "TLS_DHE_PSK_WITH_AES_256_CCM"); + public static final CipherSuite TLS_PSK_WITH_AES_128_CCM_8 = + new CipherSuite((short) 0xC0A8, "TLS_PSK_WITH_AES_128_CCM_8"); + public static final CipherSuite TLS_PSK_WITH_AES_256_CCM_8 = + new CipherSuite((short) 0xC0A9, "TLS_PSK_WITH_AES_256_CCM_8"); + public static final CipherSuite TLS_PSK_DHE_WITH_AES_128_CCM_8 = + new CipherSuite((short) 0xC0AA, "TLS_PSK_DHE_WITH_AES_128_CCM_8"); + public static final CipherSuite TLS_PSK_DHE_WITH_AES_256_CCM_8 = + new CipherSuite((short) 0xC0AB, "TLS_PSK_DHE_WITH_AES_256_CCM_8"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CCM = + new CipherSuite((short) 0xC0AC, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CCM = + new CipherSuite((short) 0xC0AD, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = + new CipherSuite((short) 0xC0AE, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = + new CipherSuite((short) 0xC0AF, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8"); + public static final CipherSuite TLS_ECCPWD_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0xC0B0, "TLS_ECCPWD_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_ECCPWD_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0xC0B1, "TLS_ECCPWD_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_ECCPWD_WITH_AES_128_CCM_SHA256 = + new CipherSuite((short) 0xC0B2, "TLS_ECCPWD_WITH_AES_128_CCM_SHA256"); + public static final CipherSuite TLS_ECCPWD_WITH_AES_256_CCM_SHA384 = + new CipherSuite((short) 0xC0B3, "TLS_ECCPWD_WITH_AES_256_CCM_SHA384"); + public static final CipherSuite RESERVED_GREASE_0xCACA = + new CipherSuite((short) 0xCACA, "Reserved (GREASE)"); + public static final CipherSuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = + new CipherSuite((short) 0xCCA8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"); + public static final CipherSuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = + new CipherSuite((short) 0xCCA9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"); + public static final CipherSuite TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = + new CipherSuite((short) 0xCCAA, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"); + public static final CipherSuite TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = + new CipherSuite((short) 0xCCAB, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = + new CipherSuite((short) 0xCCAC, "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256"); + public static final CipherSuite TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = + new CipherSuite((short) 0xCCAD, "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256"); + public static final CipherSuite TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = + new CipherSuite((short) 0xCCAE, "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 = + new CipherSuite((short) 0xD001, "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 = + new CipherSuite((short) 0xD002, "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256 = + new CipherSuite((short) 0xD003, "TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256"); + public static final CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256 = + new CipherSuite((short) 0xD005, "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256"); + public static final CipherSuite RESERVED_GREASE_0xDADA = + new CipherSuite((short) 0xDADA, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0xEAEA = + new CipherSuite((short) 0xEAEA, "Reserved (GREASE)"); + public static final CipherSuite RESERVED_GREASE_0xFAFA = + new CipherSuite((short) 0xFAFA, "Reserved (GREASE)"); + + public CipherSuite(Short value, String name) { + super(value, name); + registry.put(value, this); + } + + public static CipherSuite getInstance(Short value) { + if (registry.containsKey(value)) { + return registry.get(value); + } else { + throw new IllegalArgumentException("Unknown cipher suite: " + value); + } + } + + @Override + public int compareTo(CipherSuite o) { + return value().compareTo(o.value()); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/CompressionMethod.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/CompressionMethod.java new file mode 100644 index 0000000..df26377 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/CompressionMethod.java @@ -0,0 +1,38 @@ +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 { + + // https://www.iana.org/assignments/comp-meth-ids/comp-meth-ids.xhtml + + public static final CompressionMethod NULL = new CompressionMethod((byte) 0, "null"); + public static final CompressionMethod DEFLATE = new CompressionMethod((byte) 1, "Deflate"); + public static final CompressionMethod LZS = new CompressionMethod((byte) 64, "LZS"); + + private static final Map 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()); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/ContentType.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/ContentType.java new file mode 100644 index 0000000..6ea9699 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/ContentType.java @@ -0,0 +1,44 @@ +package ru.serega6531.packmate.service.optimization.tls.numbers; + +import org.pcap4j.packet.namednumber.NamedNumber; + +import java.util.HashMap; +import java.util.Map; + +public class ContentType extends NamedNumber { + + // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml + + public static final ContentType CHANGE_CIPHER_SPEC = new ContentType((byte) 20, "Change Cipher Spec"); + public static final ContentType ALERT = new ContentType((byte) 21, "Alert"); + public static final ContentType HANDSHAKE = new ContentType((byte) 22, "Handshake"); + public static final ContentType APPLICATION_DATA = new ContentType((byte) 23, "Application Data"); + public static final ContentType HEARTBEAT = new ContentType((byte) 24, "Heartbeat"); + + private static final Map registry = new HashMap<>(); + + static { + registry.put(CHANGE_CIPHER_SPEC.value(), CHANGE_CIPHER_SPEC); + registry.put(ALERT.value(), ALERT); + registry.put(HANDSHAKE.value(), HANDSHAKE); + registry.put(APPLICATION_DATA.value(), APPLICATION_DATA); + registry.put(HEARTBEAT.value(), HEARTBEAT); + } + + public ContentType(Byte value, String name) { + super(value, name); + } + + public static ContentType getInstance(Byte value) { + if (registry.containsKey(value)) { + return registry.get(value); + } else { + throw new IllegalArgumentException("Unknown record type " + value); + } + } + + @Override + public int compareTo(ContentType o) { + return value().compareTo(o.value()); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/ExtensionType.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/ExtensionType.java new file mode 100644 index 0000000..6fdd6cd --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/ExtensionType.java @@ -0,0 +1,98 @@ +package ru.serega6531.packmate.service.optimization.tls.numbers; + +import org.pcap4j.packet.namednumber.NamedNumber; + +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("unused") +public class ExtensionType extends NamedNumber { + + private static final Map registry = new HashMap<>(); + + public static final ExtensionType SERVER_NAME = new ExtensionType((short) 0, "server_name"); + public static final ExtensionType MAX_FRAGMENT_LENGTH = new ExtensionType((short) 1, "max_fragment_length"); + public static final ExtensionType CLIENT_CERTIFICATE_URL = new ExtensionType((short) 2, "client_certificate_url"); + public static final ExtensionType TRUSTED_CA_KEYS = new ExtensionType((short) 3, "trusted_ca_keys"); + public static final ExtensionType TRUNCATED_HMAC = new ExtensionType((short) 4, "truncated_hmac"); + public static final ExtensionType STATUS_REQUEST = new ExtensionType((short) 5, "status_request"); + public static final ExtensionType USER_MAPPING = new ExtensionType((short) 6, "user_mapping"); + public static final ExtensionType CLIENT_AUTHZ = new ExtensionType((short) 7, "client_authz"); + public static final ExtensionType SERVER_AUTHZ = new ExtensionType((short) 8, "server_authz"); + public static final ExtensionType CERT_TYPE = new ExtensionType((short) 9, "cert_type"); + public static final ExtensionType SUPPORTED_GROUPS = new ExtensionType((short) 10, "supported_groups"); + public static final ExtensionType EC_POINT_FORMATS = new ExtensionType((short) 11, "ec_point_formats"); + public static final ExtensionType SRP = new ExtensionType((short) 12, "srp"); + public static final ExtensionType SIGNATURE_ALGORITHMS = new ExtensionType((short) 13, "signature_algorithms"); + public static final ExtensionType USE_SRTP = new ExtensionType((short) 14, "use_srtp"); + public static final ExtensionType HEARTBEAT = new ExtensionType((short) 15, "heartbeat"); + public static final ExtensionType APPLICATION_LAYER_PROTOCOL_NEGOTIATION = new ExtensionType((short) 16, "application_layer_protocol_negotiation"); + public static final ExtensionType STATUS_REQUEST_V2 = new ExtensionType((short) 17, "status_request_v2"); + public static final ExtensionType SIGNED_CERTIFICATE_TIMESTAMP = new ExtensionType((short) 18, "signed_certificate_timestamp"); + public static final ExtensionType CLIENT_CERTIFICATE_TYPE = new ExtensionType((short) 19, "client_certificate_type"); + public static final ExtensionType SERVER_CERTIFICATE_TYPE = new ExtensionType((short) 20, "server_certificate_type"); + public static final ExtensionType PADDING = new ExtensionType((short) 21, "padding"); + public static final ExtensionType ENCRYPT_THEN_MAC = new ExtensionType((short) 22, "encrypt_then_mac"); + public static final ExtensionType EXTENDED_MASTER_SECRET = new ExtensionType((short) 23, "extended_master_secret"); + public static final ExtensionType TOKEN_BINDING = new ExtensionType((short) 24, "token_binding"); + public static final ExtensionType CACHED_INFO = new ExtensionType((short) 25, "cached_info"); + public static final ExtensionType TLS_LTS = new ExtensionType((short) 26, "tls_lts"); + public static final ExtensionType COMPRESS_CERTIFICATE = new ExtensionType((short) 27, "compress_certificate"); + public static final ExtensionType RECORD_SIZE_LIMIT = new ExtensionType((short) 28, "record_size_limit"); + public static final ExtensionType PWD_PROTECT = new ExtensionType((short) 29, "pwd_protect"); + public static final ExtensionType PWD_CLEAR = new ExtensionType((short) 30, "pwd_clear"); + public static final ExtensionType PASSWORD_SALT = new ExtensionType((short) 31, "password_salt"); + public static final ExtensionType TICKET_PINNING = new ExtensionType((short) 32, "ticket_pinning"); + public static final ExtensionType TLS_CERT_WITH_EXTERN_PSK = new ExtensionType((short) 33, "tls_cert_with_extern_psk"); + public static final ExtensionType DELEGATED_CREDENTIALS = new ExtensionType((short) 34, "delegated_credentials"); + public static final ExtensionType SESSION_TICKET = new ExtensionType((short) 35, "session_ticket"); + public static final ExtensionType PRE_SHARED_KEY = new ExtensionType((short) 41, "pre_shared_key"); + public static final ExtensionType EARLY_DATA = new ExtensionType((short) 42, "early_data"); + public static final ExtensionType SUPPORTED_VERSIONS = new ExtensionType((short) 43, "supported_versions"); + public static final ExtensionType COOKIE = new ExtensionType((short) 44, "cookie"); + public static final ExtensionType PSK_KEY_EXCHANGE_MODES = new ExtensionType((short) 45, "psk_key_exchange_modes"); + public static final ExtensionType CERTIFICATE_AUTHORITIES = new ExtensionType((short) 47, "certificate_authorities"); + public static final ExtensionType OID_FILTERS = new ExtensionType((short) 48, "oid_filters"); + public static final ExtensionType POST_HANDSHAKE_AUTH = new ExtensionType((short) 49, "post_handshake_auth"); + public static final ExtensionType SIGNATURE_ALGORITHMS_CERT = new ExtensionType((short) 50, "signature_algorithms_cert"); + public static final ExtensionType KEY_SHARE = new ExtensionType((short) 51, "key_share"); + public static final ExtensionType TRANSPARENCY_INFO = new ExtensionType((short) 52, "transparency_info"); + public static final ExtensionType CONNECTION_ID = new ExtensionType((short) 53, "connection_id"); + public static final ExtensionType EXTERNAL_ID_HASH = new ExtensionType((short) 55, "external_id_hash"); + public static final ExtensionType EXTERNAL_SESSION_ID = new ExtensionType((short) 56, "external_session_id"); + public static final ExtensionType RESERVED_GREASE_2570 = new ExtensionType((short) 2570, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_6682 = new ExtensionType((short) 6682, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_10794 = new ExtensionType((short) 10794, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_14906 = new ExtensionType((short) 14906, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_19018 = new ExtensionType((short) 19018, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_23130 = new ExtensionType((short) 23130, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_27242 = new ExtensionType((short) 27242, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_31354 = new ExtensionType((short) 31354, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_35466 = new ExtensionType((short) 35466, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_39578 = new ExtensionType((short) 39578, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_43690 = new ExtensionType((short) 43690, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_47802 = new ExtensionType((short) 47802, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_51914 = new ExtensionType((short) 51914, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_56026 = new ExtensionType((short) 56026, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_60138 = new ExtensionType((short) 60138, "Reserved (GREASE)"); + public static final ExtensionType RESERVED_GREASE_64250 = new ExtensionType((short) 64250, "Reserved (GREASE)"); + public static final ExtensionType RENEGOTIATION_INFO = new ExtensionType((short) 65281, "renegotiation_info"); + + public ExtensionType(Short value, String name) { + super(value, name); + registry.put(value, this); + } + + 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()); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/HandshakeType.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/HandshakeType.java new file mode 100644 index 0000000..228f68b --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/HandshakeType.java @@ -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; + +@SuppressWarnings("unused") +public class HandshakeType extends NamedNumber { + + private static final Map registry = new HashMap<>(); + + // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml + + 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 HELLO_VERIFY_REQUEST = new HandshakeType((byte) 3, "Hello Verify Request"); + public static final HandshakeType NEW_SESSION_TICKET = new HandshakeType((byte) 4, "New Session Ticket"); + public static final HandshakeType END_OF_EARLY_DATA = new HandshakeType((byte) 5, "End Of Early Data"); + public static final HandshakeType HELLO_RETRY_REQUEST = new HandshakeType((byte) 6, "Hello Retry Request"); + public static final HandshakeType ENCRYPTED_EXTENSIONS = new HandshakeType((byte) 8, "Encrypted Extensions"); + 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"); + public static final HandshakeType CERTIFICATE_URL = new HandshakeType((byte) 21, "Certificate URL"); + public static final HandshakeType CERTIFICATE_STATUS = new HandshakeType((byte) 22, "Certificate Status"); + public static final HandshakeType SUPPLEMENTAL_DATA = new HandshakeType((byte) 23, "Supplemental Data"); + public static final HandshakeType KEY_UPDATE = new HandshakeType((byte) 24, "Key Update"); + public static final HandshakeType COMPRESSED_CERTIFICATE = new HandshakeType((byte) 25, "Compressed Certificate"); + public static final HandshakeType MESSAGE_HASH = new HandshakeType((byte) 254, "Message Hash"); + + public static final HandshakeType ENCRYPTED_HANDSHAKE_MESSAGE = new HandshakeType((byte) 255, "Encrypted Handshake Message"); + + public HandshakeType(Byte value, String name) { + super(value, name); + registry.put(value, this); + } + + public static HandshakeType getInstance(Byte value) { + return registry.getOrDefault(value, ENCRYPTED_HANDSHAKE_MESSAGE); + } + + @Override + public int compareTo(HandshakeType o) { + return value().compareTo(o.value()); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/HeartbeatMessageType.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/HeartbeatMessageType.java new file mode 100644 index 0000000..a2c293a --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/HeartbeatMessageType.java @@ -0,0 +1,33 @@ +package ru.serega6531.packmate.service.optimization.tls.numbers; + +import org.pcap4j.packet.namednumber.NamedNumber; + +import java.util.HashMap; +import java.util.Map; + +public class HeartbeatMessageType extends NamedNumber { + + private static final Map registry = new HashMap<>(); + + public static final HeartbeatMessageType HEARTBEAT_REQUEST = new HeartbeatMessageType((byte) 1, "heartbeat_request"); + public static final HeartbeatMessageType HEARTBEAT_RESPONSE = new HeartbeatMessageType((byte) 2, "heartbeat_response"); + + public HeartbeatMessageType(Byte value, String name) { + super(value, name); + registry.put(value, this); + } + + public static HeartbeatMessageType getInstance(Byte value) { + if (registry.containsKey(value)) { + return registry.get(value); + } else { + throw new IllegalArgumentException("Unknown heartbeat message type: " + value); + } + } + + @Override + public int compareTo(HeartbeatMessageType o) { + return value().compareTo(o.value()); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/KeyGroup.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/KeyGroup.java new file mode 100644 index 0000000..a278abe --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/KeyGroup.java @@ -0,0 +1,98 @@ +package ru.serega6531.packmate.service.optimization.tls.numbers; + +import org.pcap4j.packet.namednumber.NamedNumber; + +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("unused") +public class KeyGroup extends NamedNumber { + + // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml + + private static final Map registry = new HashMap<>(); + + public static final KeyGroup RESERVED_GREASE_0 = new KeyGroup((short) 0, "Reserved (GREASE)"); + public static final KeyGroup SECT163K1 = new KeyGroup((short) 1, "sect163k1"); + public static final KeyGroup SECT163R1 = new KeyGroup((short) 2, "sect163r1"); + public static final KeyGroup SECT163R2 = new KeyGroup((short) 3, "sect163r2"); + public static final KeyGroup SECT193R1 = new KeyGroup((short) 4, "sect193r1"); + public static final KeyGroup SECT193R2 = new KeyGroup((short) 5, "sect193r2"); + public static final KeyGroup SECT233K1 = new KeyGroup((short) 6, "sect233k1"); + public static final KeyGroup SECT233R1 = new KeyGroup((short) 7, "sect233r1"); + public static final KeyGroup SECT239K1 = new KeyGroup((short) 8, "sect239k1"); + public static final KeyGroup SECT283K1 = new KeyGroup((short) 9, "sect283k1"); + public static final KeyGroup SECT283R1 = new KeyGroup((short) 10, "sect283r1"); + public static final KeyGroup SECT409K1 = new KeyGroup((short) 11, "sect409k1"); + public static final KeyGroup SECT409R1 = new KeyGroup((short) 12, "sect409r1"); + public static final KeyGroup SECT571K1 = new KeyGroup((short) 13, "sect571k1"); + public static final KeyGroup SECT571R1 = new KeyGroup((short) 14, "sect571r1"); + public static final KeyGroup SECP160K1 = new KeyGroup((short) 15, "secp160k1"); + public static final KeyGroup SECP160R1 = new KeyGroup((short) 16, "secp160r1"); + public static final KeyGroup SECP160R2 = new KeyGroup((short) 17, "secp160r2"); + public static final KeyGroup SECP192K1 = new KeyGroup((short) 18, "secp192k1"); + public static final KeyGroup SECP192R1 = new KeyGroup((short) 19, "secp192r1"); + public static final KeyGroup SECP224K1 = new KeyGroup((short) 20, "secp224k1"); + public static final KeyGroup SECP224R1 = new KeyGroup((short) 21, "secp224r1"); + public static final KeyGroup SECP256K1 = new KeyGroup((short) 22, "secp256k1"); + public static final KeyGroup SECP256R1 = new KeyGroup((short) 23, "secp256r1"); + public static final KeyGroup SECP384R1 = new KeyGroup((short) 24, "secp384r1"); + public static final KeyGroup SECP521R1 = new KeyGroup((short) 25, "secp521r1"); + public static final KeyGroup BRAINPOOLP256R1 = new KeyGroup((short) 26, "brainpoolP256r1"); + public static final KeyGroup BRAINPOOLP384R1 = new KeyGroup((short) 27, "brainpoolP384r1"); + public static final KeyGroup BRAINPOOLP512R1 = new KeyGroup((short) 28, "brainpoolP512r1"); + public static final KeyGroup X25519 = new KeyGroup((short) 29, "x25519"); + public static final KeyGroup X448 = new KeyGroup((short) 30, "x448"); + public static final KeyGroup BRAINPOOLP256R1TLS13 = new KeyGroup((short) 31, "brainpoolP256r1tls13"); + public static final KeyGroup BRAINPOOLP384R1TLS13 = new KeyGroup((short) 32, "brainpoolP384r1tls13"); + public static final KeyGroup BRAINPOOLP512R1TLS13 = new KeyGroup((short) 33, "brainpoolP512r1tls13"); + public static final KeyGroup GC256A = new KeyGroup((short) 34, "GC256A"); + public static final KeyGroup GC256B = new KeyGroup((short) 35, "GC256B"); + public static final KeyGroup GC256C = new KeyGroup((short) 36, "GC256C"); + public static final KeyGroup GC256D = new KeyGroup((short) 37, "GC256D"); + public static final KeyGroup GC512A = new KeyGroup((short) 38, "GC512A"); + public static final KeyGroup GC512B = new KeyGroup((short) 39, "GC512B"); + public static final KeyGroup GC512C = new KeyGroup((short) 40, "GC512C"); + public static final KeyGroup CURVESM2 = new KeyGroup((short) 41, "curveSM2"); + public static final KeyGroup FFDHE2048 = new KeyGroup((short) 256, "ffdhe2048"); + public static final KeyGroup FFDHE3072 = new KeyGroup((short) 257, "ffdhe3072"); + public static final KeyGroup FFDHE4096 = new KeyGroup((short) 258, "ffdhe4096"); + public static final KeyGroup FFDHE6144 = new KeyGroup((short) 259, "ffdhe6144"); + public static final KeyGroup FFDHE8192 = new KeyGroup((short) 260, "ffdhe8192"); + public static final KeyGroup RESERVED_GREASE_2570 = new KeyGroup((short) 2570, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_6682 = new KeyGroup((short) 6682, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_10794 = new KeyGroup((short) 10794, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_14906 = new KeyGroup((short) 14906, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_19018 = new KeyGroup((short) 19018, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_23130 = new KeyGroup((short) 23130, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_27242 = new KeyGroup((short) 27242, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_31354 = new KeyGroup((short) 31354, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_35466 = new KeyGroup((short) 35466, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_39578 = new KeyGroup((short) 39578, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_43690 = new KeyGroup((short) 43690, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_47802 = new KeyGroup((short) 47802, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_51914 = new KeyGroup((short) 51914, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_56026 = new KeyGroup((short) 56026, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_60138 = new KeyGroup((short) 60138, "Reserved (GREASE)"); + public static final KeyGroup RESERVED_GREASE_64250 = new KeyGroup((short) 64250, "Reserved (GREASE)"); + public static final KeyGroup ARBITRARY_EXPLICIT_PRIME_CURVES = new KeyGroup((short) 65281, "arbitrary_explicit_prime_curves"); + public static final KeyGroup ARBITRARY_EXPLICIT_CHAR2_CURVES = new KeyGroup((short) 65282, "arbitrary_explicit_char2_curves"); + + public KeyGroup(Short value, String name) { + super(value, name); + registry.put(value, this); + } + + public static KeyGroup getInstance(Short value) { + if (registry.containsKey(value)) { + return registry.get(value); + } else { + return new KeyGroup(value, "Unknown"); + } + } + + @Override + public int compareTo(KeyGroup o) { + return value().compareTo(o.value()); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/TlsVersion.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/TlsVersion.java new file mode 100644 index 0000000..c27ecc5 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/numbers/TlsVersion.java @@ -0,0 +1,41 @@ +package ru.serega6531.packmate.service.optimization.tls.numbers; + +import org.pcap4j.packet.namednumber.NamedNumber; + +import java.util.HashMap; +import java.util.Map; + +public class TlsVersion extends NamedNumber { + + public static final TlsVersion TLS_1_0 = new TlsVersion((short) 0x0301, "TLS 1.0"); + public static final TlsVersion TLS_1_1 = new TlsVersion((short) 0x0302, "TLS 1.1"); + public static final TlsVersion TLS_1_2 = new TlsVersion((short) 0x0303, "TLS 1.2"); + public static final TlsVersion TLS_1_3 = new TlsVersion((short) 0x0304, "TLS 1.3"); + + private static final Map registry = new HashMap<>(); + + static { + registry.put(TLS_1_0.value(), TLS_1_0); + registry.put(TLS_1_1.value(), TLS_1_1); + registry.put(TLS_1_2.value(), TLS_1_2); + registry.put(TLS_1_3.value(), TLS_1_3); + } + + public TlsVersion(Short value, String name) { + super(value, name); + } + + public static TlsVersion getInstance(Short value) { + if (registry.containsKey(value)) { + return registry.get(value); + } else { + return new TlsVersion(value, "unknown"); + } + } + + @Override + public int compareTo(TlsVersion o) { + return value().compareTo(o.value()); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/AlertRecord.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/AlertRecord.java new file mode 100644 index 0000000..df746e9 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/AlertRecord.java @@ -0,0 +1,40 @@ +package ru.serega6531.packmate.service.optimization.tls.records; + +import org.pcap4j.util.ByteArrays; +import ru.serega6531.packmate.service.optimization.tls.numbers.AlertDescription; +import ru.serega6531.packmate.service.optimization.tls.numbers.AlertLevel; + +import static org.pcap4j.util.ByteArrays.BYTE_SIZE_IN_BYTES; + +public class AlertRecord implements TlsRecord { + + private static final int LEVEL_OFFSET = 0; + private static final int DESCRIPTION_OFFSET = LEVEL_OFFSET + BYTE_SIZE_IN_BYTES; + + private int length; + private AlertLevel level; + private AlertDescription description; + + public static AlertRecord newInstance(byte[] rawData, int offset, int length) { + ByteArrays.validateBounds(rawData, offset, length); + return new AlertRecord(rawData, offset, length); + } + + public AlertRecord(byte[] rawData, int offset, int length) { + this.length = length; + this.level = AlertLevel.getInstance(ByteArrays.getByte(rawData, LEVEL_OFFSET + offset)); + + if (level != AlertLevel.ENCRYPTED_ALERT) { + this.description = AlertDescription.getInstance(ByteArrays.getByte(rawData, DESCRIPTION_OFFSET + offset)); + } + } + + @Override + public String toString() { + if (level != AlertLevel.ENCRYPTED_ALERT) { + return " Alert [level: " + level.name() + ", description: " + description.name() + "]"; + } else { + return " Encrypted Alert [" + length + " bytes]"; + } + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/ApplicationDataRecord.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/ApplicationDataRecord.java new file mode 100644 index 0000000..69bfa96 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/ApplicationDataRecord.java @@ -0,0 +1,33 @@ +package ru.serega6531.packmate.service.optimization.tls.records; + +import org.pcap4j.util.ByteArrays; + +public class ApplicationDataRecord implements TlsRecord { + + /** + * 0x0 - Encrypted Application Data + * 0x0 + length - End + */ + + private byte[] data; + + public static ApplicationDataRecord newInstance(byte[] rawData, int offset, int length) { + ByteArrays.validateBounds(rawData, offset, length); + return new ApplicationDataRecord(rawData, offset, length); + } + + public ApplicationDataRecord(byte[] rawData, int offset, int length) { + data = new byte[length]; + System.arraycopy(rawData, offset, data, 0, length); + } + + public byte[] getData() { + return data; + } + + @Override + public String toString() { + return " Encrypted data: [" + data.length + " bytes]"; + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/ChangeCipherSpecRecord.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/ChangeCipherSpecRecord.java new file mode 100644 index 0000000..b6db856 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/ChangeCipherSpecRecord.java @@ -0,0 +1,27 @@ +package ru.serega6531.packmate.service.optimization.tls.records; + +import org.pcap4j.util.ByteArrays; + +public class ChangeCipherSpecRecord implements TlsRecord { + + /** + 0x0 - Change Cipher Spec Message + 0x1 - End + */ + + private byte changeCipherSpecMessage; + + public static ChangeCipherSpecRecord newInstance(byte[] rawData, int offset, int length) { + ByteArrays.validateBounds(rawData, offset, length); + return new ChangeCipherSpecRecord(rawData, offset); + } + + private ChangeCipherSpecRecord(byte[] rawData, int offset) { + this.changeCipherSpecMessage = ByteArrays.getByte(rawData, offset); + } + + @Override + public String toString() { + return " Change Cipher Spec Message: " + changeCipherSpecMessage; + } +} 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 new file mode 100644 index 0000000..e9a2317 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HandshakeRecord.java @@ -0,0 +1,73 @@ +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.*; +import ru.serega6531.packmate.utils.BytesUtils; + +import static org.pcap4j.util.ByteArrays.BYTE_SIZE_IN_BYTES; + +public class HandshakeRecord implements TlsRecord { + + /* + 0x0 - Handshake type + 0x1 - Handshake length + 0x4 - Handshake version + 0x6 - Handshake content + */ + + private static final int HANDSHAKE_TYPE_OFFSET = 0; + private static final int LENGTH_OFFSET = HANDSHAKE_TYPE_OFFSET + BYTE_SIZE_IN_BYTES; + private static final int CONTENT_OFFSET = LENGTH_OFFSET + 3; + + private HandshakeType handshakeType; + private int handshakeLength; // 3 bytes + private HandshakeRecordContent content; + + public static HandshakeRecord newInstance(byte[] rawData, int offset, int length) { + ByteArrays.validateBounds(rawData, offset, 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.ENCRYPTED_HANDSHAKE_MESSAGE) { + this.handshakeLength = length; + this.content = BasicHandshakeRecordContent.newInstance( + rawData, offset, handshakeLength); + return; + } + + this.handshakeLength = BytesUtils.getThreeBytesInt(rawData, LENGTH_OFFSET + offset); + + if (handshakeType == HandshakeType.CLIENT_HELLO) { + this.content = ClientHelloHandshakeRecordContent.newInstance( + rawData, offset + CONTENT_OFFSET, handshakeLength); + } 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 = BasicHandshakeRecordContent.newInstance( + rawData, offset + CONTENT_OFFSET, handshakeLength); + } + } + + public HandshakeType getHandshakeType() { + return handshakeType; + } + + public HandshakeRecordContent getContent() { + return content; + } + + @Override + public String toString() { + return " Handshake length: " + handshakeLength + "\n" + + " Handshake type: " + handshakeType + "\n" + + content.toString(); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HeartbeatRecord.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HeartbeatRecord.java new file mode 100644 index 0000000..8628d43 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/HeartbeatRecord.java @@ -0,0 +1,53 @@ +package ru.serega6531.packmate.service.optimization.tls.records; + +import org.pcap4j.util.ByteArrays; +import ru.serega6531.packmate.service.optimization.tls.numbers.HeartbeatMessageType; + +import static org.pcap4j.util.ByteArrays.BYTE_SIZE_IN_BYTES; +import static org.pcap4j.util.ByteArrays.SHORT_SIZE_IN_BYTES; + +public class HeartbeatRecord implements TlsRecord { + + //https://tools.ietf.org/html/rfc6520 + + private static final int TYPE_OFFSET = 0; + private static final int PAYLOAD_LENGTH_OFFSET = TYPE_OFFSET + BYTE_SIZE_IN_BYTES; + private static final int PAYLOAD_OFFSET = PAYLOAD_LENGTH_OFFSET + SHORT_SIZE_IN_BYTES; + + private HeartbeatMessageType type; + private short payloadLength; + private byte[] payload; + private byte[] padding; + + public static HeartbeatRecord newInstance(byte[] rawData, int offset, int length) { + ByteArrays.validateBounds(rawData, offset, length); + return new HeartbeatRecord(rawData, offset, length); + } + + public HeartbeatRecord(byte[] rawData, int offset, int length) { + this.type = HeartbeatMessageType.getInstance(ByteArrays.getByte(rawData, TYPE_OFFSET + offset)); + this.payloadLength = ByteArrays.getShort(rawData, PAYLOAD_LENGTH_OFFSET + offset); + this.payload = ByteArrays.getSubArray(rawData, PAYLOAD_OFFSET + offset, payloadLength); + this.padding = ByteArrays.getSubArray(rawData, PAYLOAD_OFFSET + payloadLength + offset); + } + + public HeartbeatMessageType getType() { + return type; + } + + public byte[] getPayload() { + return payload; + } + + public byte[] getPadding() { + return padding; + } + + @Override + public String toString() { + return " Heartbeat (" + type.name() + + ") [" + payloadLength + " bytes payload, " + + padding.length + " bytes padding]"; + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/TlsRecord.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/TlsRecord.java new file mode 100644 index 0000000..dac0f68 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/TlsRecord.java @@ -0,0 +1,7 @@ +package ru.serega6531.packmate.service.optimization.tls.records; + +import java.io.Serializable; + +public interface TlsRecord extends Serializable { + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicHandshakeRecordContent.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicHandshakeRecordContent.java new file mode 100644 index 0000000..a0a4b8f --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/BasicHandshakeRecordContent.java @@ -0,0 +1,36 @@ +package ru.serega6531.packmate.service.optimization.tls.records.handshakes; + +import org.pcap4j.util.ByteArrays; + +public class BasicHandshakeRecordContent implements HandshakeRecordContent { + + /** + * 0x0 - Content + * 0x0 + length - End + */ + + private byte[] content; + + public static BasicHandshakeRecordContent newInstance(byte[] rawData, int offset, int length) { + if(length > 0) { + ByteArrays.validateBounds(rawData, offset, length); + } + return new BasicHandshakeRecordContent(rawData, offset, length); + } + + public BasicHandshakeRecordContent(byte[] rawData, int offset, int length) { + content = new byte[length]; + if (length > 0) { + System.arraycopy(rawData, offset, content, 0, length); + } + } + + public byte[] getContent() { + return content; + } + + @Override + public String toString() { + return " [" + content.length + " bytes]"; + } +} 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..ddad7bb --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/CertificateHandshakeRecordContent.java @@ -0,0 +1,52 @@ +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; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(" Chain length: " + rawCertificates.size()); + + for (byte[] cert : rawCertificates) { + sb.append('\n'); + sb.append(" [").append(cert.length).append(" bytes]"); + } + + return sb.toString(); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/ClientHelloHandshakeRecordContent.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/ClientHelloHandshakeRecordContent.java new file mode 100644 index 0000000..b642e5c --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/ClientHelloHandshakeRecordContent.java @@ -0,0 +1,82 @@ +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 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 extends HelloHandshakeRecordContent { + + /* + 0x0 - Client random + 0x20 - Session id length (sidl) + 0x21 - Session id + 0x21+sidl - Cipher suites length (csl) + 0x23+sidl - Cipher suite 1..(csl/2) + 0x23+sidl+csl - Compression methods length (cml) + 0x24+sidl+csl - Compression method 1..cml + 0x24+sidl+csl+cml - Extensions Length (el) + 0x26+sidl+csl+cml - Extension 1..N + 0x26+sidl+csl+cml+el - End + */ + + private static final int CIPHER_SUITES_LENGTH_OFFSET = HelloHandshakeRecordContent.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_LENGTH_OFFSET = + COMPRESSION_METHOD_OFFSET; // + sessionIdLength + cipherSuitesLength + compressionMethodsLength + private static final int EXTENSIONS_OFFSET = COMPRESSION_METHOD_OFFSET + SHORT_SIZE_IN_BYTES; + + private short cipherSuitesLength; + private List cipherSuites; + private byte compressionMethodsLength; + private List compressionMethods; + + public static ClientHelloHandshakeRecordContent newInstance(byte[] rawData, int offset, int length) { + ByteArrays.validateBounds(rawData, offset, length); + return new ClientHelloHandshakeRecordContent(rawData, offset); + } + + private ClientHelloHandshakeRecordContent(byte[] rawData, int offset) { + readCommonPart(rawData, offset); + + 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, + EXTENSIONS_LENGTH_OFFSET + compressionMethodsLength + sessionIdLength + cipherSuitesLength + offset); + + readExtensions(rawData, EXTENSIONS_OFFSET + compressionMethodsLength + + sessionIdLength + cipherSuitesLength + offset, true); + } + + @Override + public String toString() { + return super.toString() + "\n" + + " Cipher suites: " + cipherSuites.toString() + "\n" + + " Compression methods: " + compressionMethods.toString(); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/HandshakeRecordContent.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/HandshakeRecordContent.java new file mode 100644 index 0000000..1676cca --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/HandshakeRecordContent.java @@ -0,0 +1,4 @@ +package ru.serega6531.packmate.service.optimization.tls.records.handshakes; + +public interface HandshakeRecordContent { +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/HelloHandshakeRecordContent.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/HelloHandshakeRecordContent.java new file mode 100644 index 0000000..84bf537 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/HelloHandshakeRecordContent.java @@ -0,0 +1,81 @@ +package ru.serega6531.packmate.service.optimization.tls.records.handshakes; + +import org.pcap4j.util.ByteArrays; +import ru.serega6531.packmate.service.optimization.tls.extensions.TlsExtension; +import ru.serega6531.packmate.service.optimization.tls.numbers.ExtensionType; +import ru.serega6531.packmate.service.optimization.tls.numbers.TlsVersion; + +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 abstract class HelloHandshakeRecordContent implements HandshakeRecordContent { + + private static final int VERSION_OFFSET = 0; + private static final int RANDOM_OFFSET = VERSION_OFFSET + SHORT_SIZE_IN_BYTES; + private static final int SESSION_ID_LENGTH_OFFSET = RANDOM_OFFSET + 32; + protected static final int SESSION_ID_OFFSET = SESSION_ID_LENGTH_OFFSET + BYTE_SIZE_IN_BYTES; + + protected TlsVersion version; + protected byte[] random = new byte[32]; + protected byte sessionIdLength; + protected byte[] sessionId; + + protected short extensionsLength; + private List extensions; + + protected void readCommonPart(byte[] rawData, int 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); + } + } + + protected void readExtensions(byte[] rawData, int offset, boolean client) { + extensions = new ArrayList<>(extensionsLength); + + int cursor = 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; + + extensions.add(TlsExtension.newInstance(extensionType, rawData, cursor, extensionLength, client)); + + cursor += extensionLength; + } + } + + public TlsVersion getVersion() { + return version; + } + + public byte[] getRandom() { + return random; + } + + public byte[] getSessionId() { + return sessionId; + } + + public List getExtensions() { + return extensions; + } + + @Override + public String toString() { + return " TLS version: " + version + "\n" + + " Random: " + ByteArrays.toHexString(random, "") + "\n" + + " Session id: " + (sessionIdLength > 0 ? ByteArrays.toHexString(sessionId, "") : "null") + "\n" + + " Extensions: " + extensions.toString(); + } +} diff --git a/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/ServerHelloHandshakeRecordContent.java b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/ServerHelloHandshakeRecordContent.java new file mode 100644 index 0000000..6cd3cc0 --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/optimization/tls/records/handshakes/ServerHelloHandshakeRecordContent.java @@ -0,0 +1,64 @@ +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 static org.pcap4j.util.ByteArrays.BYTE_SIZE_IN_BYTES; +import static org.pcap4j.util.ByteArrays.SHORT_SIZE_IN_BYTES; + +public class ServerHelloHandshakeRecordContent extends HelloHandshakeRecordContent { + + /* + 0x0 - Server random + 0x20 - Session id length (sidl) + 0x21 - Session id + 0x21+si - Cipher suite + 0x23+sidl - Compression method + 0x24+sidl - Extensions Length (el) + 0x26+sidl - Extension 1..N + 0x26+sidl+el - End + */ + + private static final int CIPHER_SUITE_OFFSET = HelloHandshakeRecordContent.SESSION_ID_OFFSET; // + sessionIdLength + private static final int COMPRESSION_METHOD_OFFSET = CIPHER_SUITE_OFFSET + SHORT_SIZE_IN_BYTES; // + sessionIdLength + private static final int EXTENSIONS_LENGTH_OFFSET = COMPRESSION_METHOD_OFFSET + BYTE_SIZE_IN_BYTES; // + sessionIdLength + private static final int EXTENSIONS_OFFSET = EXTENSIONS_LENGTH_OFFSET + SHORT_SIZE_IN_BYTES; // + sessionIdLength + + private CipherSuite cipherSuite; + private CompressionMethod compressionMethod; + + public static ServerHelloHandshakeRecordContent newInstance(byte[] rawData, int offset, int length) { + ByteArrays.validateBounds(rawData, offset, length); + return new ServerHelloHandshakeRecordContent(rawData, offset); + } + + public ServerHelloHandshakeRecordContent(byte[] rawData, int offset) { + readCommonPart(rawData, offset); + + this.cipherSuite = CipherSuite.getInstance(ByteArrays.getShort(rawData, + CIPHER_SUITE_OFFSET + sessionIdLength + offset)); + this.compressionMethod = CompressionMethod.getInstance(ByteArrays.getByte(rawData, + COMPRESSION_METHOD_OFFSET + sessionIdLength + offset)); + + this.extensionsLength = ByteArrays.getShort(rawData, + EXTENSIONS_LENGTH_OFFSET + sessionIdLength + offset); + readExtensions(rawData, EXTENSIONS_OFFSET + sessionIdLength + offset, false); + } + + public CipherSuite getCipherSuite() { + return cipherSuite; + } + + public CompressionMethod getCompressionMethod() { + return compressionMethod; + } + + @Override + public String toString() { + return super.toString() + "\n" + + " Cipher suite: " + cipherSuite.toString() + "\n" + + " Compression method: " + compressionMethod.toString(); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/utils/BytesUtils.java b/src/main/java/ru/serega6531/packmate/utils/BytesUtils.java index 2d08bce..acf0891 100644 --- a/src/main/java/ru/serega6531/packmate/utils/BytesUtils.java +++ b/src/main/java/ru/serega6531/packmate/utils/BytesUtils.java @@ -1,12 +1,18 @@ package ru.serega6531.packmate.utils; 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 public class BytesUtils { /** - * @param array где ищем + * @param array где ищем * @param target что ищем */ public int indexOf(byte[] array, byte[] target, int start, int end) { @@ -27,16 +33,16 @@ public class BytesUtils { } /** - * @param array где ищем + * @param array где ищем * @param target что ищем */ public boolean endsWith(byte[] array, byte[] target) { - if(array.length < target.length) { + if (array.length < target.length) { return false; } 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; } } @@ -44,4 +50,37 @@ public class BytesUtils { 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])); + } + } + } diff --git a/src/main/java/ru/serega6531/packmate/utils/PacketUtils.java b/src/main/java/ru/serega6531/packmate/utils/PacketUtils.java index 459e427..cd4a057 100644 --- a/src/main/java/ru/serega6531/packmate/utils/PacketUtils.java +++ b/src/main/java/ru/serega6531/packmate/utils/PacketUtils.java @@ -4,6 +4,7 @@ import lombok.experimental.UtilityClass; import org.apache.commons.lang3.ArrayUtils; import ru.serega6531.packmate.model.Packet; +import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -16,4 +17,29 @@ public class PacketUtils { .reduce(ArrayUtils::addAll); } + public List> sliceToSides(List packets) { + List> result = new ArrayList<>(); + List side = new ArrayList<>(); + boolean incoming = true; + + for (Packet packet : packets) { + if(packet.isIncoming() != incoming) { + incoming = packet.isIncoming(); + + if(!side.isEmpty()) { + result.add(side); + side = new ArrayList<>(); + } + } + + side.add(packet); + } + + if(!side.isEmpty()) { + result.add(side); + } + + return result; + } + } diff --git a/src/test/java/ru/serega6531/packmate/PackmateDumpFileLoader.java b/src/test/java/ru/serega6531/packmate/PackmateDumpFileLoader.java new file mode 100644 index 0000000..1391ff3 --- /dev/null +++ b/src/test/java/ru/serega6531/packmate/PackmateDumpFileLoader.java @@ -0,0 +1,42 @@ +package ru.serega6531.packmate; + +import org.springframework.security.crypto.codec.Hex; +import ru.serega6531.packmate.model.Packet; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +public class PackmateDumpFileLoader { + + private final File file; + + public PackmateDumpFileLoader(String path) { + this.file = new File(getClass().getClassLoader().getResource(path).getFile()); + } + + public List getPackets() throws IOException { + boolean in = true; + List packets = new ArrayList<>(); + + for (String line : Files.readAllLines(file.toPath())) { + if (line.startsWith("#")) { + continue; + } + + switch (line) { + case "in" -> in = true; + case "out" -> in = false; + default -> packets.add(Packet.builder() + .content(Hex.decode(line)) + .incoming(in) + .build()); + } + } + + return packets; + } + +} diff --git a/src/test/java/ru/serega6531/packmate/TlsDecryptorTest.java b/src/test/java/ru/serega6531/packmate/TlsDecryptorTest.java new file mode 100644 index 0000000..7e98927 --- /dev/null +++ b/src/test/java/ru/serega6531/packmate/TlsDecryptorTest.java @@ -0,0 +1,39 @@ +package ru.serega6531.packmate; + +import org.junit.jupiter.api.Test; +import ru.serega6531.packmate.model.Packet; +import ru.serega6531.packmate.service.optimization.RsaKeysHolder; +import ru.serega6531.packmate.service.optimization.TlsDecryptor; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class TlsDecryptorTest { + + @Test + public void testDecryptTls() throws IOException { + List packets = new PackmateDumpFileLoader("tls.pkmt").getPackets(); + + RsaKeysHolder keysHolder = new RsaKeysHolder(); + File keyFile = new File(getClass().getClassLoader().getResource("tls.key").getFile()); + keysHolder.addKey(keyFile); + + TlsDecryptor decryptor = new TlsDecryptor(packets, keysHolder); + decryptor.decryptTls(); + + assertTrue(decryptor.isParsed(), "TLS not parsed"); + List parsed = decryptor.getParsedPackets(); + assertNotNull(parsed, "Parsed packets list is null"); + + parsed.forEach(p -> System.out.println(p.getContentString())); + + assertEquals(4, parsed.size(), "Wrong packets list size"); + + assertTrue(new String(parsed.get(0).getContent()).startsWith("GET /"), "Wrong content at the start"); + assertTrue(new String(parsed.get(3).getContent()).endsWith("Not Found\n"), "Wrong content at the end"); + } + +} diff --git a/src/test/resources/tls.key b/src/test/resources/tls.key new file mode 100644 index 0000000..3b9801a --- /dev/null +++ b/src/test/resources/tls.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDWJO65om/5LMA0 +8w9Uk36h4ukQ7Qt8nbpbeHzxorl4lGwWBASEAEmDYNUcGO0CxglOE93F9BPNGn6q +Vj8Ypp3kcTGOzsXcFrd0wRpXbSwbynnmqTCYigiLzIidasfUrGul4s1fVZFdkQZS +p2Y5pEUxq1GKcAgCVwjMyWC1dhGqvTcA5ps0JoSRoA+Nzs/BeTHlTm8UvT9eD9ER +8RmYVOi1edcJ/eztj1CVydq5X27QNmwLuqsAwq38I27nlq1NU5ShqDQ16bg8IY/c +Ll4QJB7SVbrLf3dJ7KY5i7DNEoYUiJGRwDJZt+wcZLtFSzj0cn0BuEU6M0PYglUI +uQTeosUZAgMBAAECggEAehq7CJyHzoPm4QpLDoW/qh1RmfYgG6FwVqHgVIPdz9SJ +wQ/vZzkmscPwIEJSOsejHKMVTL983vGhkgz1k1/GHjEw+eYLShCl8Ov+0iUNBpew +ZIbKj9/9OYGZ0HDHmwvpocAuLJME/V4pRc3v6yQw1D6EkzSITJVGDkcxXqcBMeIA +uNVr+pwLH9vO7ybva+e3T4ROWxlecHrcB94THops4fy5+SGVILwvKaP4cRhjLfD4 +2XV4O5N0imdPAYsNNHyHbAzjvZPoCOsuH3B/tWmRHq3oOa4ZcFUNTDmO9GgfbtY/ +PHEFV34XxMjy3bK0vLxHqS9CEj1cvfq8e1NqkDTugQKBgQD6CEezGf9OFb3byBui +X3OzXWdWQ5jnodOTPb/P+y9DrORJPy1/0BcXh/cHF58kNDZvzVwTFcAjfx6bxS41 +JAddFRZjNuHXEOtFRkD3Wp4W7Atrv/yeKbpE9PCaNYtUDasL8RKcdJiHNFpN4xRl +jpQtIiQ9pikrjUXLgW0S88zzyQKBgQDbQV+DMxGS2Cee6nfMmUcGjgQd8D0cXLjk +OZSmEnk4FCvV8ZdysjirqmuitFTE+PYmOJzhlQl8lubEs4Kc7L9CfEwbK9mNN0ZG +BNdT21nFuJp7YoZzZDTHuwF0nBjQFYcdaWDW+qFqrqs9mKbmCQ5vSzql6al+pzdX +X/YS0QTO0QKBgDUMprHQdUPLByJnnb1gxTqsOa2q3/ldc3eNJXJqWAfi2fjUh8HT +k+KxPW9qyqAy1832429FMSQW55ajSn+J6moMfFiGn3ozI8fp9QTGXD5+zJmK/X1N +WzEgSyBc9ffago0hFBLQBkDBkdtur7gwfS3qTYgrBhcwfTuFdXAM/FJJAoGABIQ2 +OXel1waI2mcuDJLjuajXQN6gA6ONU3Y0L6+Vu6f+tyuA2SX+sNqT2Qgp7tzKBUOJ +R8RQK7bYDhk8iYr+7Zmt36lpk9Udp3eWD+4mzUHePMhsyJe51pttjj9g63hmDh8L +laIYDSCH+n7YgUiSeYxtKtnDWg6Lv0sEwKJ5nOECgYBsF5PoHRE4Q/Vs18qbI4t/ +zPwWWNP0sb3PYRlWLTKMBowQdDOxnXAF12txoLNhpOn9DjZdNEb2EMsqlzdNjphN +uUWZq89d5kDwKfj4ji087elcjsW79R5oqwrN8a0NimftZ4eBPbcn8Y0r5psPcSzE +36iKGM2euQYD8Ub+aDOSLQ== +-----END PRIVATE KEY----- diff --git a/src/test/resources/tls.pkmt b/src/test/resources/tls.pkmt new file mode 100644 index 0000000..13efa36 --- /dev/null +++ b/src/test/resources/tls.pkmt @@ -0,0 +1,20 @@ +in +#client hello +1603010200010001fc0303ab8a3d448fd31533fdd5673dbb1989b4dcd4bb74298b5e07b4c0bbcc377b1b0c20c8c34a4cf2946e46539b82a01b1d1839a2dd9992c84e3a61b6bc093476014f2b00221a1a130113021303c02bc02fc02cc030cca9cca8c013c014009c009d002f0035000a010001919a9a00000000000f000d00000a746c73746573742e727500170000ff01000100000a000a00086a6a001d00170018000b00020100002300000010000e000c02683208687474702f312e31000500050100000000000d00140012040308040401050308050501080606010201001200000033002b00296a6a000100001d002051384ff2b9214f63167a3853f5a52edbbc7c69ffc92362e683f435581bf65470002d00020101002b000b0adada0304030303020301001b00030200028a8a000100001500ce0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +out +#server hello, certificate, server hello done +160303003b020000370303c265ca0eb2c8ed4c9dac81c7dcdc59af00a6e16069224c1d1a8b29a0cb70da6600003500000f00230000ff01000100000b0002010016030303190b00031500031200030f3082030b308201f3a00302010202143a6065239cb8878b4b71c4faad1de64b4c548593300d06092a864886f70d01010b050030153113301106035504030c0a746c73746573742e7275301e170d3230303432363030303033315a170d3437303931323030303033315a30153113301106035504030c0a746c73746573742e727530820122300d06092a864886f70d01010105000382010f003082010a0282010100d624eeb9a26ff92cc034f30f54937ea1e2e910ed0b7c9dba5b787cf1a2b978946c1604048400498360d51c18ed02c6094e13ddc5f413cd1a7eaa563f18a69de471318ecec5dc16b774c11a576d2c1bca79e6a930988a088bcc889d6ac7d4ac6ba5e2cd5f55915d910652a76639a44531ab518a7008025708ccc960b57611aabd3700e69b34268491a00f8dcecfc17931e54e6f14bd3f5e0fd111f1199854e8b579d709fdeced8f5095c9dab95f6ed0366c0bbaab00c2adfc236ee796ad4d5394a1a83435e9b83c218fdc2e5e10241ed255bacb7f7749eca6398bb0cd128614889191c03259b7ec1c64bb454b38f4727d01b8453a3343d8825508b904dea2c5190203010001a3533051301d0603551d0e04160414da78a59601d5fd5c44d117f9b1594d6c4a20b3c7301f0603551d23041830168014da78a59601d5fd5c44d117f9b1594d6c4a20b3c7300f0603551d130101ff040530030101ff300d06092a864886f70d01010b05000382010100d0216187f73b06904b95c565f8d105d92fbbd927599a58ff4bd3609ea250dafdf3a92e5c4ba421b0ceaaf61361911bed7b3045396c6e207821d29679c1816df9b43cc17544848c0eb0021f2c925b68a522c8cac6bc00c0d27eb254af10c21a885d64da4cf1f099ae355d5ec1f62922b6330604bb0536d987797bed9227a424c2eb21131f782871f5f2edf3bcd2cea97d4119f60c2e5c2e16094852bb2ec6b6cfdd2b0ad61313c3b4eeff9d20e30529d6f30ed596ec3231c652c429f5e3dfcfc08b605ab9eecfe9208332045d5df839cc2557c27469a81ebd9107696309b6cc44599716645f03e8906e6159eba1d527fbb83bdee87d68d65afb3bc7a085a8292116030300040e000000 +in +#client key exchange, change cipher spec, finished +1603030106100001020100998d0154e87f4048ccdffae2e503c8615219a5cc8499a42e3ac8290fe68ed6698d5648972c118cbb55fd3145f971e6ad32c8c53d3ffbaf9aafba4fe19bb6877e24517fba2c10e3265c0899efe3d57c048f4595ad22095c8f830f98436a9ebb0dd2d4ebfbbaccacd37673d64a1b804cb84e5ec12a9925e8842d611e50f73f5a3510deefdadf2156cad25bf7503a889bd2ebe7d222774ec7ddb52e5bd0d0a56a3fadcd08d8a4c14b749f4f81dae032bc749a7032c26cd3d08ba1d9b386c129dec7f875ad9c6364fc49788058ff1c97d4c0bf40afd9b622a566e396cfffa3cecefa0e76c04d4ca80d390bb13d89f23c4db1c9ba57d6cac497361be40cf3bba989e31403030001011603030040cda408fd8118f3025a92763bf57842110aec599d4b94cb336cee8b76a71c501798d2a109451c5e9a491aa1746d6f4c69e6ccd1960fbc506cb8fc8780d6456c47 +out +#new session ticket, change cipher spec, finished +16030300820400007e0000000000788f7158dae3bcd35ca7ad66cf29e1a3cfcd3d0c0e1f2e09e57d9820aedbecd5cba3abdaabd13313c19d9bedba00f78989b3662146baeaee90e559659b1dc573c452f8ac3daaf55ab76dfb222914570fda59af14a4fe251c4822bd6ea4f027ab3cc407d73b4e62e6e7412daa5010327583b7946eb94311a1c71403030001011603030040a0ba33f39ea69d4d1e3a220488de43df968a898913d6ddb7875d45f586807b4ef91eff357207b6b31a38e846fa34ad60b39e730caea56d8fbed2fdf0d49fa3af +in +17030302701cd53193e3cbd28fb3f5d651c02299e5963b02ac3c865fcabf27dc798c8c9a9450029e072e39b81776c5533c091e6fa42405a19551322b1102dd2855c3007069ecb80343a5cb79e28b75a30d0f1d998e482e7ad109bb5b4fa0c3537fb0d3c3c083d48c55eb78ec23c62b1d73c2d3d9d109625da5c0585ad9549aa658a78a8aa5b303880c6f8ea7ddbfe2b6b57da40f5c31a48bf98d29e03e3607ab96059c9abdbe47dc30bdeb19dfad82d0994dac7c4ae3c70853fd92a3fd277b72024a816affbcd06c0ed43933f491c696008140c53fb5b7add6b42b9d83104b8406dc1123d110f101b7067335539f5798844735426e48ef79fd11af3b2bc5a772071f9fde764122d85b842086ea5f80b6f1a19a6fb80206acfa383f29844de6a0cbe6abd764e173667b997f665aa14e3e04fd67c96e53b4d289ea0392f98a304113e0fbbb2c7994f005439973d2f89f8c41cb897ae39228a106654867187f1f703edded36202d6dcf9d86e2080412e890ae26b2dc1e6ae452bccc3ef941c236172e0e83336950dd5cee527e37db25ca2142669ae2e1bc84c08c00d449c514ce80f11f401e4744167a755b108f13d3a1f428b2bc256bbbfe0bea3bbcb256c8016c90870ca334086339c6bde85d8a28990b285514acad9982a15ae8f9381c61a5adf5be77e45866d40fa42e3ec8041ae76289c5af5bf6bcad46f1d3f29dd81a6cc9c77b82a6e9f15d05c6747e74915231f433e027b240abcdd7aae7c61f55065d99586dca49093fede85e9489b7906093d957bccd4995baa0ef69d4abd08a4b35821f1821e8ff8fdfa669ecdf374e93cbbac3b3e585ae9dd3c1fa2f5a33662e91786b77b8e39a1d9305ec995dd0e90e95ec1b47c86ecb +out +170303011086a33a551333597509bb32d152f75bb5f31bda9c1c79230bc93addd1d6bcaa187d3c5dabafa6918e66a6e0d5b6de97f32dcc0dcb88ba217e592e305917d2c4a6783f5f197c4f545fb426313480835e02f9d6d0a44360fcee7751360dc29daf32e5fc3d90ee41ddde909e75fcd5e6ea01466716cef065e3a0e29c1265148b020f06c3b1f520b3651816d7dd19755120a86240bae191e068011d294487abe78b6fea1e1e25eef239dd816b7844d9756858c9867358910afe9e67444cdca14391f15bbcf989038907d1bdf5a94b7bb061e90873ecc7693ff6888fa7670af9874a891d8150f178c68ca19383cee710ea4dcff9542880585c163e5cfebeb0bc2fc8092d533a60a1c01d2be0a18bc19d521f26 +in +170303023016d02d90cddf15fcde62eea22c52b0a3a4d505c53fb5a56c376f5891dcedd3e93e48ce691f54a5210cd0c87ac21d8207d7a1fd2401613d3d29c0b8ab54c754898d2dd7159ee015955a8881aea9de7ce2aff422d5c4b924ea308d26b64b9bc23a30f42a37329b686730c64b28b08ea37af3f6f0b5385ec600c6a5b16facf7e34fa19fb4c477c53b911203e4cb42eafb5036ce7c3589c77d9219802c0fb50814c28d3b090d9e22285de41030cde8c6eda96b451d65843827df75aac7f3cde6489fb354dada7086b0b70da0d235109f6cb9a6f5cc6690b6693bb216b9b9ec392a930a43e9639021edd3e5f36bb8043ba249bd0e3c8169a9cfb0563ed4ee04638e3e3c7d8db2540b99abb7f50ae459d62a4b4efa5adf79d89757cb1e2a58728055e49d287a16550a4ed1ab419b274982661a300fff8fe399f13f46611d8fd3a4a45068dac73132747662e25304e6c8228c292137e330c884e3e0464423105d8ed587bdf4b46d5d633d05930a6e07e8ab83e91dcbe3538ad1fe599e99a26bf249bfd8ad6677450ddb753363f20263caf08a8373fb61396d04bd7e24a5c3d1a1c926386d54f80aececc0e19d9e3bd704966220956c125f4d7571109c24e9b5943da5339d584ac5990639aa16d2f67f24e52a74447ee4bf83bc6eb6b35abd69aeb4f904efd597e26dd11d80c631a686e3ab7632b0ee074fce11a524328397c72505a2a7862a68a1e291f2c14cd9d0a4fca26e30264f1b9b0193871fe7207674291506de78a86b0d9bcbfa9f0a8315f82782aeba +out +17030300e094fdf76bfcb2d9e642deb82c58903c878c132b9cc47f03ab4337b3df3cce619bb4bb6b9d8c3a8e205cc0cb97c55b220289ecd833a3401523744beb27f077b799f044422bd84bb22ee85a76c7e45951ddef1c6b9f19d233bbd4136eca5838b9e07682bd19e90e71bd35c24c5f717af9f80c4e55d9f2db50931efaf12743a9e8414b20e6bd7978661429df5f80b019e08fff324cfcfaca92c85d828d8f981d8687ad391aed95b189ee933f6f005a09c1cb5999e43bf8e34b258a30bafda77c6692563b22475fe99a814c2701ba79d3779c1812e473f15ad20cb414657dd0fd5c3b \ No newline at end of file