PRF берется через УпругийЗамок
This commit is contained in:
@@ -36,6 +36,8 @@ dependencies {
|
|||||||
compile 'org.pcap4j:pcap4j-packetfactory-static:1.8.2'
|
compile 'org.pcap4j:pcap4j-packetfactory-static:1.8.2'
|
||||||
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
|
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
|
||||||
compile group: 'org.java-websocket', name: 'Java-WebSocket', version: '1.5.0-SNAPSHOT'
|
compile group: 'org.java-websocket', name: 'Java-WebSocket', version: '1.5.0-SNAPSHOT'
|
||||||
|
compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.65'
|
||||||
|
compile group: 'org.bouncycastle', name: 'bctls-jdk15on', version: '1.65'
|
||||||
compileOnly 'org.projectlombok:lombok'
|
compileOnly 'org.projectlombok:lombok'
|
||||||
runtimeOnly 'org.springframework.boot:spring-boot-devtools'
|
runtimeOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
runtimeOnly 'org.postgresql:postgresql'
|
runtimeOnly 'org.postgresql:postgresql'
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ package ru.serega6531.packmate.service.optimization;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
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 ru.serega6531.packmate.model.Packet;
|
import ru.serega6531.packmate.model.Packet;
|
||||||
import ru.serega6531.packmate.service.optimization.tls.TlsPacket;
|
import ru.serega6531.packmate.service.optimization.tls.TlsPacket;
|
||||||
import ru.serega6531.packmate.service.optimization.tls.keys.TlsKeyUtils;
|
import ru.serega6531.packmate.service.optimization.tls.keys.TlsKeyUtils;
|
||||||
@@ -14,7 +19,6 @@ 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.ClientHelloHandshakeRecordContent;
|
||||||
import ru.serega6531.packmate.service.optimization.tls.records.handshakes.HandshakeRecordContent;
|
import ru.serega6531.packmate.service.optimization.tls.records.handshakes.HandshakeRecordContent;
|
||||||
import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ServerHelloHandshakeRecordContent;
|
import ru.serega6531.packmate.service.optimization.tls.records.handshakes.ServerHelloHandshakeRecordContent;
|
||||||
import ru.serega6531.packmate.utils.PRF;
|
|
||||||
import ru.serega6531.packmate.utils.TlsUtils;
|
import ru.serega6531.packmate.utils.TlsUtils;
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
@@ -76,8 +80,10 @@ public class TlsDecryptor {
|
|||||||
byte[] randomCS = ArrayUtils.addAll(clientRandom, serverRandom);
|
byte[] randomCS = ArrayUtils.addAll(clientRandom, serverRandom);
|
||||||
byte[] randomSC = ArrayUtils.addAll(serverRandom, clientRandom);
|
byte[] randomSC = ArrayUtils.addAll(serverRandom, clientRandom);
|
||||||
|
|
||||||
byte[] masterSecret = PRF.getBytes(preMaster, "master secret", randomCS, 48);
|
BcTlsSecret preSecret = new BcTlsSecret(new BcTlsCrypto(null), preMaster);
|
||||||
byte[] expanded = PRF.getBytes(masterSecret, "key expansion", randomSC, 136);
|
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[] clientMacKey = new byte[20];
|
byte[] clientMacKey = new byte[20];
|
||||||
byte[] serverMacKey = new byte[20];
|
byte[] serverMacKey = new byte[20];
|
||||||
@@ -94,7 +100,7 @@ public class TlsDecryptor {
|
|||||||
bb.get(clientIV);
|
bb.get(clientIV);
|
||||||
bb.get(serverIV);
|
bb.get(serverIV);
|
||||||
|
|
||||||
Cipher aes = Cipher.getInstance("AES/CBC/NoPadding"); // TLS_RSA_WITH_AES_256_CBC_SHA
|
Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding"); // TLS_RSA_WITH_AES_256_CBC_SHA
|
||||||
SecretKeySpec skeySpec = new SecretKeySpec(clientEncryptionKey, "AES");
|
SecretKeySpec skeySpec = new SecretKeySpec(clientEncryptionKey, "AES");
|
||||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(clientIV);
|
IvParameterSpec ivParameterSpec = new IvParameterSpec(clientIV);
|
||||||
aes.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
|
aes.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user