36 Commits

Author SHA1 Message Date
Sergey Shkurov
cc66f47d0d Update README.md 2023-08-05 02:01:25 +04:00
Sergey Shkurov
d085e04168 Remove RsaKeysHolder 2023-08-05 02:00:39 +04:00
Sergey Shkurov
65c6de9a06 Update frontend 2023-08-03 03:22:55 +04:00
Sergey Shkurov
b7f61fc435 Remove more test files 2023-08-03 02:56:43 +04:00
Sergey Shkurov
b02185794d Remove test 2023-08-03 02:56:06 +04:00
Sergey Shkurov
5ee345735d Remove dto fields 2023-08-03 02:56:00 +04:00
Sergey Shkurov
88e76c096d Remove TLS support 2023-08-03 02:46:30 +04:00
Sergey
938031f1de Use RawHTTP library to process HTTP streams (packmate/Packmate!23) 2023-07-31 15:42:17 +00:00
Sergey
7986658bd1 Update configuration 2023-07-26 18:21:49 +00:00
Sergey
4fed53244d Merge branch 'update-frontend' into 'master'
Update frontend to show packet offsets

See merge request packmate/Packmate!21
2023-07-24 22:30:47 +00:00
Sergey Shkurov
37fd548364 Update frontend to show packet offsets 2023-07-25 02:28:56 +04:00
Sergey Shkurov
fcd7918125 Update frontend to use dark theme 2023-05-01 23:23:11 +02:00
Sergey Shkurov
c88ca8abbd Update frontend 2023-05-01 21:18:26 +02:00
Sergey
15206188a2 Merge branch 'display-stream-size' into 'master'
Display stream size

See merge request packmate/Packmate!20
2023-04-30 22:22:01 +00:00
Sergey
4346445af9 Display stream size 2023-04-30 22:22:01 +00:00
Sergey
f1d67f696d Merge branch 'pattern-updates' into 'master'
Pattern updates

Closes #32

See merge request packmate/Packmate!19
2023-04-30 00:08:15 +00:00
Sergey Shkurov
4b45f7dee7 Update frontend 2023-04-30 01:50:05 +02:00
Sergey Shkurov
a8ee7363d4 Revert adding field 2023-04-29 04:51:57 +02:00
Sergey Shkurov
25d0921aed Update frontend 2023-04-29 04:40:46 +02:00
Sergey Shkurov
73fa5b1373 Add support for pattern updating 2023-04-28 04:08:16 +02:00
Sergey Shkurov
40136ad9d9 Update ServiceController endpoints 2023-04-28 03:59:01 +02:00
Sergey Shkurov
0b50f202fc Move dto transformation into services 2023-04-28 03:27:28 +02:00
Sergey Shkurov
288d24fffc Send pattern ids instead of patterns in streams 2023-04-28 02:02:28 +02:00
Sergey
40b42934b6 Merge branch 'pattern-removal' into 'master'
Implement pattern removal

Closes #29

See merge request packmate/Packmate!18
2023-04-27 23:19:16 +00:00
Sergey
4cd5e72fee Implement pattern removal 2023-04-27 23:19:16 +00:00
Sergey
145f3e63c8 Merge branch 'update-versions' into 'master'
Update versions

See merge request packmate/Packmate!17
2023-04-27 21:22:40 +00:00
Sergey Shkurov
6ea53719fd Remove DISTINCT 2023-04-27 23:19:19 +02:00
Sergey Shkurov
8bbd135e96 Refactor code 2023-04-27 22:35:03 +02:00
Sergey Shkurov
79315c3c18 Update jna dependency for MacOS 2023-04-27 22:35:02 +02:00
Sergey Shkurov
67c5462018 Fix a possible bug 2023-04-27 22:35:02 +02:00
Sergey Shkurov
4e2473a3cc Update libraries 2023-04-27 22:35:02 +02:00
Sergey Shkurov
ea45f1b9e5 Use gradle.kts 2023-04-27 22:35:02 +02:00
Sergey Shkurov
93ec39b561 Prepare to move to gradle.kts 2023-04-27 22:35:02 +02:00
Sergey Shkurov
7878ecebfc Fix hashtag symbols becoming links 2023-04-27 22:35:02 +02:00
Sergey Shkurov
7afb9dc5fb Update Spring Boot 2 2023-04-27 22:35:02 +02:00
Sergey Shkurov
8d33c6a6e1 Update gradle version 2023-04-27 22:35:02 +02:00
98 changed files with 667 additions and 3765 deletions

View File

@@ -22,7 +22,6 @@
* Автоматически проводит urldecode * Автоматически проводит urldecode
* Разархивирует GZIP в HTTP на лету * Разархивирует GZIP в HTTP на лету
* Разархивирует сжатые WebSockets * Разархивирует сжатые WebSockets
* Расшифровывает TLS на RSA при наличии приватного ключа
![Скриншот главного окна](screenshots/Screenshot.png) ![Скриншот главного окна](screenshots/Screenshot.png)

View File

@@ -22,7 +22,6 @@ Advanced network traffic flow analyzer for A/D CTFs.
* Can urldecode text automatically * Can urldecode text automatically
* Can automatically decompress GZIPed HTTP * Can automatically decompress GZIPed HTTP
* Can automatically deflate WebSockets with permessages-deflate extension * Can automatically deflate WebSockets with permessages-deflate extension
* Can automatically decrypt TLS with RSA using given private key (like Wireshark)
![Main window](screenshots/Screenshot.png) ![Main window](screenshots/Screenshot.png)

View File

@@ -1,50 +0,0 @@
plugins {
id 'org.springframework.boot' version '2.6.3'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'ru.serega6531'
version = '1.0-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation "org.springframework.boot:spring-boot-starter-security"
implementation "org.springframework.boot:spring-boot-starter-websocket"
implementation 'org.springframework.session:spring-session-core'
implementation 'com.github.jmnarloch:modelmapper-spring-boot-starter:1.1.0'
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
implementation group: 'commons-io', name: 'commons-io', version: '2.11.0'
implementation 'org.pcap4j:pcap4j-core:1.8.2'
implementation 'org.pcap4j:pcap4j-packetfactory-static:1.8.2'
implementation group: 'com.google.guava', name: 'guava', version: '31.0.1-jre'
implementation group: 'org.java-websocket', name: 'Java-WebSocket', version: '1.5.1'
implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.69'
implementation group: 'org.bouncycastle', name: 'bctls-jdk15on', version: '1.70'
implementation group: 'org.modelmapper', name: 'modelmapper', version: '2.4.5'
compileOnly 'org.jetbrains:annotations:22.0.0'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
}
test {
useJUnitPlatform()
}

61
build.gradle.kts Normal file
View File

@@ -0,0 +1,61 @@
plugins {
id("org.springframework.boot") version "3.0.6"
id("java")
id("io.spring.dependency-management") version "1.1.0"
}
group = "ru.serega6531"
version = "1.0-SNAPSHOT"
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
configurations {
get("compileOnly").apply {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-websocket")
implementation("org.springframework.session:spring-session-core")
implementation(group = "org.apache.commons", name = "commons-lang3", version = "3.12.0")
implementation(group = "commons-io", name = "commons-io", version = "2.11.0")
implementation("org.pcap4j:pcap4j-core:1.8.2")
implementation("org.pcap4j:pcap4j-packetfactory-static:1.8.2")
constraints {
implementation("net.java.dev.jna:jna:5.13.0") {
because("upgraded version required to run on MacOS")
// https://stackoverflow.com/questions/70368863/unsatisfiedlinkerror-for-m1-macs-while-running-play-server-locally
}
}
implementation(group = "com.google.guava", name = "guava", version = "31.1-jre")
implementation(group = "org.java-websocket", name = "Java-WebSocket", version = "1.5.3")
implementation(group = "org.bouncycastle", name = "bcprov-jdk15on", version = "1.70")
implementation(group = "org.bouncycastle", name = "bctls-jdk15on", version = "1.70")
implementation(group = "org.modelmapper", name = "modelmapper", version = "3.1.1")
implementation("com.athaydes.rawhttp:rawhttp-core:2.5.2")
compileOnly("org.jetbrains:annotations:24.0.1")
compileOnly("org.projectlombok:lombok")
runtimeOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("org.postgresql:postgresql")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
}
tasks.getByName<Test>("test") {
useJUnitPlatform()
}

View File

@@ -21,7 +21,6 @@ services:
image: registry.gitlab.com/packmate/packmate:${BUILD_TAG:-latest} image: registry.gitlab.com/packmate/packmate:${BUILD_TAG:-latest}
volumes: volumes:
- "./pcaps/:/app/pcaps/:ro" - "./pcaps/:/app/pcaps/:ro"
- "./rsa_keys/:/app/rsa_keys/:ro"
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy

View File

@@ -17,11 +17,13 @@ COPY --from=1 /tmp/compile/build/libs/packmate-*-SNAPSHOT.jar app.jar
CMD [ "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.preferIPv4Addresses=true", \ CMD [ "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.preferIPv4Addresses=true", \
"-jar", "/app/app.jar", "--spring.datasource.url=jdbc:postgresql://127.0.0.1:65001/packmate", \ "-jar", "/app/app.jar", "--spring.datasource.url=jdbc:postgresql://127.0.0.1:65001/packmate", \
"--spring.datasource.password=${DB_PASSWORD}", \ "--spring.datasource.password=${DB_PASSWORD}", \
"--capture-mode=${MODE}", "--pcap-file=${PCAP_FILE}", \ "--packmate.capture-mode=${MODE}", "--packmate.pcap-file=${PCAP_FILE}", \
"--interface-name=${INTERFACE}", "--local-ip=${LOCAL_IP}", "--account-login=${WEB_LOGIN}", \ "--packmate.interface-name=${INTERFACE}", "--packmate.local-ip=${LOCAL_IP}", \
"--old-streams-cleanup-enabled=${OLD_STREAMS_CLEANUP_ENABLED}", "--cleanup-interval=${OLD_STREAMS_CLEANUP_INTERVAL}", \ "--packmate.web.account-login=${WEB_LOGIN}", "--packmate.web.account-password=${WEB_PASSWORD}", \
"--old-streams-threshold=${OLD_STREAMS_CLEANUP_THRESHOLD}", \ "--packmate.cleanup.enabled=${OLD_STREAMS_CLEANUP_ENABLED}", \
"--account-password=${WEB_PASSWORD}", "--server.port=65000", "--server.address=0.0.0.0" \ "--packmate.cleanup.interval=${OLD_STREAMS_CLEANUP_INTERVAL}", \
"--packmate.cleanup.threshold=${OLD_STREAMS_CLEANUP_THRESHOLD}", \
"--server.port=65000", "--server.address=0.0.0.0" \
] ]
EXPOSE 65000 EXPOSE 65000

View File

@@ -75,9 +75,9 @@
Совет: иногда на CTF забывают перезаписать TTL пакетов внутри сети. В таком случае по TTL можно отличить запросы от чекеров и от других команд. Совет: иногда на CTF забывают перезаписать TTL пакетов внутри сети. В таком случае по TTL можно отличить запросы от чекеров и от других команд.
Совет #2: по User-Agent можно отличать запросы из разных источников. К примеру, можно предположить, что на скриншоте выше запросы 4 и 5 пришли из разных источников. Совет #&#8203;2: по User-Agent можно отличать запросы из разных источников. К примеру, можно предположить, что на скриншоте выше запросы 4 и 5 пришли из разных источников.
Совет #3: нажимайте на звездочку, чтобы добавить интересный стрим в избранное. Этот стрим будет выделен в списке, и появится в списке избранных стримов. Совет #&#8203;3: нажимайте на звездочку, чтобы добавить интересный стрим в избранное. Этот стрим будет выделен в списке, и появится в списке избранных стримов.
#### Управление просмотром #### Управление просмотром
@@ -101,7 +101,7 @@
Совет: создавайте отдельные паттерны для входящих и исходящих флагов. Так легче отличать чекер, кладущий флаги, от эксплоитов. Совет: создавайте отдельные паттерны для входящих и исходящих флагов. Так легче отличать чекер, кладущий флаги, от эксплоитов.
Совет #2: используйте Lookback для исследования найденных эксплоитов. Совет #&#8203;2: используйте Lookback для исследования найденных эксплоитов.
Пример: вы обнаружили, что сервис только что отдал флаг пользователю `abc123` без видимых причин. Пример: вы обнаружили, что сервис только что отдал флаг пользователю `abc123` без видимых причин.
Можно предположить, что атакующая команда создала этого пользователя и подготовила эксплоит в другом стриме. Можно предположить, что атакующая команда создала этого пользователя и подготовила эксплоит в другом стриме.

View File

@@ -68,9 +68,9 @@ you can switch between binary and text representation using the button in the si
Tip: Sometimes during CTFs, admins forget to overwrite the TTL of packets inside the network. In such cases, you can differentiate requests from checkers and other teams based on TTL. Tip: Sometimes during CTFs, admins forget to overwrite the TTL of packets inside the network. In such cases, you can differentiate requests from checkers and other teams based on TTL.
Tip #2: User-Agent can be used to differentiate requests from different sources. For example, in the screenshot above, requests 4 and 5 may have come from different sources. Tip #&#8203;2: User-Agent can be used to differentiate requests from different sources. For example, in the screenshot above, requests 4 and 5 may have come from different sources.
Tip #3: Click on the star icon to add an interesting stream to your favorites. This stream will be highlighted in the list and will appear in the list of favorite streams. Tip #&#8203;3: Click on the star icon to add an interesting stream to your favorites. This stream will be highlighted in the list and will appear in the list of favorite streams.
#### Control Panel #### Control Panel
@@ -94,7 +94,7 @@ Tip #3: Click on the star icon to add an interesting stream to your favorites. T
Tip: Create separate patterns for incoming and outgoing flags to easily distinguish between flag checkers and exploits. Tip: Create separate patterns for incoming and outgoing flags to easily distinguish between flag checkers and exploits.
Tip #2: Use Lookback to investigate discovered exploits. Tip #&#8203;2: Use Lookback to investigate discovered exploits.
Example: You found that the service just handed out a flag to user `abc123` without an apparent reason. Example: You found that the service just handed out a flag to user `abc123` without an apparent reason.
You can assume that the attacking team created this user and prepared an exploit in another stream. You can assume that the attacking team created this user and prepared an exploit in another stream.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -1,28 +0,0 @@
-----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-----

View File

@@ -3,4 +3,4 @@ pluginManagement {
gradlePluginPortal() gradlePluginPortal()
} }
} }
rootProject.name = 'packmate' rootProject.name = "packmate"

