Работа над расшифровкой RSA TLS

This commit is contained in:
serega6531
2020-04-22 00:26:44 +03:00
parent 042303dd7e
commit 72155ba99a
17 changed files with 236 additions and 248 deletions

View File

@@ -2,19 +2,26 @@ package ru.serega6531.packmate.service.optimization;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.security.crypto.codec.Hex;
import ru.serega6531.packmate.model.Packet;
import ru.serega6531.packmate.utils.PacketUtils;
import ru.serega6531.packmate.utils.SSLUtils;
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.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.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.crypto.Cipher;
import javax.net.ssl.X509KeyManager;
import java.io.File;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.util.*;
import java.util.stream.Collectors;
@RequiredArgsConstructor
public class TlsDecryptor {
@@ -23,86 +30,65 @@ public class TlsDecryptor {
@SneakyThrows
public void decryptTls() {
List<List<Packet>> sides = PacketUtils.sliceToSides(packets);
File pemFile = new File(getClass().getClassLoader().getResource("tls.pem").getFile());
File keyFile = new File(getClass().getClassLoader().getResource("tls.key").getFile());
SSLContext context = SSLUtils.createContext(pemFile, keyFile, new TlsFakeSecureRandom());
SSLEngine serverEngine = context.createSSLEngine();
serverEngine.setUseClientMode(false);
serverEngine.setNeedClientAuth(true);
X509KeyManager keyManager = TlsUtils.createKeyManager(pemFile, keyFile);
ByteBuffer decodedServerBuf = ByteBuffer.allocate(1000);
ByteBuffer tmp = ByteBuffer.allocate(50);
ByteBuffer tmp2 = ByteBuffer.allocate(50000);
// tmp.put((byte)1);
X509Certificate[] certificateChain = keyManager.getCertificateChain("1");
RSAPrivateKey privateKey = ((RSAPrivateKey) keyManager.getPrivateKey("1"));
unwrap(serverEngine, packets.get(0).getContent(), decodedServerBuf);
wrap(serverEngine, tmp, tmp2);
wrap(serverEngine, tmp, tmp2);
wrap(serverEngine, tmp, tmp2);
unwrap(serverEngine, packets.get(2).getContent(), decodedServerBuf);
unwrap(serverEngine, packets.get(3).getContent(), decodedServerBuf);
unwrap(serverEngine, packets.get(4).getContent(), decodedServerBuf);
unwrap(serverEngine, packets.get(5).getContent(), decodedServerBuf);
Map<Packet, List<TlsPacket.TlsHeader>> tlsPackets = packets.stream()
.collect(Collectors.toMap(p -> p, this::createTlsHeaders));
System.out.println();
ClientHelloHandshakeRecordContent clientHello = (ClientHelloHandshakeRecordContent)
getHandshake(tlsPackets.values(), HandshakeType.CLIENT_HELLO).orElseThrow();
ServerHelloHandshakeRecordContent serverHello = (ServerHelloHandshakeRecordContent)
getHandshake(tlsPackets.values(), HandshakeType.SERVER_HELLO).orElseThrow();
byte[] clientRandom = clientHello.getRandom();
byte[] serverRandom = serverHello.getRandom();
CipherSuite cipherSuite = serverHello.getCipherSuite();
if(cipherSuite.name().startsWith("TLS_RSA_")) {
BasicRecordContent clientKeyExchange = (BasicRecordContent)
getHandshake(tlsPackets.values(), HandshakeType.CLIENT_KEY_EXCHANGE).orElseThrow();
byte[] encryptedPreMaster = TlsKeyUtils.getClientRsaPreMaster(clientKeyExchange.getContent(), 0);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] preMaster = cipher.doFinal(encryptedPreMaster);
System.out.println();
}
}
private Optional<HandshakeRecordContent> getHandshake(Collection<List<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)
.map(HandshakeRecord::getContent)
.findFirst();
}
@SneakyThrows
private void unwrap(SSLEngine serverEngine, byte[] content, ByteBuffer buf) {
SSLEngineResult unwrap = serverEngine.unwrap(ByteBuffer.wrap(content), buf);
System.out.println("UNWRAP " + unwrap);
Runnable delegatedTask = serverEngine.getDelegatedTask();
if(delegatedTask != null) {
delegatedTask.run();
}
}
private List<TlsPacket.TlsHeader> createTlsHeaders(Packet p) {
List<TlsPacket.TlsHeader> headers = new ArrayList<>();
TlsPacket tlsPacket = TlsPacket.newPacket(p.getContent(), 0, p.getContent().length);
@SneakyThrows
private void wrap(SSLEngine serverEngine, ByteBuffer src, ByteBuffer dest) {
SSLEngineResult wrap = serverEngine.wrap(src, dest);
System.out.println("WRAP " + wrap);
Runnable delegatedTask = serverEngine.getDelegatedTask();
if(delegatedTask != null) {
delegatedTask.run();
}
}
headers.add(tlsPacket.getHeader());
private static class TlsFakeSecureRandom extends SecureRandom {
/*
state 0 - engineInit(SSLContextImpl.java:117)
stage 1 - SessionId.<init> -> RandomCookie
stage 2 - server random (ServerHello.java:575)
stage 3 - XDHKeyPairGenerator.generateKeyPair -> XECOperations.generatePrivate
*/
private int state = 0;
@Override
public void nextBytes(byte[] bytes) {
System.out.println("STATE " + state);
StackWalker.getInstance().forEach(System.out::println);
System.out.println("-----------------");
switch (state) {
case 0 -> Arrays.fill(bytes, (byte) 0);
case 1, 2, 3 -> System.arraycopy(getFakeBytes(), 0, bytes, 0, bytes.length);
}
state++;
}
private byte[] getFakeBytes() {
return switch (state) {
case 1 -> Hex.decode("0ab8b3409555d3d658b1844f52dfc0116467c4b9088d1deb504f3935c10de893");
case 2 -> Hex.decode("b5474b785c5e9bbadf2b0cd136e9aaf8bc2d89583ef96c479b531b94808349cc");
case 3 -> Hex.decode("801d96be72cbbd2f4e33b5ec7e5e0b073636269e42c17d1d8996fdd28c9f7230");
default -> throw new IllegalStateException("Unexpected value: " + state);
};
while (tlsPacket.getPayload() != null) {
tlsPacket = (TlsPacket) tlsPacket.getPayload();
headers.add(tlsPacket.getHeader());
}
return headers;
}
}

View File

@@ -120,6 +120,18 @@ public class TlsPacket extends AbstractPacket {
}
}
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<>();

