Skip to content

Commit

Permalink
Implement Minecraft Education v1.12.60 support
Browse files Browse the repository at this point in the history
Changes:
  * Support both MCEE and MCPE versions.
  * Config entry to enable/disable education support
  * Enable 2 way encryption by default now whilst still performing mitm
  * Update for 1.16
  * Set raknetProtocol Version from codec
  • Loading branch information
bundabrg committed Jul 15, 2020
1 parent 16c8a4e commit a91c842
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 9 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,6 @@ config.yml
logs/
logs/*
packet-logs/
packet-logs/*
packet-logs/*
data/*
sessions/*
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ __ProxyPass requires Java 8 u162 or later to function correctly due to the encr

__[Jenkins](https://ci.nukkitx.com/job/NukkitX/job/ProxyPass/job/master/)__

__[Protocol library](https://github.com/NukkitX/Protocol) used in this project__
__[Protocol library](https://github.com/NukkitX/Protocol) used in this project__
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,20 @@
<version>1.3.9</version>
<scope>provided</scope>
</dependency>
<!-- Current Bedrock Version -->
<dependency>
<groupId>com.nukkitx.protocol</groupId>
<artifactId>bedrock-v407</artifactId>
<version>2.6.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!-- Current Education Version -->
<dependency>
<groupId>com.nukkitx.protocol</groupId>
<artifactId>bedrock-v363</artifactId>
<version>2.6.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/nukkitx/proxypass/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public class Configuration {
@JsonProperty("log-to")
private LogTo logTo = LogTo.FILE;

@JsonProperty("education")
private boolean education = false;

@JsonProperty("ignored-packets")
private Set<String> ignoredPackets = Collections.emptySet();

Expand Down
13 changes: 11 additions & 2 deletions src/main/java/com/nukkitx/proxypass/ProxyPass.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.nukkitx.protocol.bedrock.BedrockClient;
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
import com.nukkitx.protocol.bedrock.BedrockServer;
import com.nukkitx.protocol.bedrock.v363.Bedrock_v363;
import com.nukkitx.protocol.bedrock.v407.Bedrock_v407;
import com.nukkitx.proxypass.network.ProxyBedrockEventHandler;
import io.netty.util.ResourceLeakDetector;
Expand All @@ -37,8 +38,8 @@ public class ProxyPass {
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
public static final YAMLMapper YAML_MAPPER = (YAMLMapper) new YAMLMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
public static final String MINECRAFT_VERSION;
public static final BedrockPacketCodec CODEC = Bedrock_v407.V407_CODEC;
public static final int PROTOCOL_VERSION = CODEC.getProtocolVersion();
public static BedrockPacketCodec CODEC;
public static int PROTOCOL_VERSION;
private static final DefaultPrettyPrinter PRETTY_PRINTER = new DefaultPrettyPrinter();

static {
Expand Down Expand Up @@ -87,6 +88,14 @@ public void boot() throws IOException {

configuration = Configuration.load(configPath);

if (configuration.isEducation()) {
CODEC = Bedrock_v363.V363_CODEC;
} else {
CODEC = Bedrock_v407.V407_CODEC;
}

PROTOCOL_VERSION = CODEC.getProtocolVersion();

proxyAddress = configuration.getProxy().getAddress();
targetAddress = configuration.getDestination().getAddress();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,28 @@
import java.net.InetSocketAddress;

@Log4j2
@RequiredArgsConstructor
@ParametersAreNonnullByDefault
public class ProxyBedrockEventHandler implements BedrockServerEventHandler {
private static final BedrockPong ADVERTISEMENT = new BedrockPong();

private final ProxyPass proxy;
private final BedrockPong ADVERTISEMENT = new BedrockPong();

static {
ADVERTISEMENT.setEdition("MCPE");
public ProxyBedrockEventHandler(ProxyPass proxy) {
this.proxy = proxy;

if (proxy.getConfiguration().isEducation()) {
ADVERTISEMENT.setEdition("MCEE");
} else {
ADVERTISEMENT.setEdition("MCPE");
}
ADVERTISEMENT.setGameType("Survival");
ADVERTISEMENT.setVersion(ProxyPass.MINECRAFT_VERSION);
ADVERTISEMENT.setProtocolVersion(ProxyPass.PROTOCOL_VERSION);
ADVERTISEMENT.setMotd("ProxyPass");
ADVERTISEMENT.setPlayerCount(0);
ADVERTISEMENT.setMaximumPlayerCount(20);
ADVERTISEMENT.setSubMotd("https://github.com/NukkitX/ProxyPass");

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.nukkitx.protocol.bedrock.util.EncryptionUtils;
import com.nukkitx.proxypass.ProxyPass;
import com.nukkitx.proxypass.network.bedrock.util.BlockPaletteUtils;
import com.nukkitx.proxypass.network.bedrock.util.ForgeryUtils;
import com.nukkitx.proxypass.network.bedrock.util.RecipeUtils;
import lombok.RequiredArgsConstructor;
import lombok.Value;
Expand Down Expand Up @@ -47,6 +48,17 @@ public boolean handle(ServerToClientHandshakePacket packet) {
SecretKey key = EncryptionUtils.getSecretKey(this.player.getProxyKeyPair().getPrivate(), serverKey,
Base64.getDecoder().decode(saltJwt.getJWTClaimsSet().getStringClaim("salt")));
session.enableEncryption(key);

ServerToClientHandshakePacket p = new ServerToClientHandshakePacket();
p.setJwt(ForgeryUtils.forgeHandshake(
player.getProxyKeyPair(),
saltJwt.getJWTClaimsSet().getStringClaim("signedToken"),
Base64.getDecoder().decode(saltJwt.getJWTClaimsSet().getStringClaim("salt"))).serialize()
);
player.getUpstream().sendPacketImmediately(p);
player.getUpstream().enableEncryption(EncryptionUtils.getSecretKey(player.getProxyKeyPair().getPrivate(),
((UpstreamPacketHandler)player.getUpstream().getPacketHandler()).getRemotePublicKey(),Base64.getDecoder().decode(saltJwt.getJWTClaimsSet().getStringClaim("salt"))));

} catch (ParseException | NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
import com.nukkitx.protocol.bedrock.BedrockClient;
import com.nukkitx.protocol.bedrock.BedrockServerSession;
import com.nukkitx.protocol.bedrock.handler.BedrockPacketHandler;
import com.nukkitx.protocol.bedrock.packet.ClientToServerHandshakePacket;
import com.nukkitx.protocol.bedrock.packet.LoginPacket;
import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket;
import com.nukkitx.protocol.bedrock.util.EncryptionUtils;
import com.nukkitx.proxypass.ProxyPass;
import com.nukkitx.proxypass.network.bedrock.util.ForgeryUtils;
import io.netty.util.AsciiString;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import net.minidev.json.JSONObject;
Expand All @@ -37,6 +39,8 @@ public class UpstreamPacketHandler implements BedrockPacketHandler {
private ArrayNode chainData;
private AuthData authData;
private ProxyPlayerSession player;
@Getter
private ECPublicKey remotePublicKey;

private static boolean validateChainData(JsonNode data) throws Exception {
ECPublicKey lastKey = null;
Expand Down Expand Up @@ -64,6 +68,11 @@ private static boolean verifyJwt(JWSObject jwt, ECPublicKey key) throws JOSEExce
return jwt.verify(new DefaultJWSVerifierFactory().createJWSVerifier(jwt.getHeader(), key));
}

public boolean handle(ClientToServerHandshakePacket packet) {
// This is handled ourselves and we don't want a duplicate packet
return true;
}

@Override
public boolean handle(LoginPacket packet) {
int protocolVersion = packet.getProtocolVersion();
Expand Down Expand Up @@ -112,6 +121,7 @@ public boolean handle(LoginPacket packet) {
throw new RuntimeException("Identity Public Key was not found!");
}
ECPublicKey identityPublicKey = EncryptionUtils.generateKey(payload.get("identityPublicKey").textValue());
this.remotePublicKey = identityPublicKey;

JWSObject clientJwt = JWSObject.parse(packet.getSkinData().toString());
verifyJwt(clientJwt, identityPublicKey);
Expand All @@ -128,7 +138,7 @@ public boolean handle(LoginPacket packet) {
private void initializeProxySession() {
log.debug("Initializing proxy session");
BedrockClient client = proxy.newClient();
client.setRakNetVersion(10);
client.setRakNetVersion(ProxyPass.CODEC.getRaknetProtocolVersion());
client.connect(proxy.getTargetAddress()).whenComplete((downstream, throwable) -> {
if (throwable != null) {
log.error("Unable to connect to downstream server " + proxy.getTargetAddress(), throwable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,32 @@ public static JWSObject forgeSkinData(KeyPair pair, JSONObject skinData) {

return jws;
}

public static SignedJWT forgeHandshake(KeyPair pair, String signedToken, byte[] token) {
String publicKeyBase64 = Base64.getEncoder().encodeToString(pair.getPublic().getEncoded());
URI x5u = URI.create(publicKeyBase64);

JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.ES384).x509CertURL(x5u).build();

long timestamp = System.currentTimeMillis();
Date nbf = new Date(timestamp - TimeUnit.SECONDS.toMillis(1));
Date exp = new Date(timestamp + TimeUnit.DAYS.toMillis(1));

JWTClaimsSet.Builder claimsBuilder = new JWTClaimsSet.Builder()
.claim("salt", Base64.getEncoder().encodeToString(token));

if (signedToken != null) {
claimsBuilder.claim("signedToken", signedToken);
}

SignedJWT jwt = new SignedJWT(header, claimsBuilder.build());

try {
EncryptionUtils.signJwt(jwt, (ECPrivateKey) pair.getPrivate());
} catch (JOSEException e) {
throw new RuntimeException(e);
}

return jwt;
}
}
3 changes: 3 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ log-packets: true
## Valid options: console, file or both
log-to: file

## Minecraft Education Support
education: false

## Packets to ignore to make your log more refined. These default packet are generally spammed
ignored-packets:
- "NetworkStackLatencyPacket"
Expand Down

0 comments on commit a91c842

Please sign in to comment.