View File

@@ -1,28 +1,35 @@
package ru.serega6531.packmate.configuration; package ru.serega6531.packmate.configuration;
import org.modelmapper.Converter;
import org.modelmapper.ModelMapper;
import org.modelmapper.TypeMap;
import org.pcap4j.core.PcapNativeException; import org.pcap4j.core.PcapNativeException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import ru.serega6531.packmate.model.Pattern;
import org.springframework.security.crypto.password.PasswordEncoder; import ru.serega6531.packmate.model.Stream;
import ru.serega6531.packmate.model.enums.CaptureMode; import ru.serega6531.packmate.model.pojo.StreamDto;
import ru.serega6531.packmate.pcap.FilePcapWorker; import ru.serega6531.packmate.pcap.FilePcapWorker;
import ru.serega6531.packmate.pcap.LivePcapWorker; import ru.serega6531.packmate.pcap.LivePcapWorker;
import ru.serega6531.packmate.pcap.NoOpPcapWorker; import ru.serega6531.packmate.pcap.NoOpPcapWorker;
import ru.serega6531.packmate.pcap.PcapWorker; import ru.serega6531.packmate.pcap.PcapWorker;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.service.ServicesService; import ru.serega6531.packmate.service.ServicesService;
import ru.serega6531.packmate.service.StreamService; import ru.serega6531.packmate.service.StreamService;
import ru.serega6531.packmate.service.SubscriptionService; import ru.serega6531.packmate.service.SubscriptionService;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Set;
import java.util.stream.Collectors;
@Configuration @Configuration
@EnableScheduling @EnableScheduling
@EnableAsync @EnableAsync
@ConfigurationPropertiesScan("ru.serega6531.packmate.properties")
public class ApplicationConfiguration { public class ApplicationConfiguration {
@Bean(destroyMethod = "stop") @Bean(destroyMethod = "stop")
@@ -30,20 +37,37 @@ public class ApplicationConfiguration {
public PcapWorker pcapWorker(ServicesService servicesService, public PcapWorker pcapWorker(ServicesService servicesService,
StreamService streamService, StreamService streamService,
SubscriptionService subscriptionService, SubscriptionService subscriptionService,
@Value("${local-ip}") String localIpString, PackmateProperties properties
@Value("${interface-name}") String interfaceName, ) throws PcapNativeException, UnknownHostException {
@Value("${pcap-file}") String filename, return switch (properties.captureMode()) {
@Value("${capture-mode}") CaptureMode captureMode) throws PcapNativeException, UnknownHostException { case LIVE -> new LivePcapWorker(servicesService, streamService, properties.localIp(), properties.interfaceName());
return switch (captureMode) { case FILE ->
case LIVE -> new LivePcapWorker(servicesService, streamService, localIpString, interfaceName); new FilePcapWorker(servicesService, streamService, subscriptionService, properties.localIp(), properties.pcapFile());
case FILE -> new FilePcapWorker(servicesService, streamService, subscriptionService, localIpString, filename);
case VIEW -> new NoOpPcapWorker(); case VIEW -> new NoOpPcapWorker();
}; };
} }
@Bean @Bean
public PasswordEncoder passwordEncoder() { public ModelMapper modelMapper() {
return new BCryptPasswordEncoder(); ModelMapper modelMapper = new ModelMapper();
addStreamMapper(modelMapper);
return modelMapper;
}
private void addStreamMapper(ModelMapper modelMapper) {
TypeMap<Stream, StreamDto> streamMapper = modelMapper.createTypeMap(Stream.class, StreamDto.class);
Converter<Set<Pattern>, Set<Integer>> patternSetToIdSet = ctx -> ctx.getSource()
.stream()
.map(Pattern::getId)
.collect(Collectors.toSet());
streamMapper.addMappings(mapping ->
mapping.using(patternSetToIdSet)
.map(Stream::getFoundPatterns, StreamDto::setFoundPatternsIds)
);
} }
} }

View File

@@ -1,57 +1,58 @@
package ru.serega6531.packmate.configuration; package ru.serega6531.packmate.configuration;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent; import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import ru.serega6531.packmate.properties.PackmateProperties;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@Slf4j @Slf4j
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { public class SecurityConfiguration {
@Value("${account-login}") @Bean
private String login; public InMemoryUserDetailsManager userDetailsService(PackmateProperties properties, PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username(properties.web().accountLogin())
.password(passwordEncoder.encode(properties.web().accountPassword()))
.roles("USER")
.build();
@Value("${account-password}") return new InMemoryUserDetailsManager(user);
private String password;
private final PasswordEncoder passwordEncoder;
@Autowired
public SecurityConfiguration(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
} }
@Autowired @Bean
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
auth.inMemoryAuthentication() return http.csrf()
.withUser(login)
.password(passwordEncoder.encode(password))
.authorities("ROLE_USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable() .disable()
.authorizeRequests() .authorizeHttpRequests((auth) ->
.antMatchers("/site.webmanifest") auth.requestMatchers("/site.webmanifest")
.permitAll() .permitAll()
.anyRequest().authenticated() .anyRequest()
.and() .authenticated()
)
.httpBasic() .httpBasic()
.and() .and()
.headers() .headers()
.frameOptions() .frameOptions()
.sameOrigin(); .sameOrigin()
.and()
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
} }
@EventListener @EventListener

View File

@@ -1,14 +1,16 @@
package ru.serega6531.packmate.controller; package ru.serega6531.packmate.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.PathVariable;
import ru.serega6531.packmate.model.Packet; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ru.serega6531.packmate.model.pojo.PacketDto; import ru.serega6531.packmate.model.pojo.PacketDto;
import ru.serega6531.packmate.model.pojo.PacketPagination; import ru.serega6531.packmate.model.pojo.PacketPagination;
import ru.serega6531.packmate.service.StreamService; import ru.serega6531.packmate.service.StreamService;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping("/api/packet/") @RequestMapping("/api/packet/")
@@ -23,10 +25,7 @@ public class PacketController {
@PostMapping("/{streamId}") @PostMapping("/{streamId}")
public List<PacketDto> getPacketsForStream(@PathVariable long streamId, @RequestBody PacketPagination pagination) { public List<PacketDto> getPacketsForStream(@PathVariable long streamId, @RequestBody PacketPagination pagination) {
List<Packet> packets = streamService.getPackets(streamId, pagination.getStartingFrom(), pagination.getPageSize()); return streamService.getPackets(streamId, pagination.getStartingFrom(), pagination.getPageSize());
return packets.stream()
.map(streamService::packetToDto)
.collect(Collectors.toList());
} }
} }

View File

@@ -1,13 +1,20 @@
package ru.serega6531.packmate.controller; package ru.serega6531.packmate.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.DeleteMapping;
import ru.serega6531.packmate.model.Pattern; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ru.serega6531.packmate.model.pojo.PatternCreateDto;
import ru.serega6531.packmate.model.pojo.PatternDto; import ru.serega6531.packmate.model.pojo.PatternDto;
import ru.serega6531.packmate.model.pojo.PatternUpdateDto;
import ru.serega6531.packmate.service.PatternService; import ru.serega6531.packmate.service.PatternService;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping("/api/pattern/") @RequestMapping("/api/pattern/")
@@ -24,14 +31,19 @@ public class PatternController {
public List<PatternDto> getPatterns() { public List<PatternDto> getPatterns() {
return service.findAll() return service.findAll()
.stream().map(service::toDto) .stream().map(service::toDto)
.collect(Collectors.toList()); .toList();
} }
@PostMapping("/{id}") @PostMapping("/{id}/enable")
public void enable(@PathVariable int id, @RequestParam boolean enabled) { public void enable(@PathVariable int id, @RequestParam boolean enabled) {
service.enable(id, enabled); service.enable(id, enabled);
} }
@DeleteMapping("/{id}")
public void delete(@PathVariable int id) {
service.delete(id);
}
@PostMapping("/{id}/lookback") @PostMapping("/{id}/lookback")
public void lookBack(@PathVariable int id, @RequestBody int minutes) { public void lookBack(@PathVariable int id, @RequestBody int minutes) {
if (minutes < 1) { if (minutes < 1) {
@@ -42,11 +54,13 @@ public class PatternController {
} }
@PostMapping @PostMapping
public PatternDto addPattern(@RequestBody PatternDto dto) { public PatternDto addPattern(@RequestBody PatternCreateDto dto) {
dto.setEnabled(true); return service.create(dto);
Pattern pattern = service.fromDto(dto); }
Pattern saved = service.save(pattern);
return service.toDto(saved); @PostMapping("/{id}")
public PatternDto updatePattern(@PathVariable int id, @RequestBody PatternUpdateDto dto) {
return service.update(id, dto);
} }
} }

View File

@@ -1,13 +1,19 @@
package ru.serega6531.packmate.controller; package ru.serega6531.packmate.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.DeleteMapping;
import ru.serega6531.packmate.model.CtfService; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ru.serega6531.packmate.model.pojo.ServiceCreateDto;
import ru.serega6531.packmate.model.pojo.ServiceDto; import ru.serega6531.packmate.model.pojo.ServiceDto;
import ru.serega6531.packmate.model.pojo.ServiceUpdateDto;
import ru.serega6531.packmate.service.ServicesService; import ru.serega6531.packmate.service.ServicesService;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping("/api/service/") @RequestMapping("/api/service/")
@@ -22,9 +28,7 @@ public class ServiceController {
@GetMapping @GetMapping
public List<ServiceDto> getServices() { public List<ServiceDto> getServices() {
return service.findAll().stream() return service.findAll();
.map(service::toDto)
.collect(Collectors.toList());
} }
@DeleteMapping("/{port}") @DeleteMapping("/{port}")
@@ -33,9 +37,13 @@ public class ServiceController {
} }
@PostMapping @PostMapping
public CtfService addService(@RequestBody ServiceDto dto) { public ServiceDto addService(@RequestBody ServiceCreateDto dto) {
CtfService newService = this.service.fromDto(dto); return this.service.create(dto);
return this.service.save(newService); }
@PostMapping("/{port}")
public ServiceDto updateService(@PathVariable int port, @RequestBody ServiceUpdateDto dto) {
return this.service.update(port, dto);
} }
} }

View File

@@ -1,14 +1,17 @@
package ru.serega6531.packmate.controller; package ru.serega6531.packmate.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.PathVariable;
import ru.serega6531.packmate.model.pojo.StreamPagination; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ru.serega6531.packmate.model.pojo.StreamDto; import ru.serega6531.packmate.model.pojo.StreamDto;
import ru.serega6531.packmate.model.pojo.StreamPagination;
import ru.serega6531.packmate.service.StreamService; import ru.serega6531.packmate.service.StreamService;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping("/api/stream/") @RequestMapping("/api/stream/")
@@ -23,16 +26,12 @@ public class StreamController {
@PostMapping("/all") @PostMapping("/all")
public List<StreamDto> getStreams(@RequestBody StreamPagination pagination) { public List<StreamDto> getStreams(@RequestBody StreamPagination pagination) {
return service.findAll(pagination, Optional.empty(), pagination.isFavorites()).stream() return service.findAll(pagination, Optional.empty(), pagination.isFavorites());
.map(service::streamToDto)
.collect(Collectors.toList());
} }
@PostMapping("/{port}") @PostMapping("/{port}")
public List<StreamDto> getStreams(@PathVariable int port, @RequestBody StreamPagination pagination) { public List<StreamDto> getStreams(@PathVariable int port, @RequestBody StreamPagination pagination) {
return service.findAll(pagination, Optional.of(port), pagination.isFavorites()).stream() return service.findAll(pagination, Optional.of(port), pagination.isFavorites());
.map(service::streamToDto)
.collect(Collectors.toList());
} }
@PostMapping("/{id}/favorite") @PostMapping("/{id}/favorite")

View File

@@ -3,10 +3,10 @@ package ru.serega6531.packmate.model;
import lombok.*; import lombok.*;
import org.hibernate.Hibernate; import org.hibernate.Hibernate;
import javax.persistence.Column; import jakarta.persistence.Column;
import javax.persistence.Entity; import jakarta.persistence.Entity;
import javax.persistence.Id; import jakarta.persistence.Id;
import javax.persistence.Table; import jakarta.persistence.Table;
import java.util.Objects; import java.util.Objects;
@Getter @Getter
@@ -23,11 +23,7 @@ public class CtfService {
@Column(nullable = false) @Column(nullable = false)
private String name; private String name;
private boolean decryptTls; private boolean http;
private boolean processChunkedEncoding;
private boolean ungzipHttp;
private boolean urldecodeHttpRequests; private boolean urldecodeHttpRequests;

View File

@@ -5,7 +5,7 @@ import org.hibernate.Hibernate;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter; import org.hibernate.annotations.Parameter;
import javax.persistence.*; import jakarta.persistence.*;
import java.util.Objects; import java.util.Objects;
@Entity @Entity

View File

@@ -5,7 +5,7 @@ import org.hibernate.Hibernate;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter; import org.hibernate.annotations.Parameter;
import javax.persistence.*; import jakarta.persistence.*;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@@ -24,7 +24,7 @@ import java.util.Set;
} }
) )
@AllArgsConstructor @AllArgsConstructor
@Builder @Builder(toBuilder = true)
@Table(indexes = { @Index(name = "stream_id_index", columnList = "stream_id") }) @Table(indexes = { @Index(name = "stream_id_index", columnList = "stream_id") })
public class Packet { public class Packet {
@@ -49,11 +49,11 @@ public class Packet {
private boolean incoming; // true если от клиента к серверу, иначе false private boolean incoming; // true если от клиента к серверу, иначе false
private boolean ungzipped; private boolean httpProcessed = false;
private boolean webSocketParsed; private boolean webSocketParsed = false;
private boolean tlsDecrypted; private boolean hasHttpBody = false;
@Column(nullable = false) @Column(nullable = false)
private byte[] content; private byte[] content;

View File

@@ -1,5 +1,10 @@
package ru.serega6531.packmate.model; package ru.serega6531.packmate.model;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
@@ -11,14 +16,13 @@ import ru.serega6531.packmate.model.enums.PatternActionType;
import ru.serega6531.packmate.model.enums.PatternDirectionType; import ru.serega6531.packmate.model.enums.PatternDirectionType;
import ru.serega6531.packmate.model.enums.PatternSearchType; import ru.serega6531.packmate.model.enums.PatternSearchType;
import javax.persistence.*;
import java.util.Objects; import java.util.Objects;
@Getter @Getter
@Setter @Setter
@RequiredArgsConstructor @RequiredArgsConstructor
@ToString @ToString
@Entity @Entity(name = "pattern")
@GenericGenerator( @GenericGenerator(
name = "pattern_generator", name = "pattern_generator",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
@@ -34,8 +38,12 @@ public class Pattern {
@GeneratedValue(generator = "pattern_generator") @GeneratedValue(generator = "pattern_generator")
private Integer id; private Integer id;
@Column(nullable = false)
private boolean enabled; private boolean enabled;
@Column(nullable = false)
private boolean deleted = false;
@Column(nullable = false) @Column(nullable = false)
private String name; private String name;

View File

@@ -9,7 +9,7 @@ import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter; import org.hibernate.annotations.Parameter;
import ru.serega6531.packmate.model.enums.Protocol; import ru.serega6531.packmate.model.enums.Protocol;
import javax.persistence.*; import jakarta.persistence.*;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -53,7 +53,7 @@ public class Stream {
private long endTimestamp; private long endTimestamp;
@ManyToMany(fetch = FetchType.EAGER) @ManyToMany
@JoinTable( @JoinTable(
name = "stream_found_patterns", name = "stream_found_patterns",
joinColumns = @JoinColumn(name = "stream_id"), joinColumns = @JoinColumn(name = "stream_id"),
@@ -70,6 +70,12 @@ public class Stream {
@Column(columnDefinition = "char(3)") @Column(columnDefinition = "char(3)")
private String userAgentHash; private String userAgentHash;
@Column(name = "size_bytes", nullable = false)
private Integer sizeBytes;
@Column(name = "packets_count", nullable = false)
private Integer packetsCount;
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;

View File

@@ -2,7 +2,7 @@ package ru.serega6531.packmate.model.enums;
public enum SubscriptionMessageType { public enum SubscriptionMessageType {
SAVE_SERVICE, SAVE_PATTERN, SAVE_SERVICE, SAVE_PATTERN,
DELETE_SERVICE, DELETE_PATTERN, DELETE_SERVICE,
NEW_STREAM, NEW_STREAM,
FINISH_LOOKBACK, FINISH_LOOKBACK,
COUNTERS_UPDATE, COUNTERS_UPDATE,

View File

@@ -1,23 +1,8 @@
package ru.serega6531.packmate.model.pojo; package ru.serega6531.packmate.model.pojo;
import lombok.Getter;
import java.util.Map; import java.util.Map;
@Getter public record CountersHolder(Map<Integer, Integer> servicesPackets, Map<Integer, Integer> servicesStreams,
public class CountersHolder {
private final Map<Integer, Integer> servicesPackets;
private final Map<Integer, Integer> servicesStreams;
private final int totalPackets;
private final int totalStreams;
public CountersHolder(Map<Integer, Integer> servicesPackets, Map<Integer, Integer> servicesStreams,
int totalPackets, int totalStreams) { int totalPackets, int totalStreams) {
this.servicesPackets = servicesPackets;
this.servicesStreams = servicesStreams;
this.totalPackets = totalPackets;
this.totalStreams = totalStreams;
}
} }

View File

@@ -13,7 +13,7 @@ public class PacketDto {
private boolean incoming; private boolean incoming;
private boolean ungzipped; private boolean ungzipped;
private boolean webSocketParsed; private boolean webSocketParsed;
private boolean tlsDecrypted; private boolean hasHttpBody;
private byte[] content; private byte[] content;
} }

View File

@@ -0,0 +1,19 @@
package ru.serega6531.packmate.model.pojo;
import lombok.Data;
import ru.serega6531.packmate.model.enums.PatternActionType;
import ru.serega6531.packmate.model.enums.PatternDirectionType;
import ru.serega6531.packmate.model.enums.PatternSearchType;
@Data
public class PatternCreateDto {
private String name;
private String value;
private String color;
private PatternSearchType searchType;
private PatternDirectionType directionType;
private PatternActionType actionType;
private Integer serviceId;
}

View File

@@ -10,6 +10,7 @@ public class PatternDto {
private int id; private int id;
private boolean enabled; private boolean enabled;
private boolean deleted;
private String name; private String name;
private String value; private String value;
private String color; private String color;

View File

@@ -0,0 +1,11 @@
package ru.serega6531.packmate.model.pojo;
import lombok.Data;
@Data
public class PatternUpdateDto {
private String name;
private String color;
}

View File

@@ -0,0 +1,15 @@
package ru.serega6531.packmate.model.pojo;
import lombok.Data;
@Data
public class ServiceCreateDto {
private int port;
private String name;
private boolean http;
private boolean urldecodeHttpRequests;
private boolean mergeAdjacentPackets;
private boolean parseWebSockets;
}

View File

@@ -7,9 +7,7 @@ public class ServiceDto {
private int port; private int port;
private String name; private String name;
private boolean decryptTls; private boolean http;
private boolean processChunkedEncoding;
private boolean ungzipHttp;
private boolean urldecodeHttpRequests; private boolean urldecodeHttpRequests;
private boolean mergeAdjacentPackets; private boolean mergeAdjacentPackets;
private boolean parseWebSockets; private boolean parseWebSockets;

View File

@@ -0,0 +1,15 @@
package ru.serega6531.packmate.model.pojo;
import lombok.Data;
@Data
public class ServiceUpdateDto {
private int port;
private String name;
private boolean http;
private boolean urldecodeHttpRequests;
private boolean mergeAdjacentPackets;
private boolean parseWebSockets;
}

View File

@@ -13,9 +13,11 @@ public class StreamDto {
private Protocol protocol; private Protocol protocol;
private long startTimestamp; private long startTimestamp;
private long endTimestamp; private long endTimestamp;
private Set<PatternDto> foundPatterns; private Set<Integer> foundPatternsIds;
private boolean favorite; private boolean favorite;
private int ttl; private int ttl;
private String userAgentHash; private String userAgentHash;
private int sizeBytes;
private int packetsCount;
} }

View File

@@ -1,29 +1,18 @@
package ru.serega6531.packmate.model.pojo; package ru.serega6531.packmate.model.pojo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import ru.serega6531.packmate.model.enums.Protocol; import ru.serega6531.packmate.model.enums.Protocol;
import java.net.InetAddress; import java.net.InetAddress;
@AllArgsConstructor public record UnfinishedStream(InetAddress firstIp, InetAddress secondIp, int firstPort, int secondPort,
@Getter Protocol protocol) {
public class UnfinishedStream {
private final InetAddress firstIp;
private final InetAddress secondIp;
private final int firstPort;
private final int secondPort;
private final Protocol protocol;
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (!(obj instanceof UnfinishedStream)) { if (!(obj instanceof UnfinishedStream o)) {
return false; return false;
} }
UnfinishedStream o = (UnfinishedStream) obj;
boolean ipEq1 = firstIp.equals(o.firstIp) && secondIp.equals(o.secondIp); boolean ipEq1 = firstIp.equals(o.firstIp) && secondIp.equals(o.secondIp);
boolean ipEq2 = firstIp.equals(o.secondIp) && secondIp.equals(o.firstIp); boolean ipEq2 = firstIp.equals(o.secondIp) && secondIp.equals(o.firstIp);
boolean portEq1 = firstPort == o.firstPort && secondPort == o.secondPort; boolean portEq1 = firstPort == o.firstPort && secondPort == o.secondPort;

View File

@@ -52,11 +52,11 @@ public abstract class AbstractPcapWorker implements PcapWorker, PacketListener {
protected AbstractPcapWorker(ServicesService servicesService, protected AbstractPcapWorker(ServicesService servicesService,
StreamService streamService, StreamService streamService,
String localIpString) throws UnknownHostException { InetAddress localIp) throws UnknownHostException {
this.servicesService = servicesService; this.servicesService = servicesService;
this.streamService = streamService; this.streamService = streamService;
this.localIp = InetAddress.getByName(localIpString); this.localIp = localIp;
BasicThreadFactory factory = new BasicThreadFactory.Builder() BasicThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern("pcap-loop").build(); .namingPattern("pcap-loop").build();

View File

@@ -16,27 +16,27 @@ import ru.serega6531.packmate.service.SubscriptionService;
import java.io.EOFException; import java.io.EOFException;
import java.io.File; import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
@Slf4j @Slf4j
public class FilePcapWorker extends AbstractPcapWorker { public class FilePcapWorker extends AbstractPcapWorker {
private final File directory = new File("pcaps");
private final SubscriptionService subscriptionService; private final SubscriptionService subscriptionService;
private final File file; private final File file;
public FilePcapWorker(ServicesService servicesService, public FilePcapWorker(ServicesService servicesService,
StreamService streamService, StreamService streamService,
SubscriptionService subscriptionService, SubscriptionService subscriptionService,
String localIpString, InetAddress localIp,
String filename) throws UnknownHostException { String filename) throws UnknownHostException {
super(servicesService, streamService, localIpString); super(servicesService, streamService, localIp);
this.subscriptionService = subscriptionService; this.subscriptionService = subscriptionService;
File directory = new File("pcaps");
file = new File(directory, filename); file = new File(directory, filename);
if (!file.exists()) { validateFileExists();
throw new PcapFileNotFoundException(file, directory);
}
processorExecutorService = new InlineExecutorService(); processorExecutorService = new InlineExecutorService();
} }
@@ -86,4 +86,10 @@ public class FilePcapWorker extends AbstractPcapWorker {
public String getExecutorState() { public String getExecutorState() {
return "inline"; return "inline";
} }
private void validateFileExists() {
if (!file.exists()) {
throw new PcapFileNotFoundException(file, directory);
}
}
} }

View File

@@ -10,6 +10,7 @@ import ru.serega6531.packmate.exception.PcapInterfaceNotFoundException;
import ru.serega6531.packmate.service.ServicesService; import ru.serega6531.packmate.service.ServicesService;
import ru.serega6531.packmate.service.StreamService; import ru.serega6531.packmate.service.StreamService;
import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.List; import java.util.List;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@@ -23,9 +24,9 @@ public class LivePcapWorker extends AbstractPcapWorker {
public LivePcapWorker(ServicesService servicesService, public LivePcapWorker(ServicesService servicesService,
StreamService streamService, StreamService streamService,
String localIpString, InetAddress localIp,
String interfaceName) throws PcapNativeException, UnknownHostException { String interfaceName) throws PcapNativeException, UnknownHostException {
super(servicesService, streamService, localIpString); super(servicesService, streamService, localIp);
device = Pcaps.getDevByName(interfaceName); device = Pcaps.getDevByName(interfaceName);
if (device == null) { if (device == null) {

View File

@@ -1,11 +1,10 @@
package ru.serega6531.packmate.pcap; package ru.serega6531.packmate.pcap;
import org.pcap4j.core.PcapNativeException;
import ru.serega6531.packmate.model.enums.Protocol; import ru.serega6531.packmate.model.enums.Protocol;
public class NoOpPcapWorker implements PcapWorker { public class NoOpPcapWorker implements PcapWorker {
@Override @Override
public void start() throws PcapNativeException { public void start() {
} }
@Override @Override

View File

@@ -0,0 +1,38 @@
package ru.serega6531.packmate.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import ru.serega6531.packmate.model.enums.CaptureMode;
import java.net.InetAddress;
@ConfigurationProperties("packmate")
public record PackmateProperties(
CaptureMode captureMode,
String interfaceName,
String pcapFile,
InetAddress localIp,
WebProperties web,
TimeoutProperties timeout,
CleanupProperties cleanup,
boolean ignoreEmptyPackets
) {
public record WebProperties(
String accountLogin,
String accountPassword
) {}
public record TimeoutProperties(
int udpStreamTimeout,
int tcpStreamTimeout,
int checkInterval
){}
public record CleanupProperties(
boolean enabled,
int threshold,
int interval
){}
}

View File

@@ -1,11 +1,13 @@
package ru.serega6531.packmate.repository; package ru.serega6531.packmate.repository;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.*; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import ru.serega6531.packmate.model.Packet; import ru.serega6531.packmate.model.Packet;
import ru.serega6531.packmate.model.Stream; import ru.serega6531.packmate.model.Stream;
import javax.persistence.QueryHint;
import java.util.List; import java.util.List;
public interface StreamRepository extends JpaRepository<Stream, Long>, JpaSpecificationExecutor<Stream> { public interface StreamRepository extends JpaRepository<Stream, Long>, JpaSpecificationExecutor<Stream> {
@@ -16,13 +18,12 @@ public interface StreamRepository extends JpaRepository<Stream, Long>, JpaSpecif
long deleteByEndTimestampBeforeAndFavoriteIsFalse(long threshold); long deleteByEndTimestampBeforeAndFavoriteIsFalse(long threshold);
@Query("SELECT DISTINCT p FROM Packet p " + @Query("SELECT p FROM Packet p " +
"LEFT JOIN FETCH p.matches " + "LEFT JOIN FETCH p.matches " +
"WHERE p.stream.id = :streamId " + "WHERE p.stream.id = :streamId " +
"AND (:startingFrom IS NULL OR p.id > :startingFrom) " + "AND (:startingFrom IS NULL OR p.id > :startingFrom) " +
"ORDER BY p.id" "ORDER BY p.id"
) )
@QueryHints(@QueryHint(name = org.hibernate.jpa.QueryHints.HINT_PASS_DISTINCT_THROUGH, value = "false"))
List<Packet> getPackets(long streamId, Long startingFrom, Pageable pageable); List<Packet> getPackets(long streamId, Long startingFrom, Pageable pageable);
} }

View File

@@ -1,25 +1,31 @@
package ru.serega6531.packmate.service; package ru.serega6531.packmate.service;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper; import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.serega6531.packmate.model.CtfService; import ru.serega6531.packmate.model.CtfService;
import ru.serega6531.packmate.model.FoundPattern; import ru.serega6531.packmate.model.FoundPattern;
import ru.serega6531.packmate.model.Pattern; import ru.serega6531.packmate.model.Pattern;
import ru.serega6531.packmate.model.enums.PatternActionType; import ru.serega6531.packmate.model.enums.PatternActionType;
import ru.serega6531.packmate.model.enums.PatternDirectionType; import ru.serega6531.packmate.model.enums.PatternDirectionType;
import ru.serega6531.packmate.model.enums.SubscriptionMessageType; import ru.serega6531.packmate.model.enums.SubscriptionMessageType;
import ru.serega6531.packmate.model.pojo.PatternCreateDto;
import ru.serega6531.packmate.model.pojo.PatternDto; import ru.serega6531.packmate.model.pojo.PatternDto;
import ru.serega6531.packmate.model.pojo.PatternUpdateDto;
import ru.serega6531.packmate.model.pojo.SubscriptionMessage; import ru.serega6531.packmate.model.pojo.SubscriptionMessage;
import ru.serega6531.packmate.repository.PatternRepository; import ru.serega6531.packmate.repository.PatternRepository;
import javax.annotation.PostConstruct;
import java.time.Instant; import java.time.Instant;
import java.util.*; import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Service @Service
@Slf4j @Slf4j
@@ -59,11 +65,11 @@ public class PatternService {
public Set<FoundPattern> findMatches(byte[] bytes, CtfService service, PatternDirectionType directionType, PatternActionType actionType) { public Set<FoundPattern> findMatches(byte[] bytes, CtfService service, PatternDirectionType directionType, PatternActionType actionType) {
final List<Pattern> list = patterns.values().stream() final List<Pattern> list = patterns.values().stream()
.filter(Pattern::isEnabled) .filter(pattern -> pattern.isEnabled() && !pattern.isDeleted())
.filter(p -> p.getServiceId() == null || p.getServiceId() == service.getPort()) .filter(p -> p.getServiceId() == null || p.getServiceId().equals(service.getPort()))
.filter(p -> p.getActionType() == actionType) .filter(p -> p.getActionType() == actionType)
.filter(p -> p.getDirectionType() == directionType || p.getDirectionType() == PatternDirectionType.BOTH) .filter(p -> p.getDirectionType() == directionType || p.getDirectionType() == PatternDirectionType.BOTH)
.collect(Collectors.toList()); .toList();
return new PatternMatcher(bytes, list).findMatches(); return new PatternMatcher(bytes, list).findMatches();
} }
@@ -88,15 +94,47 @@ public class PatternService {
} }
} }
public Pattern save(Pattern pattern) { public void delete(int id) {
final Pattern pattern = find(id);
if (pattern != null) {
pattern.setDeleted(true);
final Pattern saved = repository.save(pattern);
patterns.put(id, saved);
log.info("Deleted pattern '{}' with value '{}'", pattern.getName(), pattern.getValue());
subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.SAVE_PATTERN, toDto(saved)));
}
}
@Transactional
public PatternDto create(PatternCreateDto dto) {
Pattern pattern = fromDto(dto);
pattern.setEnabled(true);
pattern.setDeleted(false);
pattern.setSearchStartTimestamp(System.currentTimeMillis());
Pattern saved = save(pattern);
return toDto(saved);
}
@Transactional
public PatternDto update(int id, PatternUpdateDto dto) {
Pattern pattern = repository.findById(id).orElseThrow();
modelMapper.map(dto, pattern);
Pattern saved = save(pattern);
return toDto(saved);
}
private Pattern save(Pattern pattern) {
try { try {
PatternMatcher.compilePattern(pattern); PatternMatcher.compilePattern(pattern);
} catch (Exception e) { } catch (Exception e) {
throw new IllegalArgumentException(e.getMessage()); throw new IllegalArgumentException(e.getMessage());
} }
pattern.setSearchStartTimestamp(System.currentTimeMillis());
final Pattern saved = repository.save(pattern); final Pattern saved = repository.save(pattern);
patterns.put(saved.getId(), saved); patterns.put(saved.getId(), saved);
@@ -121,12 +159,11 @@ public class PatternService {
} }
} }
public Pattern fromDto(PatternDto dto) { public Pattern fromDto(PatternCreateDto dto) {
return modelMapper.map(dto, Pattern.class); return modelMapper.map(dto, Pattern.class);
} }
public PatternDto toDto(Pattern pattern) { public PatternDto toDto(Pattern pattern) {
return modelMapper.map(pattern, PatternDto.class); return modelMapper.map(pattern, PatternDto.class);
} }
} }

View File

@@ -4,8 +4,8 @@ import lombok.extern.slf4j.Slf4j;
import org.pcap4j.core.PcapNativeException; import org.pcap4j.core.PcapNativeException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.serega6531.packmate.model.CtfService;
import ru.serega6531.packmate.model.enums.SubscriptionMessageType; import ru.serega6531.packmate.model.enums.SubscriptionMessageType;
import ru.serega6531.packmate.model.pojo.ServiceDto;
import ru.serega6531.packmate.model.pojo.SubscriptionMessage; import ru.serega6531.packmate.model.pojo.SubscriptionMessage;
import ru.serega6531.packmate.pcap.NoOpPcapWorker; import ru.serega6531.packmate.pcap.NoOpPcapWorker;
import ru.serega6531.packmate.pcap.PcapWorker; import ru.serega6531.packmate.pcap.PcapWorker;
@@ -40,14 +40,14 @@ public class PcapService {
} }
} }
public void updateFilter(Collection<CtfService> services) { public void updateFilter(Collection<ServiceDto> services) {
String filter; String filter;
if (services.isEmpty()) { if (services.isEmpty()) {
filter = "tcp or udp"; filter = "tcp or udp";
} else { } else {
final String ports = services.stream() final String ports = services.stream()
.map(CtfService::getPort) .map(ServiceDto::getPort)
.map(p -> "port " + p) .map(p -> "port " + p)
.collect(Collectors.joining(" or ")); .collect(Collectors.joining(" or "));

View File

@@ -1,21 +1,26 @@
package ru.serega6531.packmate.service; package ru.serega6531.packmate.service;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper; import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.model.CtfService; import ru.serega6531.packmate.model.CtfService;
import ru.serega6531.packmate.model.enums.SubscriptionMessageType; import ru.serega6531.packmate.model.enums.SubscriptionMessageType;
import ru.serega6531.packmate.model.pojo.ServiceCreateDto;
import ru.serega6531.packmate.model.pojo.ServiceDto; import ru.serega6531.packmate.model.pojo.ServiceDto;
import ru.serega6531.packmate.model.pojo.ServiceUpdateDto;
import ru.serega6531.packmate.model.pojo.SubscriptionMessage; import ru.serega6531.packmate.model.pojo.SubscriptionMessage;
import ru.serega6531.packmate.repository.ServiceRepository; import ru.serega6531.packmate.repository.ServiceRepository;
import javax.annotation.PostConstruct;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.util.HashMap;
import java.util.*; import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service @Service
@Slf4j @Slf4j
@@ -35,12 +40,12 @@ public class ServicesService {
SubscriptionService subscriptionService, SubscriptionService subscriptionService,
@Lazy PcapService pcapService, @Lazy PcapService pcapService,
ModelMapper modelMapper, ModelMapper modelMapper,
@Value("${local-ip}") String localIpString) throws UnknownHostException { PackmateProperties properties) {
this.repository = repository; this.repository = repository;
this.subscriptionService = subscriptionService; this.subscriptionService = subscriptionService;
this.pcapService = pcapService; this.pcapService = pcapService;
this.modelMapper = modelMapper; this.modelMapper = modelMapper;
this.localIp = InetAddress.getByName(localIpString); this.localIp = properties.localIp();
} }
@PostConstruct @PostConstruct
@@ -67,8 +72,11 @@ public class ServicesService {
return Optional.ofNullable(services.get(port)); return Optional.ofNullable(services.get(port));
} }
public Collection<CtfService> findAll() { public List<ServiceDto> findAll() {
return services.values(); return services.values()
.stream()
.map(this::toDto)
.toList();
} }
public void deleteByPort(int port) { public void deleteByPort(int port) {
@@ -82,9 +90,31 @@ public class ServicesService {
updateFilter(); updateFilter();
} }
public CtfService save(CtfService service) { @Transactional
log.info("Added or edited service '{}' at port {}", service.getName(), service.getPort()); public ServiceDto create(ServiceCreateDto dto) {
if (repository.existsById(dto.getPort())) {
throw new IllegalArgumentException("Service already exists");
}
CtfService service = fromDto(dto);
log.info("Added service '{}' at port {}", service.getName(), service.getPort());
return save(service);
}
@Transactional
public ServiceDto update(int port, ServiceUpdateDto dto) {
CtfService service = repository.findById(port).orElseThrow();
log.info("Edited service '{}' at port {}", service.getName(), service.getPort());
modelMapper.map(dto, service);
service.setPort(port);
return save(service);
}
private ServiceDto save(CtfService service) {
final CtfService saved = repository.save(service); final CtfService saved = repository.save(service);
services.put(saved.getPort(), saved); services.put(saved.getPort(), saved);
@@ -92,18 +122,18 @@ public class ServicesService {
updateFilter(); updateFilter();
return saved; return toDto(saved);
} }
public void updateFilter() { public void updateFilter() {
pcapService.updateFilter(findAll()); pcapService.updateFilter(findAll());
} }
public ServiceDto toDto(CtfService service) { private ServiceDto toDto(CtfService service) {
return modelMapper.map(service, ServiceDto.class); return modelMapper.map(service, ServiceDto.class);
} }
public CtfService fromDto(ServiceDto dto) { private CtfService fromDto(ServiceCreateDto dto) {
return modelMapper.map(dto, CtfService.class); return modelMapper.map(dto, CtfService.class);
} }

View File

@@ -4,7 +4,6 @@ import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.modelmapper.ModelMapper; import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
@@ -13,13 +12,21 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import ru.serega6531.packmate.model.*; import ru.serega6531.packmate.model.CtfService;
import ru.serega6531.packmate.model.FoundPattern;
import ru.serega6531.packmate.model.Packet;
import ru.serega6531.packmate.model.Pattern;
import ru.serega6531.packmate.model.Stream;
import ru.serega6531.packmate.model.enums.PatternActionType; import ru.serega6531.packmate.model.enums.PatternActionType;
import ru.serega6531.packmate.model.enums.PatternDirectionType; import ru.serega6531.packmate.model.enums.PatternDirectionType;
import ru.serega6531.packmate.model.enums.SubscriptionMessageType; import ru.serega6531.packmate.model.enums.SubscriptionMessageType;
import ru.serega6531.packmate.model.pojo.*; import ru.serega6531.packmate.model.pojo.PacketDto;
import ru.serega6531.packmate.model.pojo.StreamDto;
import ru.serega6531.packmate.model.pojo.StreamPagination;
import ru.serega6531.packmate.model.pojo.SubscriptionMessage;
import ru.serega6531.packmate.model.pojo.UnfinishedStream;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.repository.StreamRepository; import ru.serega6531.packmate.repository.StreamRepository;
import ru.serega6531.packmate.service.optimization.RsaKeysHolder;
import ru.serega6531.packmate.service.optimization.StreamOptimizer; import ru.serega6531.packmate.service.optimization.StreamOptimizer;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@@ -28,7 +35,6 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.stream.Collectors;
@Service @Service
@Slf4j @Slf4j
@@ -39,9 +45,7 @@ public class StreamService {
private final ServicesService servicesService; private final ServicesService servicesService;
private final CountingService countingService; private final CountingService countingService;
private final SubscriptionService subscriptionService; private final SubscriptionService subscriptionService;
private final RsaKeysHolder keysHolder;
private final ModelMapper modelMapper; private final ModelMapper modelMapper;
private final boolean ignoreEmptyPackets; private final boolean ignoreEmptyPackets;
private final java.util.regex.Pattern userAgentPattern = java.util.regex.Pattern.compile("User-Agent: (.+)\\r\\n"); private final java.util.regex.Pattern userAgentPattern = java.util.regex.Pattern.compile("User-Agent: (.+)\\r\\n");
@@ -52,17 +56,15 @@ public class StreamService {
ServicesService servicesService, ServicesService servicesService,
CountingService countingService, CountingService countingService,
SubscriptionService subscriptionService, SubscriptionService subscriptionService,
RsaKeysHolder keysHolder,
ModelMapper modelMapper, ModelMapper modelMapper,
@Value("${ignore-empty-packets}") boolean ignoreEmptyPackets) { PackmateProperties properties) {
this.repository = repository; this.repository = repository;
this.patternService = patternService; this.patternService = patternService;
this.servicesService = servicesService; this.servicesService = servicesService;
this.countingService = countingService; this.countingService = countingService;
this.subscriptionService = subscriptionService; this.subscriptionService = subscriptionService;
this.keysHolder = keysHolder;
this.modelMapper = modelMapper; this.modelMapper = modelMapper;
this.ignoreEmptyPackets = ignoreEmptyPackets; this.ignoreEmptyPackets = properties.ignoreEmptyPackets();
} }
/** /**
@@ -71,15 +73,15 @@ public class StreamService {
@Transactional(propagation = Propagation.NEVER) @Transactional(propagation = Propagation.NEVER)
public boolean saveNewStream(UnfinishedStream unfinishedStream, List<Packet> packets) { public boolean saveNewStream(UnfinishedStream unfinishedStream, List<Packet> packets) {
final var serviceOptional = servicesService.findService( final var serviceOptional = servicesService.findService(
unfinishedStream.getFirstIp(), unfinishedStream.firstIp(),
unfinishedStream.getFirstPort(), unfinishedStream.firstPort(),
unfinishedStream.getSecondIp(), unfinishedStream.secondIp(),
unfinishedStream.getSecondPort() unfinishedStream.secondPort()
); );
if (serviceOptional.isEmpty()) { if (serviceOptional.isEmpty()) {
log.warn("Failed to save the stream: service at port {} or {} does not exist", log.warn("Failed to save the stream: service at port {} or {} does not exist",
unfinishedStream.getFirstPort(), unfinishedStream.getSecondPort()); unfinishedStream.firstPort(), unfinishedStream.secondPort());
return false; return false;
} }
CtfService service = serviceOptional.get(); CtfService service = serviceOptional.get();
@@ -95,7 +97,10 @@ public class StreamService {
countingService.countStream(service.getPort(), packets.size()); countingService.countStream(service.getPort(), packets.size());
List<Packet> optimizedPackets = new StreamOptimizer(keysHolder, service, packets).optimizeStream(); int packetsSize = packets.stream().mapToInt(p -> p.getContent().length).sum();
int packetsCount = packets.size();
List<Packet> optimizedPackets = new StreamOptimizer(service, packets).optimizeStream();
if (isStreamIgnored(optimizedPackets, service)) { if (isStreamIgnored(optimizedPackets, service)) {
log.debug("New stream is ignored"); log.debug("New stream is ignored");
@@ -107,7 +112,7 @@ public class StreamService {
.findFirst(); .findFirst();
final Stream stream = new Stream(); final Stream stream = new Stream();
stream.setProtocol(unfinishedStream.getProtocol()); stream.setProtocol(unfinishedStream.protocol());
stream.setTtl(firstIncoming.map(Packet::getTtl).orElse(0)); stream.setTtl(firstIncoming.map(Packet::getTtl).orElse(0));
stream.setStartTimestamp(packets.get(0).getTimestamp()); stream.setStartTimestamp(packets.get(0).getTimestamp());
stream.setEndTimestamp(packets.get(packets.size() - 1).getTimestamp()); stream.setEndTimestamp(packets.get(packets.size() - 1).getTimestamp());
@@ -116,6 +121,9 @@ public class StreamService {
String userAgentHash = getUserAgentHash(optimizedPackets); String userAgentHash = getUserAgentHash(optimizedPackets);
stream.setUserAgentHash(userAgentHash); stream.setUserAgentHash(userAgentHash);
stream.setSizeBytes(packetsSize);
stream.setPacketsCount(packetsCount);
Set<Pattern> foundPatterns = matchPatterns(optimizedPackets, service); Set<Pattern> foundPatterns = matchPatterns(optimizedPackets, service);
stream.setFoundPatterns(foundPatterns); stream.setFoundPatterns(foundPatterns);
stream.setPackets(optimizedPackets); stream.setPackets(optimizedPackets);
@@ -190,7 +198,7 @@ public class StreamService {
foundPatterns.addAll(matches.stream() foundPatterns.addAll(matches.stream()
.map(FoundPattern::getPatternId) .map(FoundPattern::getPatternId)
.map(patternService::find) .map(patternService::find)
.collect(Collectors.toList())); .toList());
} }
return foundPatterns; return foundPatterns;
@@ -244,9 +252,12 @@ public class StreamService {
return saved; return saved;
} }
public List<Packet> getPackets(long streamId, @Nullable Long startingFrom, int pageSize) { @Transactional
// long safeStartingFrom = startingFrom != null ? startingFrom : 0; public List<PacketDto> getPackets(long streamId, @Nullable Long startingFrom, int pageSize) {
return repository.getPackets(streamId, startingFrom, Pageable.ofSize(pageSize)); return repository.getPackets(streamId, startingFrom, Pageable.ofSize(pageSize))
.stream()
.map(this::packetToDto)
.toList();
} }
/** /**
@@ -262,7 +273,8 @@ public class StreamService {
repository.setFavorite(id, favorite); repository.setFavorite(id, favorite);
} }
public List<Stream> findAll(StreamPagination pagination, Optional<Integer> service, boolean onlyFavorites) { @Transactional
public List<StreamDto> findAll(StreamPagination pagination, Optional<Integer> service, boolean onlyFavorites) {
PageRequest page = PageRequest.of(0, pagination.getPageSize(), Sort.Direction.DESC, "id"); PageRequest page = PageRequest.of(0, pagination.getPageSize(), Sort.Direction.DESC, "id");
Specification<Stream> spec = Specification.where(null); Specification<Stream> spec = Specification.where(null);
@@ -283,7 +295,11 @@ public class StreamService {
spec = spec.and(streamPatternsContains(pagination.getPattern())); spec = spec.and(streamPatternsContains(pagination.getPattern()));
} }
return repository.findAll(spec, page).getContent(); return repository.findAll(spec, page)
.getContent()
.stream()
.map(this::streamToDto)
.toList();
} }
public List<Stream> findAllBetweenTimestamps(long start, long end) { public List<Stream> findAllBetweenTimestamps(long start, long end) {

View File

@@ -1,180 +0,0 @@
package ru.serega6531.packmate.service.optimization;
import com.google.common.primitives.Bytes;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import ru.serega6531.packmate.model.Packet;
import ru.serega6531.packmate.utils.BytesUtils;
import ru.serega6531.packmate.utils.PacketUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@RequiredArgsConstructor
public class HttpChunksProcessor {
private static final String CHUNKED_HTTP_HEADER = "transfer-encoding: chunked\r\n";
private final List<Packet> packets;
private int position;
private boolean chunkStarted = false;
private final List<Packet> chunkPackets = new ArrayList<>();
public void processChunkedEncoding() {
int start = -1;
for (position = 0; position < packets.size(); position++) {
Packet packet = packets.get(position);
if (!packet.isIncoming()) {
String content = packet.getContentString();
boolean http = content.startsWith("HTTP/");
int contentPos = content.indexOf("\r\n\r\n");
if (http && contentPos != -1) { // начало body
String headers = content.substring(0, contentPos + 2); // захватываем первые \r\n
boolean chunked = headers.toLowerCase().contains(CHUNKED_HTTP_HEADER);
if (chunked) {
chunkStarted = true;
start = position;
chunkPackets.add(packet);
checkCompleteChunk(chunkPackets, start);
} else {
chunkStarted = false;
chunkPackets.clear();
}
} else if (chunkStarted) {
chunkPackets.add(packet);
checkCompleteChunk(chunkPackets, start);
}
}
}
}
private void checkCompleteChunk(List<Packet> packets, int start) {
boolean end = Arrays.equals(packets.get(packets.size() - 1).getContent(), "0\r\n\r\n".getBytes()) ||
BytesUtils.endsWith(packets.get(packets.size() - 1).getContent(), "\r\n0\r\n\r\n".getBytes());
if (end) {
processChunk(packets, start);
}
}
@SneakyThrows
private void processChunk(List<Packet> packets, int start) {
//noinspection OptionalGetWithoutIsPresent
final byte[] content = PacketUtils.mergePackets(packets).get();
ByteArrayOutputStream output = new ByteArrayOutputStream(content.length);
final int contentStart = Bytes.indexOf(content, "\r\n\r\n".getBytes()) + 4;
output.write(content, 0, contentStart);
ByteBuffer buf = ByteBuffer.wrap(Arrays.copyOfRange(content, contentStart, content.length));
while (true) {
final int chunkSize = readChunkSize(buf);
switch (chunkSize) {
case -1 -> {
log.warn("Failed to merge chunks, next chunk size not found");
resetChunk();
return;
}
case 0 -> {
buildWholePacket(packets, start, output);
return;
}
default -> {
if (!readChunk(buf, chunkSize, output)) return;
if (!readTrailer(buf)) return;
}
}
}
}
private boolean readChunk(ByteBuffer buf, int chunkSize, ByteArrayOutputStream output) throws IOException {
if (chunkSize > buf.remaining()) {
log.warn("Failed to merge chunks, chunk size too big: {} + {} > {}",
buf.position(), chunkSize, buf.capacity());
resetChunk();
return false;
}
byte[] chunk = new byte[chunkSize];
buf.get(chunk);
output.write(chunk);
return true;
}
private boolean readTrailer(ByteBuffer buf) {
if (buf.remaining() < 2) {
log.warn("Failed to merge chunks, chunk doesn't end with \\r\\n");
resetChunk();
return false;
}
int c1 = buf.get();
int c2 = buf.get();
if (c1 != '\r' || c2 != '\n') {
log.warn("Failed to merge chunks, chunk trailer is not equal to \\r\\n");
resetChunk();
return false;
}
return true;
}
private void buildWholePacket(List<Packet> packets, int start, ByteArrayOutputStream output) {
Packet result = Packet.builder()
.incoming(false)
.timestamp(packets.get(0).getTimestamp())
.ungzipped(false)
.webSocketParsed(false)
.tlsDecrypted(packets.get(0).isTlsDecrypted())
.content(output.toByteArray())
.build();
this.packets.removeAll(packets);
this.packets.add(start, result);
resetChunk();
position = start + 1;
}
private void resetChunk() {
chunkStarted = false;
chunkPackets.clear();
}
private int readChunkSize(ByteBuffer buf) {
StringBuilder sb = new StringBuilder();
while (buf.remaining() > 2) {
byte b = buf.get();
if ((b >= '0' && b <= '9') || (b >= 'a' && b <= 'f')) {
sb.append((char) b);
} else if (b == '\r') {
if (buf.get() == '\n') {
return Integer.parseInt(sb.toString(), 16);
} else {
return -1; // после \r не идет \n
}
} else {
return -1;
}
}
return -1;
}
}

View File

@@ -1,121 +0,0 @@
package ru.serega6531.packmate.service.optimization;
import com.google.common.primitives.Bytes;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import ru.serega6531.packmate.model.Packet;
import ru.serega6531.packmate.utils.PacketUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipException;
@Slf4j
@RequiredArgsConstructor
public class HttpGzipProcessor {
private static final String GZIP_HTTP_HEADER = "content-encoding: gzip\r\n";
private static final byte[] GZIP_HEADER = {0x1f, (byte) 0x8b, 0x08};
private final List<Packet> packets;
boolean gzipStarted = false;
private int position;
/**
* Попытаться распаковать GZIP из исходящих http пакетов. <br>
* GZIP поток начинается на найденном HTTP пакете с заголовком Content-Encoding: gzip
* (при этом заголовок HTTP может быть в другом пакете)<br>
* Поток заканчивается при обнаружении нового HTTP заголовка,
* при смене стороны передачи или при окончании всего стрима
*/
public void unpackGzip() {
int gzipStartPacket = 0;
for (position = 0; position < packets.size(); position++) {
Packet packet = packets.get(position);
if (packet.isIncoming() && gzipStarted) { // поток gzip закончился
extractGzip(gzipStartPacket, position - 1);
} else if (!packet.isIncoming()) {
String content = packet.getContentString();
int contentPos = content.indexOf("\r\n\r\n");
boolean http = content.startsWith("HTTP/");
if (http && gzipStarted) { // начался новый http пакет, заканчиваем старый gzip поток
extractGzip(gzipStartPacket, position - 1);
}
if (contentPos != -1) { // начало body
String headers = content.substring(0, contentPos + 2); // захватываем первые \r\n
boolean gziped = headers.toLowerCase().contains(GZIP_HTTP_HEADER);
if (gziped) {
gzipStarted = true;
gzipStartPacket = position;
}
}
}
}
if (gzipStarted) { // стрим закончился gzip пакетом
extractGzip(gzipStartPacket, packets.size() - 1);
}
}
/**
* Попытаться распаковать кусок пакетов с gzip body и вставить результат на их место
*/
private void extractGzip(int gzipStartPacket, int gzipEndPacket) {
List<Packet> cut = packets.subList(gzipStartPacket, gzipEndPacket + 1);
Packet decompressed = decompressGzipPackets(cut);
if (decompressed != null) {
packets.removeAll(cut);
packets.add(gzipStartPacket, decompressed);
gzipStarted = false;
position = gzipStartPacket + 1; // продвигаем указатель на следующий после склеенного блок
}
}
private Packet decompressGzipPackets(List<Packet> cut) {
//noinspection OptionalGetWithoutIsPresent
final byte[] content = PacketUtils.mergePackets(cut).get();
final int gzipStart = Bytes.indexOf(content, GZIP_HEADER);
byte[] httpHeader = Arrays.copyOfRange(content, 0, gzipStart);
byte[] gzipBytes = Arrays.copyOfRange(content, gzipStart, content.length);
try {
final GZIPInputStream gzipStream = new GZIPInputStream(new ByteArrayInputStream(gzipBytes));
ByteArrayOutputStream out = new ByteArrayOutputStream();
IOUtils.copy(gzipStream, out);
byte[] newContent = ArrayUtils.addAll(httpHeader, out.toByteArray());
log.debug("GZIP decompressed: {} -> {} bytes", gzipBytes.length, out.size());
return Packet.builder()
.incoming(false)
.timestamp(cut.get(0).getTimestamp())
.ungzipped(true)
.webSocketParsed(false)
.tlsDecrypted(cut.get(0).isTlsDecrypted())
.content(newContent)
.build();
} catch (ZipException e) {
log.warn("Failed to decompress gzip, leaving as it is: {}", e.getMessage());
} catch (IOException e) {
log.error("decompress gzip", e);
}
return null;
}
}

View File

@@ -0,0 +1,65 @@
package ru.serega6531.packmate.service.optimization;
import lombok.extern.slf4j.Slf4j;
import rawhttp.core.HttpMessage;
import rawhttp.core.RawHttp;
import rawhttp.core.RawHttpOptions;
import rawhttp.core.body.BodyReader;
import rawhttp.core.errors.InvalidHttpHeader;
import rawhttp.core.errors.InvalidHttpRequest;
import rawhttp.core.errors.InvalidHttpResponse;
import rawhttp.core.errors.InvalidMessageFrame;
import rawhttp.core.errors.UnknownEncodingException;
import ru.serega6531.packmate.model.Packet;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
@Slf4j
public class HttpProcessor {
private static final RawHttp rawHttp = new RawHttp(RawHttpOptions.strict());
public void process(List<Packet> packets) {
packets.stream()
.filter(p -> !p.isWebSocketParsed())
.forEach(this::processPacket);
}
private void processPacket(Packet packet) {
try {
ByteArrayInputStream contentStream = new ByteArrayInputStream(packet.getContent());
HttpMessage message;
if (packet.isIncoming()) {
message = rawHttp.parseRequest(contentStream).eagerly();
} else {
message = rawHttp.parseResponse(contentStream).eagerly();
}
packet.setContent(getDecodedMessage(message));
packet.setHasHttpBody(message.getBody().isPresent());
} catch (IOException | InvalidHttpRequest | InvalidHttpResponse | InvalidHttpHeader | InvalidMessageFrame |
UnknownEncodingException e) {
log.warn("Could not parse http packet", e);
}
}
private byte[] getDecodedMessage(HttpMessage message) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream(256);
message.getStartLine().writeTo(os);
message.getHeaders().writeTo(os);
Optional<? extends BodyReader> body = message.getBody();
if (body.isPresent()) {
body.get().writeDecodedTo(os, 256);
}
return os.toByteArray();
}
}

View File

@@ -1,6 +1,5 @@
package ru.serega6531.packmate.service.optimization; package ru.serega6531.packmate.service.optimization;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import ru.serega6531.packmate.model.Packet; import ru.serega6531.packmate.model.Packet;
@@ -9,17 +8,14 @@ import java.net.URLDecoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
@AllArgsConstructor
@Slf4j @Slf4j
public class HttpUrldecodeProcessor { public class HttpUrldecodeProcessor {
private final List<Packet> packets;
/** /**
* Декодирование urlencode с http пакета до смены стороны или окончания стрима * Декодирование urlencode с http пакета до смены стороны или окончания стрима
*/ */
@SneakyThrows @SneakyThrows
public void urldecodeRequests() { public void urldecodeRequests(List<Packet> packets) {
boolean httpStarted = false; boolean httpStarted = false;
for (Packet packet : packets) { for (Packet packet : packets) {

View File

@@ -1,30 +1,25 @@
package ru.serega6531.packmate.service.optimization; package ru.serega6531.packmate.service.optimization;
import lombok.AllArgsConstructor;
import ru.serega6531.packmate.model.Packet; import ru.serega6531.packmate.model.Packet;
import ru.serega6531.packmate.utils.PacketUtils; import ru.serega6531.packmate.utils.PacketUtils;
import java.util.List; import java.util.List;
@AllArgsConstructor
public class PacketsMerger { public class PacketsMerger {
private final List<Packet> packets;
/** /**
* Сжать соседние пакеты в одном направлении в один. * Сжать соседние пакеты в одном направлении в один. Не склеивает WS и не-WS пакеты.
* Выполняется после других оптимизаций чтобы правильно определять границы пакетов.
*/ */
public void mergeAdjacentPackets() { public void mergeAdjacentPackets(List<Packet> packets) {
int start = 0; int start = 0;
int packetsInRow = 0; int packetsInRow = 0;
boolean incoming = true; Packet previous = null;
for (int i = 0; i < packets.size(); i++) { for (int i = 0; i < packets.size(); i++) {
Packet packet = packets.get(i); Packet packet = packets.get(i);
if (packet.isIncoming() != incoming) { if (previous == null || !shouldBeInSameBatch(packet, previous)) {
if (packetsInRow > 1) { if (packetsInRow > 1) {
compress(start, i); compress(packets, start, i);
i = start + 1; // продвигаем указатель на следующий после склеенного блок i = start + 1; // продвигаем указатель на следующий после склеенного блок
} }
@@ -34,36 +29,38 @@ public class PacketsMerger {
packetsInRow++; packetsInRow++;
} }
incoming = packet.isIncoming(); previous = packet;
} }
if (packetsInRow > 1) { if (packetsInRow > 1) {
compress(start, packets.size()); compress(packets, start, packets.size());
} }
} }
/** /**
* Сжать кусок со start по end в один пакет * Сжать кусок со start по end в один пакет
*/ */
private void compress(int start, int end) { private void compress(List<Packet> packets, int start, int end) {
final List<Packet> cut = packets.subList(start, end); final List<Packet> cut = packets.subList(start, end);
final long timestamp = cut.get(0).getTimestamp(); final long timestamp = cut.get(0).getTimestamp();
final boolean ungzipped = cut.stream().anyMatch(Packet::isUngzipped); final boolean httpProcessed = cut.stream().anyMatch(Packet::isHttpProcessed);
final boolean webSocketParsed = cut.stream().anyMatch(Packet::isWebSocketParsed); final boolean webSocketParsed = cut.stream().anyMatch(Packet::isWebSocketParsed);
final boolean tlsDecrypted = cut.get(0).isTlsDecrypted();
final boolean incoming = cut.get(0).isIncoming(); final boolean incoming = cut.get(0).isIncoming();
//noinspection OptionalGetWithoutIsPresent final byte[] content = PacketUtils.mergePackets(cut);
final byte[] content = PacketUtils.mergePackets(cut).get();
packets.removeAll(cut); packets.removeAll(cut);
packets.add(start, Packet.builder() packets.add(start, Packet.builder()
.incoming(incoming) .incoming(incoming)
.timestamp(timestamp) .timestamp(timestamp)
.ungzipped(ungzipped) .httpProcessed(httpProcessed)
.webSocketParsed(webSocketParsed) .webSocketParsed(webSocketParsed)
.tlsDecrypted(tlsDecrypted)
.content(content) .content(content)
.build()); .build());
} }
private boolean shouldBeInSameBatch(Packet p1, Packet p2) {
return p1.isIncoming() == p2.isIncoming() &&
p1.isWebSocketParsed() == p2.isWebSocketParsed();
}
} }

View File

@@ -1,75 +0,0 @@
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<BigInteger, RSAPrivateKey> 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);
}
}

View File

@@ -1,7 +1,6 @@
package ru.serega6531.packmate.service.optimization; package ru.serega6531.packmate.service.optimization;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import ru.serega6531.packmate.model.CtfService; import ru.serega6531.packmate.model.CtfService;
import ru.serega6531.packmate.model.Packet; import ru.serega6531.packmate.model.Packet;
@@ -12,116 +11,55 @@ import java.util.List;
@Slf4j @Slf4j
public class StreamOptimizer { public class StreamOptimizer {
private final RsaKeysHolder keysHolder;
private final CtfService service; private final CtfService service;
private List<Packet> packets; private List<Packet> packets;
private final PacketsMerger merger = new PacketsMerger();
private final HttpUrldecodeProcessor urldecodeProcessor = new HttpUrldecodeProcessor();
private final HttpProcessor httpProcessor = new HttpProcessor();
/** /**
* Вызвать для выполнения оптимизаций на переданном списке пакетов. * Вызвать для выполнения оптимизаций на переданном списке пакетов.
*/ */
public List<Packet> optimizeStream() { public List<Packet> optimizeStream() {
if (service.isDecryptTls()) {
try {
decryptTls();
} catch (Exception e) {
log.warn("Error optimizing stream (tls)", e);
return packets;
}
}
if (service.isProcessChunkedEncoding()) {
try {
processChunkedEncoding();
} catch (Exception e) {
log.warn("Error optimizing stream (chunks)", e);
return packets;
}
}
if (service.isUngzipHttp()) {
try {
unpackGzip();
} catch (Exception e) {
log.warn("Error optimizing stream (gzip)", e);
return packets;
}
}
if (service.isParseWebSockets()) { if (service.isParseWebSockets()) {
try { try {
parseWebSockets(); parseWebSockets();
} catch (Exception e) { } catch (Exception e) {
log.warn("Error optimizing stream (websocketss)", e); log.warn("Error optimizing stream (websockets)", e);
return packets; return packets;
} }
} }
if (service.isUrldecodeHttpRequests()) { if (service.isUrldecodeHttpRequests()) {
try { try {
urldecodeRequests(); urldecodeProcessor.urldecodeRequests(packets);
} catch (Exception e) { } catch (Exception e) {
log.warn("Error optimizing stream (urldecode)", e); log.warn("Error optimizing stream (urldecode)", e);
return packets; return packets;
} }
} }
if (service.isMergeAdjacentPackets()) { if (service.isMergeAdjacentPackets() || service.isHttp()) {
try { try {
mergeAdjacentPackets(); merger.mergeAdjacentPackets(packets);
} catch (Exception e) { } catch (Exception e) {
log.warn("Error optimizing stream (adjacent)", e); log.warn("Error optimizing stream (adjacent)", e);
return packets; return packets;
} }
} }
if (service.isHttp()) {
try {
httpProcessor.process(packets);
} catch (Exception e) {
log.warn("Error optimizing stream (http)", e);
return packets; return packets;
} }
private void decryptTls() {
final TlsDecryptor tlsDecryptor = new TlsDecryptor(packets, keysHolder);
tlsDecryptor.decryptTls();
if (tlsDecryptor.isParsed()) {
packets = tlsDecryptor.getParsedPackets();
}
} }
/** return packets;
* Сжать соседние пакеты в одном направлении в один.
* Выполняется после других оптимизаций чтобы правильно определять границы пакетов.
*/
private void mergeAdjacentPackets() {
final PacketsMerger merger = new PacketsMerger(packets);
merger.mergeAdjacentPackets();
}
/**
* Декодирование urlencode с http пакета до смены стороны или окончания стрима
*/
@SneakyThrows
private void urldecodeRequests() {
final HttpUrldecodeProcessor processor = new HttpUrldecodeProcessor(packets);
processor.urldecodeRequests();
}
/**
* <a href="https://ru.wikipedia.org/wiki/Chunked_transfer_encoding">Chunked transfer encoding</a>
*/
private void processChunkedEncoding() {
HttpChunksProcessor processor = new HttpChunksProcessor(packets);
processor.processChunkedEncoding();
}
/**
* Попытаться распаковать GZIP из исходящих http пакетов. <br>
* GZIP поток начинается на найденном HTTP пакете с заголовком Content-Encoding: gzip
* (при этом заголовок HTTP может быть в другом пакете)<br>
* Поток заканчивается при обнаружении нового HTTP заголовка,
* при смене стороны передачи или при окончании всего стрима
*/
private void unpackGzip() {
final HttpGzipProcessor processor = new HttpGzipProcessor(packets);
processor.unpackGzip();
} }
private void parseWebSockets() { private void parseWebSockets() {

View File

@@ -1,300 +0,0 @@
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<Packet> packets;
private final RsaKeysHolder keysHolder;
@Getter
private boolean parsed = false;
private List<Packet> result;
private ListMultimap<Packet, TlsPacket.TlsHeader> 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);
clientRandom = clientHello.getRandom();
serverRandom = serverHello.getRandom();
decryptTlsRsa(blockCipher);
}
}
@SneakyThrows
private void decryptTlsRsa(String blockCipher) {
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<RSAPublicKey> 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<BcTlsSecret> 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();
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<Cipher> clientCipherOpt = createCipher(blockCipherMode, clientEncryptionKey, clientIV);
Optional<Cipher> 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<TlsPacket.TlsHeader> 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<BcTlsSecret> getPreMaster(RSAPrivateKey privateKey) {
Optional<HandshakeRecordContent> 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<RSAPublicKey> getRsaPublicKey() {
var certificateHandshakeOpt = getHandshake(HandshakeType.CERTIFICATE);
if (certificateHandshakeOpt.isEmpty()) {
return Optional.empty();
}
var certificateHandshake = (CertificateHandshakeRecordContent) certificateHandshakeOpt.get();
List<byte[]> 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<Cipher> 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<HandshakeRecordContent> 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<TlsPacket.TlsHeader> createTlsHeaders(Packet p) throws IllegalRawDataException {
List<TlsPacket.TlsHeader> 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<Packet> getParsedPackets() {
if (!parsed) {
throw new IllegalStateException("TLS is not parsed");
}
return result;
}
}

View File

@@ -120,14 +120,9 @@ public class WebSocketsParser {
} }
private Packet mimicPacket(Packet packet, byte[] content, boolean ws) { private Packet mimicPacket(Packet packet, byte[] content, boolean ws) {
return Packet.builder() return packet.toBuilder()
.content(content) .content(content)
.incoming(packet.isIncoming())
.timestamp(packet.getTimestamp())
.ttl(packet.getTtl())
.ungzipped(packet.isUngzipped())
.webSocketParsed(ws) .webSocketParsed(ws)
.tlsDecrypted(packet.isTlsDecrypted())
.build(); .build();
} }
@@ -138,8 +133,7 @@ public class WebSocketsParser {
for (List<Packet> side : sides) { for (List<Packet> side : sides) {
final Packet lastPacket = side.get(0); final Packet lastPacket = side.get(0);
//noinspection OptionalGetWithoutIsPresent final byte[] wsContent = PacketUtils.mergePackets(side);
final byte[] wsContent = PacketUtils.mergePackets(side).get();
final ByteBuffer buffer = ByteBuffer.wrap(wsContent); final ByteBuffer buffer = ByteBuffer.wrap(wsContent);
List<Framedata> frames; List<Framedata> frames;
@@ -153,14 +147,10 @@ public class WebSocketsParser {
for (Framedata frame : frames) { for (Framedata frame : frames) {
if (frame instanceof DataFrame) { if (frame instanceof DataFrame) {
parsedPackets.add(Packet.builder() parsedPackets.add(
lastPacket.toBuilder()
.content(frame.getPayloadData().array()) .content(frame.getPayloadData().array())
.incoming(lastPacket.isIncoming())
.timestamp(lastPacket.getTimestamp())
.ttl(lastPacket.getTtl())
.ungzipped(lastPacket.isUngzipped())
.webSocketParsed(true) .webSocketParsed(true)
.tlsDecrypted(lastPacket.isTlsDecrypted())
.build() .build()
); );
} }
@@ -179,13 +169,10 @@ public class WebSocketsParser {
} }
private String getHandshake(final List<Packet> packets) { private String getHandshake(final List<Packet> packets) {
final String handshake = PacketUtils.mergePackets(packets) final String handshake = new String(PacketUtils.mergePackets(packets));
.map(String::new)
.orElse(null);
if (handshake == null || if (!handshake.toLowerCase().contains(WEBSOCKET_CONNECTION_HEADER)
!handshake.toLowerCase().contains(WEBSOCKET_CONNECTION_HEADER) || || !handshake.toLowerCase().contains(WEBSOCKET_UPGRADE_HEADER)) {
!handshake.toLowerCase().contains(WEBSOCKET_UPGRADE_HEADER)) {
return null; return null;
} }

View File

@@ -1,172 +0,0 @@
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<byte[]> getRawFields() {
List<byte[]> 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);
}
}
}

View File

@@ -1,49 +0,0 @@
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();
}
}

View File

@@ -1,24 +0,0 @@
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();
}
}
}

View File

@@ -1,23 +0,0 @@
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);
}
}

View File

@@ -1,33 +0,0 @@
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();
}
}

View File

@@ -1,46 +0,0 @@
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<KeyShareEntry> 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();
}
}

View File

@@ -1,14 +0,0 @@
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);
}
}

View File

@@ -1,42 +0,0 @@
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;
}
}

View File

@@ -1,44 +0,0 @@
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;
}
}

View File

@@ -1,108 +0,0 @@
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;
}
}

View File

@@ -1,16 +0,0 @@
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;
}
}

View File

@@ -1,57 +0,0 @@
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<Short, NamedCurve> 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);
}
}

View File

@@ -1,58 +0,0 @@
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<Short, SignatureScheme> 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);
}
}

