Добавлен PRF

This commit is contained in:
serega6531
2020-04-22 19:27:38 +03:00
parent 72155ba99a
commit 482d74f4b4
3 changed files with 229 additions and 1 deletions

View File

@@ -2,6 +2,7 @@ package ru.serega6531.packmate.service.optimization;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang3.ArrayUtils;
import ru.serega6531.packmate.model.Packet;
import ru.serega6531.packmate.service.optimization.tls.TlsPacket;
import ru.serega6531.packmate.service.optimization.tls.keys.TlsKeyUtils;
@@ -13,6 +14,7 @@ import ru.serega6531.packmate.service.optimization.tls.records.handshakes.BasicR
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.PRF;
import ru.serega6531.packmate.utils.TlsUtils;
import javax.crypto.Cipher;
@@ -21,11 +23,15 @@ import java.io.File;
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;
@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;
@SneakyThrows
@@ -50,7 +56,12 @@ public class TlsDecryptor {
CipherSuite cipherSuite = serverHello.getCipherSuite();
if(cipherSuite.name().startsWith("TLS_RSA_")) {
if(cipherSuite.name().startsWith("TLS_RSA_WITH_")) {
Matcher matcher = cipherSuitePattern.matcher(cipherSuite.name());
matcher.find();
String blockCipher = matcher.group(1);
String hashAlgo = matcher.group(2);
BasicRecordContent clientKeyExchange = (BasicRecordContent)
getHandshake(tlsPackets.values(), HandshakeType.CLIENT_KEY_EXCHANGE).orElseThrow();
@@ -59,7 +70,11 @@ public class TlsDecryptor {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] preMaster = cipher.doFinal(encryptedPreMaster);
byte[] seed1 = ArrayUtils.addAll(clientRandom, serverRandom);
byte[] seed2 = ArrayUtils.addAll(serverRandom, clientRandom);
byte[] masterSecret = PRF.getBytes(preMaster, "master secret", seed1, 48);
byte[] expanded = PRF.getBytes(masterSecret, "key expansion", seed2, 136);
System.out.println();
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright 2001-2011 Joel Hockey (joel.hockey@gmail.com). All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package ru.serega6531.packmate.utils;
import java.security.MessageDigest;
/**
* https://github.com/joelhockey/tls/blob/master/src/main/java/net/java/jless/tls/HMAC.java
*/
public class HMAC {
private byte[] k_ipad = new byte[64];
private byte[] k_opad = new byte[64];
MessageDigest md = null;
/**
* Class constructor specifying the MessageDigest and secret to use
*
* @param md the MessageDigest (MD5 or SHA1).
* @param key the secret to seed the md.
*/
public HMAC(MessageDigest md, byte[] key) {
setMD(md);
setKey(key);
}
/**
* Set the MessageDigest for HMAC
*
* @param md the MessageDigest
*/
public void setMD(MessageDigest md) {
this.md = md;
}
/**
* Set the secret key for HMAC
*
* @param key the key.
*/
public void setKey(byte[] key) {
int keyLength = 0;
// get keyLength.
if (key == null) {
keyLength = 0;
} else {
keyLength = key.length;
}
// if the key is longer than 64 bytes then hash it.
byte[] tempKey = keyLength > 64 ? md.digest(key) : key;
// get m_k_ipad and m_k_opad
for (int i = 0; i < keyLength; i++) {
k_ipad[i] = (byte) (0x36 ^ tempKey[i]);
k_opad[i] = (byte) (0x5C ^ tempKey[i]);
}
for (int i = keyLength; i < 64; i++) {
k_ipad[i] = 0x36;
k_opad[i] = 0x5C;
}
}
/**
* Digest the HMAC
*
* @param input the byte array input
* @return HMAC value
*/
public byte[] digest(byte[] input) {
md.reset();
md.update(k_ipad);
md.update(input);
byte[] inner = md.digest();
md.update(k_opad);
md.update(inner);
return md.digest();
}
}

View File

@@ -0,0 +1,110 @@
package ru.serega6531.packmate.utils;
import lombok.experimental.UtilityClass;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Based on <a href="https://github.com/NivekT/Java/blob/master/SecureChannel/PRF.java">PRF.java</a>
*/
@UtilityClass
public class PRF {
private static final MessageDigest md5;
private static final MessageDigest sha;
private static final HMAC hmac = new HMAC(null, null);
static {
try {
md5 = MessageDigest.getInstance("MD5");
sha = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 or SHA failed to initialize");
}
}
/**
* Generates the PRF of the given inputs
* @param secret
* @param label
* @param seed
* @param length The length of the output to generate.
* @return PRF of inputs
*/
public byte[] getBytes(byte[] secret, String label, byte[] seed, int length) {
byte[] output = new byte[length];
// split secret into S1 and S2
int lenS1 = secret.length / 2 + secret.length % 2;
byte[] s1 = new byte[lenS1];
byte[] s2 = new byte[lenS1];
System.arraycopy(secret, 0, s1, 0, lenS1);
System.arraycopy(secret, secret.length - lenS1, s2, 0, lenS1);
// get the seed as concatenation of label and seed
byte[] labelAndSeed = new byte[label.length() + seed.length];
System.arraycopy(label.getBytes(), 0, labelAndSeed, 0, label.length());
System.arraycopy(seed, 0, labelAndSeed, label.length(), seed.length);
byte[] md5Output = p_hash(md5, 16, s1, labelAndSeed, length);
byte[] shaOutput = p_hash(sha, 20, s2, labelAndSeed, length);
// XOR md5 and sha to get output
for (int i = 0; i < length; i++) {
output[i] = (byte) (md5Output[i] ^ shaOutput[i]);
}
return output;
}
/**
* Perform the P_hash function
* @param md The MessageDigest function to use
* @param digestLength The length of output from the given digest
* @param secret The TLS secret
* @param seed The seed to use
* @param length The desired length of the output.
* @return The P_hash of the inputs.
*/
private byte[] p_hash(MessageDigest md, int digestLength, byte[] secret,
byte[] seed, int length) {
// set up our hmac
hmac.setMD(md);
hmac.setKey(secret);
byte[] output = new byte[length]; // what we return
int offset = 0; // how much data we have created so far
int toCopy = 0; // the amount of data to copy from current HMAC
byte[] a = seed; // initialise A(0)
// concatenation of A and seed
byte[] aSeed = new byte[digestLength + seed.length];
System.arraycopy(seed, 0, aSeed, digestLength, seed.length);
byte[] tempBuf = null;
// continually perform HMACs and concatenate until we have enough output
while( offset < length ) {
// calculate the A to use.
a = hmac.digest(a);
// concatenate A and seed and perform HMAC
System.arraycopy(a, 0, aSeed, 0, digestLength);
tempBuf = hmac.digest(aSeed);
// work out how much needs to be copied and copy it
toCopy = Math.min(tempBuf.length, (length - offset));
System.arraycopy(tempBuf, 0, output, offset, toCopy);
offset += toCopy;
}
return output;
}
}