Расшифровка TLS
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
package ru.serega6531.packmate.service.optimization;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.serega6531.packmate.utils.TlsUtils;
|
||||
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
import java.io.File;
|
||||
import java.math.BigInteger;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class RsaKeysHolder {
|
||||
|
||||
// Key: N from RSA public key
|
||||
private final Map<BigInteger, RSAPrivateKey> keys = new HashMap<>();
|
||||
|
||||
public void addKey(File pemFile, File keyFile) {
|
||||
if(!pemFile.exists() || !keyFile.exists()) {
|
||||
throw new IllegalArgumentException("One of files does not exist");
|
||||
}
|
||||
|
||||
X509KeyManager keyManager = TlsUtils.createKeyManager(pemFile, keyFile);
|
||||
|
||||
// X509Certificate[] certificateChain = keyManager.getCertificateChain("1");
|
||||
RSAPrivateKey privateKey = ((RSAPrivateKey) keyManager.getPrivateKey("1"));
|
||||
keys.put(privateKey.getModulus(), privateKey);
|
||||
}
|
||||
|
||||
public RSAPrivateKey getKey(BigInteger modulus) {
|
||||
return keys.get(modulus);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +1,54 @@
|
||||
package ru.serega6531.packmate.service.optimization;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
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.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.BasicRecordContent;
|
||||
import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ClientHelloHandshakeRecordContent;
|
||||
import ru.serega6531.packmate.service.optimization.tls.records.handshakes.HandshakeRecordContent;
|
||||
import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ServerHelloHandshakeRecordContent;
|
||||
import ru.serega6531.packmate.utils.TlsUtils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@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;
|
||||
|
||||
@SneakyThrows
|
||||
public void decryptTls() {
|
||||
File pemFile = new File(getClass().getClassLoader().getResource("tls.pem").getFile());
|
||||
File keyFile = new File(getClass().getClassLoader().getResource("tls.key").getFile());
|
||||
X509KeyManager keyManager = TlsUtils.createKeyManager(pemFile, keyFile);
|
||||
ListMultimap<Packet, TlsPacket.TlsHeader> tlsPackets = ArrayListMultimap.create(packets.size(), 1);
|
||||
|
||||
X509Certificate[] certificateChain = keyManager.getCertificateChain("1");
|
||||
RSAPrivateKey privateKey = ((RSAPrivateKey) keyManager.getPrivateKey("1"));
|
||||
|
||||
Map<Packet, List<TlsPacket.TlsHeader>> tlsPackets = packets.stream()
|
||||
.collect(Collectors.toMap(p -> p, this::createTlsHeaders));
|
||||
packets.forEach(p -> tlsPackets.putAll(p, createTlsHeaders(p)));
|
||||
|
||||
ClientHelloHandshakeRecordContent clientHello = (ClientHelloHandshakeRecordContent)
|
||||
getHandshake(tlsPackets.values(), HandshakeType.CLIENT_HELLO).orElseThrow();
|
||||
@@ -65,10 +62,18 @@ public class TlsDecryptor {
|
||||
|
||||
if (cipherSuite.name().startsWith("TLS_RSA_WITH_")) {
|
||||
Matcher matcher = cipherSuitePattern.matcher(cipherSuite.name());
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
matcher.find();
|
||||
String blockCipher = matcher.group(1);
|
||||
String hashAlgo = matcher.group(2);
|
||||
|
||||
//TODO
|
||||
RSAPrivateKey privateKey = keysHolder.getKey(null);
|
||||
if(privateKey == null) {
|
||||
log.warn("Key for modulus not found: {}", "TODO");
|
||||
return;
|
||||
}
|
||||
|
||||
BasicRecordContent clientKeyExchange = (BasicRecordContent)
|
||||
getHandshake(tlsPackets.values(), HandshakeType.CLIENT_KEY_EXCHANGE).orElseThrow();
|
||||
|
||||
@@ -83,7 +88,8 @@ public class TlsDecryptor {
|
||||
BcTlsSecret preSecret = new BcTlsSecret(new BcTlsCrypto(null), preMaster);
|
||||
TlsSecret masterSecret = preSecret.deriveUsingPRF(
|
||||
PRFAlgorithm.tls_prf_sha256, ExporterLabel.master_secret, randomCS, 48);
|
||||
byte[] expanded = masterSecret.deriveUsingPRF(PRFAlgorithm.tls_prf_sha256, ExporterLabel.key_expansion, randomSC, 136).extract(); // для sha256
|
||||
byte[] expanded = masterSecret.deriveUsingPRF(
|
||||
PRFAlgorithm.tls_prf_sha256, ExporterLabel.key_expansion, randomSC, 136).extract(); // для sha256
|
||||
|
||||
byte[] clientMacKey = new byte[20];
|
||||
byte[] serverMacKey = new byte[20];
|
||||
@@ -100,33 +106,77 @@ public class TlsDecryptor {
|
||||
bb.get(clientIV);
|
||||
bb.get(serverIV);
|
||||
|
||||
Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding"); // TLS_RSA_WITH_AES_256_CBC_SHA
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(clientEncryptionKey, "AES");
|
||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(clientIV);
|
||||
aes.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
|
||||
byte[] clientFinishedEncrypted = getFinishedData(tlsPackets, true);
|
||||
byte[] serverFinishedEncrypted = getFinishedData(tlsPackets, false);
|
||||
|
||||
byte[] data = tlsPackets.entrySet().stream()
|
||||
.filter(ent -> ent.getKey().isIncoming())
|
||||
.map(Map.Entry::getValue)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(p -> p.getContentType() == ContentType.HANDSHAKE)
|
||||
.map(p -> ((HandshakeRecord) p.getRecord()))
|
||||
.filter(r -> r.getHandshakeType() == HandshakeType.ENCRYPTED_HANDSHAKE_MESSAGE)
|
||||
.map(r -> ((BasicRecordContent) r.getContent()))
|
||||
.findFirst()
|
||||
.orElseThrow()
|
||||
.getContent();
|
||||
Cipher clientCipher = createCipher(clientEncryptionKey, clientIV, clientFinishedEncrypted);
|
||||
// byte[] clientFinishedData = clientCipher.update(clientFinishedEncrypted);
|
||||
// HandshakeRecord clientFinished = HandshakeRecord.newInstance(clientFinishedData, 16, clientFinishedData.length - 16);
|
||||
|
||||
byte[] decrypt = aes.doFinal(data);
|
||||
System.out.println();
|
||||
Cipher serverCipher = createCipher(serverEncryptionKey, serverIV, serverFinishedEncrypted);
|
||||
// byte[] serverFinishedData = serverCipher.update(serverFinishedEncrypted);
|
||||
// HandshakeRecord serverFinished = HandshakeRecord.newInstance(serverFinishedData, 16, serverFinishedData.length - 16);
|
||||
|
||||
for (Map.Entry<Packet, TlsPacket.TlsHeader> entry : tlsPackets.entries()) {
|
||||
if (entry.getValue().getContentType() == ContentType.APPLICATION_DATA) {
|
||||
byte[] data = ((ApplicationDataRecord) entry.getValue().getRecord()).getData();
|
||||
boolean client = entry.getKey().isIncoming();
|
||||
|
||||
byte[] decoded;
|
||||
|
||||
if(client) {
|
||||
decoded = clientCipher.update(data);
|
||||
} else {
|
||||
decoded = serverCipher.update(data);
|
||||
}
|
||||
|
||||
decoded = clearDecodedData(decoded);
|
||||
String string = new String(decoded);
|
||||
System.out.println(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Optional<HandshakeRecordContent> getHandshake(Collection<List<TlsPacket.TlsHeader>> packets,
|
||||
@SneakyThrows
|
||||
private Cipher createCipher(byte[] key, byte[] iv, byte[] initData) {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // TLS_RSA_WITH_AES_256_CBC_SHA
|
||||
SecretKeySpec serverSkeySpec = new SecretKeySpec(key, "AES");
|
||||
IvParameterSpec serverIvParameterSpec = new IvParameterSpec(iv);
|
||||
cipher.init(Cipher.DECRYPT_MODE, serverSkeySpec, serverIvParameterSpec);
|
||||
cipher.update(initData);
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
||||
private byte[] clearDecodedData(byte[] decoded) {
|
||||
int start = 32;
|
||||
int end = decoded.length - 6; //FIXME
|
||||
decoded = ByteArrays.getSubArray(decoded, start, end - start);
|
||||
return decoded;
|
||||
}
|
||||
|
||||
private byte[] getFinishedData(ListMultimap<Packet, TlsPacket.TlsHeader> tlsPackets, boolean incoming) {
|
||||
return ((BasicRecordContent) getHandshake(tlsPackets.asMap().entrySet().stream()
|
||||
.filter(ent -> ent.getKey().isIncoming() == incoming)
|
||||
.map(Map.Entry::getValue)
|
||||
.flatMap(Collection::stream), HandshakeType.ENCRYPTED_HANDSHAKE_MESSAGE))
|
||||
.getContent();
|
||||
}
|
||||
|
||||
private HandshakeRecordContent getHandshake(Stream<TlsPacket.TlsHeader> stream, HandshakeType handshakeType) {
|
||||
return stream.filter(p -> p.getContentType() == ContentType.HANDSHAKE)
|
||||
.map(p -> ((HandshakeRecord) p.getRecord()))
|
||||
.filter(r -> r.getHandshakeType() == handshakeType)
|
||||
.map(r -> ((BasicRecordContent) r.getContent()))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
private Optional<HandshakeRecordContent> getHandshake(Collection<TlsPacket.TlsHeader> packets,
|
||||
HandshakeType handshakeType) {
|
||||
return packets.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.filter(p -> p.getContentType() == ContentType.HANDSHAKE)
|
||||
.map(p -> ((HandshakeRecord) p.getRecord()))
|
||||
.filter(r -> r.getHandshakeType() == handshakeType)
|
||||
|
||||
Reference in New Issue
Block a user