View File

@@ -1,65 +0,0 @@
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<Byte, AlertDescription> {
private static final Map<Byte, AlertDescription> 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());
}
}

View File

@@ -1,32 +0,0 @@
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<Byte, AlertLevel> {
private static final Map<Byte, AlertLevel> 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());
}
}

View File

@@ -1,741 +0,0 @@
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<Short, CipherSuite> {
private static final Map<Short, CipherSuite> 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());
}
}

View File

@@ -1,38 +0,0 @@
package ru.serega6531.packmate.service.optimization.tls.numbers;
import org.pcap4j.packet.namednumber.NamedNumber;
import java.util.HashMap;
import java.util.Map;
public class CompressionMethod extends NamedNumber<Byte, CompressionMethod> {
// 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<Byte, CompressionMethod> registry = new HashMap<>();
static {
registry.put(NULL.value(), NULL);
}
public CompressionMethod(Byte value, String name) {
super(value, name);
}
public static CompressionMethod getInstance(Byte value) {
if (registry.containsKey(value)) {
return registry.get(value);
} else {
return new CompressionMethod(value, "Unknown");
}
}
@Override
public int compareTo(CompressionMethod o) {
return value().compareTo(o.value());
}
}

View File

@@ -1,44 +0,0 @@
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<Byte, ContentType> {
// 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<Byte, ContentType> 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());
}
}