View File

@@ -1,26 +1,22 @@
package ru.serega6531.packmate.service.optimization.tls.keys;
import ru.serega6531.packmate.service.optimization.tls.keys.enums.SignatureHashAlgorithmHash;
import ru.serega6531.packmate.service.optimization.tls.keys.enums.SignatureHashAlgorithmSignature;
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 SignatureHashAlgorithmHash signatureHashAlgorithmHash;
private final SignatureHashAlgorithmSignature signatureHashAlgorithmSignature;
private final SignatureScheme signatureScheme;
private final byte[] signature;
public DhClientParams(byte[] p, byte[] g, byte[] pubkey,
SignatureHashAlgorithmHash signatureHashAlgorithmHash,
SignatureHashAlgorithmSignature signatureHashAlgorithmSignature,
SignatureScheme signatureScheme,
byte[] signature) {
this.p = p;
this.g = g;
this.pubkey = pubkey;
this.signatureHashAlgorithmHash = signatureHashAlgorithmHash;
this.signatureHashAlgorithmSignature = signatureHashAlgorithmSignature;
this.signatureScheme = signatureScheme;
this.signature = signature;
}
@@ -36,12 +32,8 @@ public class DhClientParams {
return pubkey;
}
public SignatureHashAlgorithmHash getSignatureHashAlgorithmHash() {
return signatureHashAlgorithmHash;
}
public SignatureHashAlgorithmSignature getSignatureHashAlgorithmSignature() {
return signatureHashAlgorithmSignature;
public SignatureScheme getSignatureScheme() {
return signatureScheme;
}
public byte[] getSignature() {

View File

@@ -2,27 +2,23 @@ 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.SignatureHashAlgorithmHash;
import ru.serega6531.packmate.service.optimization.tls.keys.enums.SignatureHashAlgorithmSignature;
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 SignatureHashAlgorithmHash signatureHashAlgorithmHash;
private final SignatureHashAlgorithmSignature signatureHashAlgorithmSignature;
private final SignatureScheme signatureScheme;
private final byte[] signature;
public EcdheServerParams(CurveType curveType, NamedCurve namedCurve, byte[] pubkey,
SignatureHashAlgorithmHash signatureHashAlgorithmHash,
SignatureHashAlgorithmSignature signatureHashAlgorithmSignature,
SignatureScheme signatureScheme,
byte[] signature) {
this.curveType = curveType;
this.namedCurve = namedCurve;
this.pubkey = pubkey;
this.signatureHashAlgorithmHash = signatureHashAlgorithmHash;
this.signatureHashAlgorithmSignature = signatureHashAlgorithmSignature;
this.signatureScheme = signatureScheme;
this.signature = signature;
}
@@ -38,12 +34,8 @@ public class EcdheServerParams {
return pubkey;
}
public SignatureHashAlgorithmHash getSignatureHashAlgorithmHash() {
return signatureHashAlgorithmHash;
}
public SignatureHashAlgorithmSignature getSignatureHashAlgorithmSignature() {
return signatureHashAlgorithmSignature;
public SignatureScheme getSignatureScheme() {
return signatureScheme;
}
public byte[] getSignature() {

View File

@@ -1,22 +0,0 @@
package ru.serega6531.packmate.service.optimization.tls.keys;
import ru.serega6531.packmate.service.optimization.tls.numbers.TlsVersion;
public class RsaServerParams {
private final TlsVersion version;
private final byte[] encryptedPreMasterSecret;
public RsaServerParams(TlsVersion version, byte[] encryptedPreMasterSecret) {
this.version = version;
this.encryptedPreMasterSecret = encryptedPreMasterSecret;
}
public TlsVersion getVersion() {
return version;
}
public byte[] getEncryptedPreMasterSecret() {
return encryptedPreMasterSecret;
}
}

View File

@@ -2,9 +2,7 @@ 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.SignatureHashAlgorithmHash;
import ru.serega6531.packmate.service.optimization.tls.keys.enums.SignatureHashAlgorithmSignature;
import ru.serega6531.packmate.service.optimization.tls.numbers.TlsVersion;
import ru.serega6531.packmate.service.optimization.tls.keys.enums.SignatureScheme;
import java.nio.ByteBuffer;
@@ -31,13 +29,10 @@ public final class TlsKeyUtils {
byte[] pubKey = new byte[pubKeyLength]; // aka Ys
bb.get(pubKey);
SignatureHashAlgorithmHash signatureHashAlgorithmHash =
SignatureHashAlgorithmHash.findByValue(bb.getShort());
SignatureHashAlgorithmSignature signatureHashAlgorithmSignature =
SignatureHashAlgorithmSignature.findByValue(bb.getShort());
SignatureScheme signatureScheme = SignatureScheme.findByValue(bb.getShort());
if (signatureHashAlgorithmHash == null || signatureHashAlgorithmSignature == null) {
throw new IllegalArgumentException("Unknown signature data");
if (signatureScheme == null) {
throw new IllegalArgumentException("Unknown signature scheme");
}
short signatureLength = bb.getShort();
@@ -45,7 +40,7 @@ public final class TlsKeyUtils {
bb.get(signature);
return new DhClientParams(p, g, pubKey, signatureHashAlgorithmHash, signatureHashAlgorithmSignature, signature);
return new DhClientParams(p, g, pubKey, signatureScheme, signature);
}
/**
@@ -70,13 +65,10 @@ public final class TlsKeyUtils {
byte[] pubkey = new byte[pubkeyLength];
bb.get(pubkey);
SignatureHashAlgorithmHash signatureHashAlgorithmHash =
SignatureHashAlgorithmHash.findByValue(bb.getShort());
SignatureHashAlgorithmSignature signatureHashAlgorithmSignature =
SignatureHashAlgorithmSignature.findByValue(bb.getShort());
SignatureScheme signatureScheme = SignatureScheme.findByValue(bb.getShort());
if (signatureHashAlgorithmHash == null || signatureHashAlgorithmSignature == null) {
throw new IllegalArgumentException("Unknown signature data");
if (signatureScheme == null) {
throw new IllegalArgumentException("Unknown signature scheme");
}
short signatureLength = bb.getShort();
@@ -84,8 +76,7 @@ public final class TlsKeyUtils {
bb.get(signature);
return new EcdheServerParams(curveType, namedCurve, pubkey,
signatureHashAlgorithmHash, signatureHashAlgorithmSignature, signature);
return new EcdheServerParams(curveType, namedCurve, pubkey, signatureScheme, signature);
}
// https://ldapwiki.com/wiki/ClientKeyExchange
@@ -104,14 +95,14 @@ public final class TlsKeyUtils {
return pubkey;
}
public static RsaServerParams parseClientRsa(byte[] rawData, int offset) {
public static byte[] getClientRsaPreMaster(byte[] rawData, int offset) {
ByteBuffer bb = ByteBuffer.wrap(rawData).position(offset);
TlsVersion version = TlsVersion.getInstance(bb.getShort());
byte[] encryptedPreMasterSecret = new byte[46];
bb.get(encryptedPreMasterSecret);
int length = bb.getShort();
byte[] encryptedPreMaster = new byte[length];
bb.get(encryptedPreMaster);
return new RsaServerParams(version, encryptedPreMasterSecret);
return encryptedPreMaster;
}
}

View File

@@ -5,7 +5,33 @@ import java.util.Map;
public enum NamedCurve {
SECP256R1((short) 0x0017);
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;

View File

@@ -1,33 +0,0 @@
package ru.serega6531.packmate.service.optimization.tls.keys.enums;
import java.util.HashMap;
import java.util.Map;
public enum SignatureHashAlgorithmHash {
SHA256((byte) 4),
SHA512((byte) 6);
private final byte value;
private static final Map<Byte, SignatureHashAlgorithmHash> map = new HashMap<>();
SignatureHashAlgorithmHash(byte value) {
this.value = value;
}
static {
for (SignatureHashAlgorithmHash curve : values()) {
map.put(curve.getValue(), curve);
}
}
public byte getValue() {
return value;
}
public static SignatureHashAlgorithmHash findByValue(short value) {
return map.get(value);
}
}

View File

@@ -1,33 +0,0 @@
package ru.serega6531.packmate.service.optimization.tls.keys.enums;
import java.util.HashMap;
import java.util.Map;
public enum SignatureHashAlgorithmSignature {
RSA((byte) 1),
ECDSA((byte) 3);
private final byte value;
private static final Map<Byte, SignatureHashAlgorithmSignature> map = new HashMap<>();
SignatureHashAlgorithmSignature(byte value) {
this.value = value;
}
static {
for (SignatureHashAlgorithmSignature curve : values()) {
map.put(curve.getValue(), curve);
}
}
public byte getValue() {
return value;
}
public static SignatureHashAlgorithmSignature findByValue(short value) {
return map.get(value);
}
}

View File

@@ -0,0 +1,58 @@
package ru.serega6531.packmate.service.optimization.tls.keys.enums;
import java.util.HashMap;
import java.util.Map;
public enum SignatureScheme {
/* RSASSA-PKCS1-v1_5 algorithms */
RSA_PKCS1_SHA256((short) 0x0401),
RSA_PKCS1_SHA384((short) 0x0501),
RSA_PKCS1_SHA512((short) 0x0601),
/* ECDSA algorithms */
ECDSA_SECP256R1_SHA256((short) 0x0403),
ECDSA_SECP384R1_SHA384((short) 0x0503),
ECDSA_SECP521R1_SHA512((short) 0x0603),
/* RSASSA-PSS algorithms with public key OID RSAEncryption */
RSA_PSS_RSAE_SHA256((short) 0x0804),
RSA_PSS_RSAE_SHA384((short) 0x0805),
RSA_PSS_RSAE_SHA512((short) 0x0806),
/* EDDSA algorithms */
ED25519((short) 0x0807),
ED448((short) 0x0808),
/* RSASSA-PSS algorithms with public key OID RSASSA-PSS */
RSA_PSS_PSS_SHA256((short) 0x0809),
RSA_PSS_PSS_SHA384((short) 0x080a),
RSA_PSS_PSS_SHA512((short) 0x080b),
/* Legacy algorithms */
RSA_PKCS1_SHA1((short) 0x0201),
ECDSA_SHA1((short) 0x0203);
private final short value;
private static final Map<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

@@ -56,6 +56,14 @@ public class HandshakeRecord implements TlsRecord {
}
}
public HandshakeType getHandshakeType() {
return handshakeType;
}
public HandshakeRecordContent getContent() {
return content;
}
@Override
public String toString() {
return " Handshake length: " + handshakeLength + "\n" +

View File

@@ -25,6 +25,10 @@ public class BasicRecordContent implements HandshakeRecordContent {
}
}
public byte[] getContent() {
return content;
}
@Override
public String toString() {
return " [" + content.length + " bytes]";

View File

@@ -55,6 +55,22 @@ public abstract class HelloHandshakeRecordContent implements HandshakeRecordCont
}
}
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" +

View File

@@ -46,6 +46,14 @@ public class ServerHelloHandshakeRecordContent extends HelloHandshakeRecordConte
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" +

View File

@@ -4,19 +4,17 @@ import com.google.common.base.Splitter;
import lombok.SneakyThrows;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509KeyManager;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import static com.google.common.base.Preconditions.checkState;
public class SSLUtils {
public class TlsUtils {
@SneakyThrows
public static SSLContext createContext(File pemFile, File keyFile, SecureRandom random) {
public static X509KeyManager createKeyManager(File pemFile, File keyFile) {
final String pass = "abcdef";
File jksKeystoreFile = File.createTempFile("packmate_", ".jks");
@@ -43,13 +41,7 @@ public class SSLUtils {
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keystore, pass.toCharArray());
SSLContext ret = SSLContext.getInstance("TLSv1.2");
TrustManagerFactory factory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
factory.init(keystore);
ret.init(keyManagerFactory.getKeyManagers(), factory.getTrustManagers(), random);
return ret;
return (X509KeyManager) keyManagerFactory.getKeyManagers()[0];
}
}