Расшифровка TLS

This commit is contained in:
serega6531
2020-04-23 22:40:27 +03:00
parent e019ade85d
commit 0e460011c2
4 changed files with 131 additions and 35 deletions

View File

@@ -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);
}
}

View File

@@ -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)