View File

@@ -1,98 +0,0 @@
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<Short, ExtensionType> {
private static final Map<Short, ExtensionType> 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());
}
}

View File

@@ -1,52 +0,0 @@
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<Byte, HandshakeType> {
private static final Map<Byte, HandshakeType> 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());
}
}

View File

@@ -1,33 +0,0 @@
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<Byte, HeartbeatMessageType> {
private static final Map<Byte, HeartbeatMessageType> 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());
}
}

View File

@@ -1,98 +0,0 @@
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<Short, KeyGroup> {
// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
private static final Map<Short, KeyGroup> 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());
}
}

View File

@@ -1,41 +0,0 @@
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<Short, TlsVersion> {
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<Short, TlsVersion> 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());
}
}

View File

@@ -1,40 +0,0 @@
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]";
}
}
}

View File

@@ -1,33 +0,0 @@
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]";
}
}

View File

@@ -1,27 +0,0 @@
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;
}
}

View File

@@ -1,73 +0,0 @@
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();
}
}

View File

@@ -1,53 +0,0 @@
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]";
}
}

View File

@@ -1,7 +0,0 @@
package ru.serega6531.packmate.service.optimization.tls.records;
import java.io.Serializable;
public interface TlsRecord extends Serializable {
}

View File

@@ -1,36 +0,0 @@
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]";
}
}

View File

@@ -1,52 +0,0 @@
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<byte[]> 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<byte[]> 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();
}
}

View File

@@ -1,82 +0,0 @@
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<CipherSuite> cipherSuites;
private byte compressionMethodsLength;
private List<CompressionMethod> 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();
}
}

View File

@@ -1,4 +0,0 @@
package ru.serega6531.packmate.service.optimization.tls.records.handshakes;
public interface HandshakeRecordContent {
}

View File

@@ -1,81 +0,0 @@
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<TlsExtension> 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<TlsExtension> 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();
}
}

View File

@@ -1,64 +0,0 @@
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();
}
}

View File

@@ -1,31 +1,30 @@
package ru.serega6531.packmate.tasks; package ru.serega6531.packmate.tasks;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.service.StreamService; import ru.serega6531.packmate.service.StreamService;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@Component @Component
@Slf4j @Slf4j
@ConditionalOnExpression("${old-streams-cleanup-enabled:false} && '${capture-mode}' == 'LIVE'") @ConditionalOnExpression("${packmate.cleanup.enabled:false} && '${packmate.capture-mode}' == 'LIVE'")
public class OldStreamsCleanupTask { public class OldStreamsCleanupTask {
private final StreamService service; private final StreamService service;
private final int oldStreamsThreshold; private final int oldStreamsThreshold;
public OldStreamsCleanupTask(StreamService service, @Value("${old-streams-threshold}") int oldStreamsThreshold) { public OldStreamsCleanupTask(StreamService service, PackmateProperties properties) {
this.service = service; this.service = service;
this.oldStreamsThreshold = oldStreamsThreshold; this.oldStreamsThreshold = properties.cleanup().threshold();
} }
@Scheduled(fixedDelayString = "PT${cleanup-interval}M", initialDelayString = "PT1M") @Scheduled(fixedDelayString = "PT${packmate.cleanup.interval}M", initialDelayString = "PT1M")
public void cleanup() { public void cleanup() {
ZonedDateTime before = ZonedDateTime.now().minus(oldStreamsThreshold, ChronoUnit.MINUTES); ZonedDateTime before = ZonedDateTime.now().minusMinutes(oldStreamsThreshold);
log.info("Cleaning up old non-favorite streams (before {})", before); log.info("Cleaning up old non-favorite streams (before {})", before);
long deleted = service.cleanupOldStreams(before); long deleted = service.cleanupOldStreams(before);
log.info("Deleted {} rows", deleted); log.info("Deleted {} rows", deleted);

View File

@@ -1,10 +1,10 @@
package ru.serega6531.packmate.tasks; package ru.serega6531.packmate.tasks;
import org.pcap4j.core.PcapNativeException; import org.pcap4j.core.PcapNativeException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.model.enums.CaptureMode; import ru.serega6531.packmate.model.enums.CaptureMode;
import ru.serega6531.packmate.service.PcapService; import ru.serega6531.packmate.service.PcapService;
import ru.serega6531.packmate.service.ServicesService; import ru.serega6531.packmate.service.ServicesService;
@@ -12,29 +12,23 @@ import ru.serega6531.packmate.service.ServicesService;
@Component @Component
public class StartupListener { public class StartupListener {
@Value("${enable-capture}") private final PackmateProperties packmateProperties;
private boolean enableCapture;
@Value("${capture-mode}")
private CaptureMode captureMode;
private final PcapService pcapService; private final PcapService pcapService;
private final ServicesService servicesService; private final ServicesService servicesService;
public StartupListener(PcapService pcapService, ServicesService servicesService) { public StartupListener(PcapService pcapService, ServicesService servicesService, PackmateProperties packmateProperties) {
this.pcapService = pcapService; this.pcapService = pcapService;
this.servicesService = servicesService; this.servicesService = servicesService;
this.packmateProperties = packmateProperties;
} }
@EventListener(ApplicationReadyEvent.class) @EventListener(ApplicationReadyEvent.class)
public void afterStartup() throws PcapNativeException { public void afterStartup() throws PcapNativeException {
if (enableCapture) {
servicesService.updateFilter(); servicesService.updateFilter();
if (captureMode == CaptureMode.LIVE) { if (packmateProperties.captureMode() == CaptureMode.LIVE) {
pcapService.start(); pcapService.start();
} }
} }
}
} }

View File

@@ -2,10 +2,10 @@ package ru.serega6531.packmate.tasks;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ru.serega6531.packmate.properties.PackmateProperties;
import ru.serega6531.packmate.model.enums.Protocol; import ru.serega6531.packmate.model.enums.Protocol;
import ru.serega6531.packmate.pcap.PcapWorker; import ru.serega6531.packmate.pcap.PcapWorker;
@@ -13,7 +13,7 @@ import java.util.concurrent.TimeUnit;
@Component @Component
@Slf4j @Slf4j
@ConditionalOnProperty(name = "capture-mode", havingValue = "LIVE") @ConditionalOnProperty(name = "packmate.capture-mode", havingValue = "LIVE")
public class TimeoutStreamsSaver { public class TimeoutStreamsSaver {
private final PcapWorker pcapWorker; private final PcapWorker pcapWorker;
@@ -22,14 +22,13 @@ public class TimeoutStreamsSaver {
@Autowired @Autowired
public TimeoutStreamsSaver(PcapWorker pcapWorker, public TimeoutStreamsSaver(PcapWorker pcapWorker,
@Value("${udp-stream-timeout}") int udpStreamTimeout, PackmateProperties properties) {
@Value("${tcp-stream-timeout}") int tcpStreamTimeout) {
this.pcapWorker = pcapWorker; this.pcapWorker = pcapWorker;
this.udpStreamTimeoutMillis = TimeUnit.SECONDS.toMillis(udpStreamTimeout); this.udpStreamTimeoutMillis = TimeUnit.SECONDS.toMillis(properties.timeout().udpStreamTimeout());
this.tcpStreamTimeoutMillis = TimeUnit.SECONDS.toMillis(tcpStreamTimeout); this.tcpStreamTimeoutMillis = TimeUnit.SECONDS.toMillis(properties.timeout().tcpStreamTimeout());
} }
@Scheduled(fixedRateString = "PT${timeout-stream-check-interval}S", initialDelayString = "PT${timeout-stream-check-interval}S") @Scheduled(fixedRateString = "PT${packmate.timeout.check-interval}S", initialDelayString = "PT${packmate.timeout.check-interval}S")
public void saveStreams() { public void saveStreams() {
int streamsClosed = pcapWorker.closeTimeoutStreams(Protocol.UDP, udpStreamTimeoutMillis); int streamsClosed = pcapWorker.closeTimeoutStreams(Protocol.UDP, udpStreamTimeoutMillis);
if (streamsClosed > 0) { if (streamsClosed > 0) {

View File

@@ -1,20 +1,28 @@
package ru.serega6531.packmate.utils; package ru.serega6531.packmate.utils;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.ArrayUtils;
import ru.serega6531.packmate.model.Packet; import ru.serega6531.packmate.model.Packet;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
@UtilityClass @UtilityClass
public class PacketUtils { public class PacketUtils {
public Optional<byte[]> mergePackets(List<Packet> cut) { public byte[] mergePackets(List<Packet> cut) {
return cut.stream() int size = cut.stream()
.map(Packet::getContent) .map(Packet::getContent)
.reduce(ArrayUtils::addAll); .mapToInt(c -> c.length)
.sum();
ByteArrayOutputStream os = new ByteArrayOutputStream(size);
cut.stream()
.map(Packet::getContent)
.forEach(os::writeBytes);
return os.toByteArray();
} }
public List<List<Packet>> sliceToSides(List<Packet> packets) { public List<List<Packet>> sliceToSides(List<Packet> packets) {

View File

@@ -1,6 +1,6 @@
spring: spring:
datasource: datasource:
url: "jdbc:postgresql://localhost/packmate" url: "jdbc:postgresql://localhost:5432/packmate"
username: "packmate" username: "packmate"
password: "123456" password: "123456"
driver-class-name: org.postgresql.Driver driver-class-name: org.postgresql.Driver
@@ -12,22 +12,27 @@ spring:
jdbc: jdbc:
batch_size: 20 batch_size: 20
order_inserts: true order_inserts: true
temp:
use_jdbc_metadata_defaults: false
database-platform: org.hibernate.dialect.PostgreSQLDialect database-platform: org.hibernate.dialect.PostgreSQLDialect
server:
compression:
enabled: true
min-response-size: 1KB
enable-capture: true packmate:
capture-mode: LIVE # LIVE, FILE, VIEW capture-mode: LIVE # LIVE, FILE, VIEW
interface-name: enp0s31f6 interface-name: enp0s31f6
pcap-file: file.pcap pcap-file: file.pcap
local-ip: "192.168.0.125" local-ip: "192.168.0.125"
account-login: BinaryBears web:
account-password: 123456 account-login: BinaryBears
udp-stream-timeout: 20 # seconds account-password: 123456
tcp-stream-timeout: 40 # seconds timeout:
timeout-stream-check-interval: 10 # seconds udp-stream-timeout: 20 # seconds
old-streams-cleanup-enabled: true tcp-stream-timeout: 40 # seconds
old-streams-threshold: 240 # minutes check-interval: 10 # seconds
cleanup-interval: 5 # minutes cleanup:
ignore-empty-packets: true enabled: true
threshold: 240 # minutes
interval: 5 # minutes
ignore-empty-packets: true

View File

@@ -1,42 +0,0 @@
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<Packet> getPackets() throws IOException {
boolean in = true;
List<Packet> 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;
}
}

View File

@@ -3,8 +3,7 @@ package ru.serega6531.packmate;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import ru.serega6531.packmate.model.Packet; import ru.serega6531.packmate.model.Packet;
import ru.serega6531.packmate.service.optimization.HttpChunksProcessor; import ru.serega6531.packmate.service.optimization.HttpProcessor;
import ru.serega6531.packmate.service.optimization.HttpGzipProcessor;
import ru.serega6531.packmate.service.optimization.HttpUrldecodeProcessor; import ru.serega6531.packmate.service.optimization.HttpUrldecodeProcessor;
import ru.serega6531.packmate.service.optimization.PacketsMerger; import ru.serega6531.packmate.service.optimization.PacketsMerger;
@@ -27,18 +26,18 @@ class StreamOptimizerTest {
List<Packet> list = new ArrayList<>(); List<Packet> list = new ArrayList<>();
list.add(p); list.add(p);
new HttpGzipProcessor(list).unpackGzip(); new HttpProcessor().process(list);
final String processed = list.get(0).getContentString(); final String processed = list.get(0).getContentString();
assertTrue(processed.contains("aaabbb")); assertTrue(processed.contains("aaabbb"));
} }
@Test @Test
void testUrldecodeRequests() { void testUrldecodeRequests() {
Packet p = createPacket("GET /?q=%D0%B0+%D0%B1 HTTP/1.1\r\n\r\n".getBytes(), true); Packet p = createPacket("GET /?q=%D0%B0+%D0%B1 HTTP/1.1\r\nHost: localhost:8080\r\n\r\n".getBytes(), true);
List<Packet> list = new ArrayList<>(); List<Packet> list = new ArrayList<>();
list.add(p); list.add(p);
new HttpUrldecodeProcessor(list).urldecodeRequests(); new HttpUrldecodeProcessor().urldecodeRequests(list);
final String processed = list.get(0).getContentString(); final String processed = list.get(0).getContentString();
assertTrue(processed.contains("а б")); assertTrue(processed.contains("а б"));
} }
@@ -60,7 +59,7 @@ class StreamOptimizerTest {
list.add(p5); list.add(p5);
list.add(p6); list.add(p6);
new PacketsMerger(list).mergeAdjacentPackets(); new PacketsMerger().mergeAdjacentPackets(list);
assertEquals(4, list.size()); assertEquals(4, list.size());
assertEquals(2, list.get(1).getContent().length); assertEquals(2, list.get(1).getContent().length);
@@ -74,7 +73,7 @@ class StreamOptimizerTest {
"6\r\nChunk1\r\n6\r\nChunk2\r\n0\r\n\r\n"; "6\r\nChunk1\r\n6\r\nChunk2\r\n0\r\n\r\n";
List<Packet> packets = new ArrayList<>(List.of(createPacket(content.getBytes(), false))); List<Packet> packets = new ArrayList<>(List.of(createPacket(content.getBytes(), false)));
new HttpChunksProcessor(packets).processChunkedEncoding(); new HttpProcessor().process(packets);
assertEquals(1, packets.size()); assertEquals(1, packets.size());
assertTrue(packets.get(0).getContentString().contains("Chunk1Chunk2")); assertTrue(packets.get(0).getContentString().contains("Chunk1Chunk2"));

View File

@@ -1,39 +0,0 @@
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<Packet> 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<Packet> 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");
}
}

View File

@@ -1,28 +0,0 @@
-----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-----

View File

@@ -1,20 +0,0 @@
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