Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code cleanup and fixes #14

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/main/java/me/THEREALWWEFAN231/tunnelmc/TunnelMC.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import me.THEREALWWEFAN231.tunnelmc.translator.EntityTranslator;
import me.THEREALWWEFAN231.tunnelmc.translator.PacketTranslatorManager;
import me.THEREALWWEFAN231.tunnelmc.translator.blockentity.BlockEntityRegistry;
import me.THEREALWWEFAN231.tunnelmc.translator.blockentity.BlockEntityTranslator;
import me.THEREALWWEFAN231.tunnelmc.translator.blockstate.BlockStateTranslator;
import me.THEREALWWEFAN231.tunnelmc.translator.container.screenhandler.ScreenHandlerTranslatorManager;
import me.THEREALWWEFAN231.tunnelmc.translator.enchantment.EnchantmentTranslator;
Expand Down
72 changes: 32 additions & 40 deletions src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/Auth.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

import me.THEREALWWEFAN231.tunnelmc.TunnelMC;

//based off https://github.com/Sandertv/gophertunnel/tree/master/minecraft/auth
/**
* Referenced from the resource below:
* https://github.com/Sandertv/gophertunnel/tree/master/minecraft/auth
*/
public class Auth {

private ECPublicKey publicKey;
Expand All @@ -30,34 +33,28 @@ public class Auth {
private String displayName;

public String getOnlineChainData() throws Exception {
Gson gson = TunnelMC.instance.fileManagement.normalGson;
Gson gson = TunnelMC.instance.fileManagement.gJson;

KeyPair ecdsa256KeyPair = Auth.createKeyPair();//for xbox live, xbox live requests use, ES256, ECDSA256
KeyPair ecdsa256KeyPair = Auth.createKeyPair();
this.publicKey = (ECPublicKey) ecdsa256KeyPair.getPublic();
this.privateKey = (ECPrivateKey) ecdsa256KeyPair.getPrivate();

Xbox xbox = new Xbox(System.getProperty("XboxAccessToken"));
Xbox xbox = new Xbox(System.getenv("XBOX_ACCESS_TOKEN"));
String userToken = xbox.getUserToken(this.publicKey, this.privateKey);
String deviceToken = xbox.getDeviceToken(this.publicKey, this.privateKey);
String titleToken = xbox.getTitleToken(this.publicKey, this.privateKey, deviceToken);
String xsts = xbox.getXstsToken(userToken, deviceToken, titleToken, this.publicKey, this.privateKey);

KeyPair ecdsa384KeyPair = EncryptionUtils.createKeyPair();//use ES384, ECDSA384
KeyPair ecdsa384KeyPair = EncryptionUtils.createKeyPair();
this.publicKey = (ECPublicKey) ecdsa384KeyPair.getPublic();
this.privateKey = (ECPrivateKey) ecdsa384KeyPair.getPrivate();

/*
* So we get a "chain"(json array with info(that has 2 objects)) from minecraft.net using our xsts token
* from there we have to add our own chain at the beginning of the chain(json array that minecraft.net sent us),
* When is all said and done, we have 3 chains(they are jwt objects, header.payload.signature)
* which we send to the server to check
*/
String chainData = xbox.requestMinecraftChain(xsts, this.publicKey);
JsonObject chainDataObject = TunnelMC.instance.fileManagement.jsonParser.parse(chainData).getAsJsonObject();
JsonArray minecraftNetChain = chainDataObject.get("chain").getAsJsonArray();
String firstChainHeader = minecraftNetChain.get(0).getAsString();
firstChainHeader = firstChainHeader.split("\\.")[0];//get the jwt header(base64)
firstChainHeader = new String(Base64.getDecoder().decode(firstChainHeader.getBytes()));//decode the jwt base64 header
firstChainHeader = firstChainHeader.split("\\.")[0];
firstChainHeader = new String(Base64.getDecoder().decode(firstChainHeader.getBytes()));
String firstKeyx5u = TunnelMC.instance.fileManagement.jsonParser.parse(firstChainHeader).getAsJsonObject().get("x5u").getAsString();

JsonObject newFirstChain = new JsonObject();
Expand All @@ -66,35 +63,30 @@ public String getOnlineChainData() throws Exception {
newFirstChain.addProperty("identityPublicKey", firstKeyx5u);
newFirstChain.addProperty("nbf", Instant.now().getEpochSecond() - TimeUnit.HOURS.toSeconds(6));

{
String publicKeyBase64 = Base64.getEncoder().encodeToString(this.publicKey.getEncoded());
JsonObject jwtHeader = new JsonObject();
jwtHeader.addProperty("alg", "ES384");
jwtHeader.addProperty("x5u", publicKeyBase64);
String publicKeyBase64 = Base64.getEncoder().encodeToString(this.publicKey.getEncoded());
JsonObject jwtHeader = new JsonObject();
jwtHeader.addProperty("alg", "ES384");
jwtHeader.addProperty("x5u", publicKeyBase64);

String header = Base64.getUrlEncoder().withoutPadding().encodeToString(gson.toJson(jwtHeader).getBytes());
String payload = Base64.getUrlEncoder().withoutPadding().encodeToString(gson.toJson(newFirstChain).getBytes());

String header = Base64.getUrlEncoder().withoutPadding().encodeToString(gson.toJson(jwtHeader).getBytes());
String payload = Base64.getUrlEncoder().withoutPadding().encodeToString(gson.toJson(newFirstChain).getBytes());
byte[] dataToSign = (header + "." + payload).getBytes();
String signatureString = this.signBytes(dataToSign);

byte[] dataToSign = (header + "." + payload).getBytes();
String signatureString = this.signBytes(dataToSign);
String jwt = header + "." + payload + "." + signatureString;

String jwt = header + "." + payload + "." + signatureString;
chainDataObject.add("chain", this.addChainToBeginning(jwt, minecraftNetChain));

chainDataObject.add("chain", this.addChainToBeginning(jwt, minecraftNetChain));//replace the chain with our new chain
}
String lastChain = minecraftNetChain.get(minecraftNetChain.size() - 1).getAsString();
String lastChainPayload = lastChain.split("\\.")[1];
lastChainPayload = new String(Base64.getDecoder().decode(lastChainPayload.getBytes()));

{
//we are now going to get some data from a chain minecraft sent us(the last chain)
String lastChain = minecraftNetChain.get(minecraftNetChain.size() - 1).getAsString();
String lastChainPayload = lastChain.split("\\.")[1];//get the middle(payload) jwt thing
lastChainPayload = new String(Base64.getDecoder().decode(lastChainPayload.getBytes()));//decode the base64

JsonObject payloadObject = TunnelMC.instance.fileManagement.jsonParser.parse(lastChainPayload).getAsJsonObject();
JsonObject extraData = payloadObject.get("extraData").getAsJsonObject();
this.xuid = extraData.get("XUID").getAsString();
this.identity = UUID.fromString(extraData.get("identity").getAsString());
this.displayName = extraData.get("displayName").getAsString();
}
JsonObject payloadObject = TunnelMC.instance.fileManagement.jsonParser.parse(lastChainPayload).getAsJsonObject();
JsonObject extraData = payloadObject.get("extraData").getAsJsonObject();
this.xuid = extraData.get("XUID").getAsString();
this.identity = UUID.fromString(extraData.get("identity").getAsString());
this.displayName = extraData.get("displayName").getAsString();

return gson.toJson(chainDataObject);
}
Expand All @@ -105,7 +97,7 @@ public String getOfflineChainData(String username) throws Exception {
UUID offlineUUID = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
String xuid = Long.toString(offlineUUID.getLeastSignificantBits());

Gson gson = TunnelMC.instance.fileManagement.normalGson;
Gson gson = TunnelMC.instance.fileManagement.gJson;
//KeyPair ecdsa256KeyPair = Auth.createKeyPair();//for xbox live, xbox live requests use, ES256, ECDSA256
KeyPair ecdsa256KeyPair = EncryptionUtils.createKeyPair();
this.publicKey = (ECPublicKey) ecdsa256KeyPair.getPublic();
Expand Down Expand Up @@ -197,7 +189,7 @@ public String getDisplayName() {
static {
try {
KEY_PAIR_GEN = KeyPairGenerator.getInstance("EC");
KEY_PAIR_GEN.initialize(new ECGenParameterSpec("secp256r1"));//use P-256
KEY_PAIR_GEN.initialize(new ECGenParameterSpec("secp256r1"));
} catch (Exception e) {
throw new AssertionError("Unable to initialize required encryption", e);
}
Expand Down

Large diffs are not rendered by default.

28 changes: 13 additions & 15 deletions src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/Xbox.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,20 @@
import me.THEREALWWEFAN231.tunnelmc.TunnelMC;
import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client;

/*
* This note refers to all auth/JWT related classes, I know there are JWT parsing dependencies(already built into the protocol
* dependence) but I want to to be "up front", meaning I/we see everything that is going on, meaning we can see exactly how
* the header, payload and signature are formed, rather then using some library that make take a couple minutes to understand(how
* it works), I also do know, at some points it would be easier to use the JWT dependence but my stance above still applies,
* maybe ill make my own simple class :shrug:
/**
* Referenced from the resource below:
* https://github.com/Sandertv/gophertunnel/tree/master/minecraft/auth
*/
//based off https://github.com/Sandertv/gophertunnel/tree/master/minecraft/auth
public class Xbox {

//go here, log in, and in the redirected url you will have your access token, https://login.live.com/oauth20_authorize.srf?client_id=00000000441cc96b&redirect_uri=https://login.live.com/oauth20_desktop.srf&response_type=token&display=touch&scope=service::user.auth.xboxlive.com::MBI_SSL&locale=en
//then add -DXboxAccessToken=YOURS to your jvm arguments
/**
* To generate your own access token (for now), login at the following link:
* https://login.live.com/oauth20_authorize.srf?client_id=00000000441cc96b&redirect_uri=https://login.live.com/oauth20_desktop.srf&response_type=token&display=touch&scope=service::user.auth.xboxlive.com::MBI_SSL&locale=en
* When you're redirected to the blank page, check the URL parameters. Look for the one that says access token, and then set
* the "XBOX_ACCESS_TOKEN" environment variable to your access token.
*
* This will be changed and simplified later on.
*/
private final String accessToken;

private static final String xboxUserAuthURL = "https://user.auth.xboxlive.com/user/authenticate";
Expand All @@ -48,7 +50,6 @@ public Xbox(String accessToken) {
}

public String getUserToken(ECPublicKey publicKey, ECPrivateKey privateKey) throws Exception {

JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("RelyingParty", "http://auth.xboxlive.com");
jsonObject.addProperty("TokenType", "JWT");
Expand Down Expand Up @@ -85,7 +86,6 @@ public String getUserToken(ECPublicKey publicKey, ECPrivateKey privateKey) throw
}

public String getDeviceToken(ECPublicKey publicKey, ECPrivateKey privateKey) throws Exception {

JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("RelyingParty", "http://auth.xboxlive.com");
jsonObject.addProperty("TokenType", "JWT");
Expand Down Expand Up @@ -124,7 +124,6 @@ public String getDeviceToken(ECPublicKey publicKey, ECPrivateKey privateKey) thr
}

public String getTitleToken(ECPublicKey publicKey, ECPrivateKey privateKey, String deviceToken) throws Exception {

JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("RelyingParty", "http://auth.xboxlive.com");
jsonObject.addProperty("TokenType", "JWT");
Expand Down Expand Up @@ -162,7 +161,6 @@ public String getTitleToken(ECPublicKey publicKey, ECPrivateKey privateKey, Stri
}

public String getXstsToken(String userToken, String deviceToken, String titleToken, ECPublicKey publicKey, ECPrivateKey privateKey) throws Exception {

JsonObject jsonObject = new JsonObject();

jsonObject.addProperty("RelyingParty", "https://multiplayer.minecraft.net/");
Expand Down Expand Up @@ -227,7 +225,7 @@ private void writeJsonObjectToPost(HttpsURLConnection connection, JsonObject jso
connection.setDoOutput(true);

DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
dataOutputStream.writeBytes(TunnelMC.instance.fileManagement.normalGson.toJson(jsonObject));
dataOutputStream.writeBytes(TunnelMC.instance.fileManagement.gJson.toJson(jsonObject));
dataOutputStream.flush();
}

Expand Down Expand Up @@ -261,7 +259,7 @@ private void addSignatureHeader(HttpsURLConnection httpsURLConnection, JsonObjec
}
bytesToSign.write(authorization.getBytes());
bytesToSign.write(new byte[] { 0 });
bytesToSign.write(TunnelMC.instance.fileManagement.normalGson.toJson(postData).getBytes());
bytesToSign.write(TunnelMC.instance.fileManagement.gJson.toJson(postData).getBytes());
bytesToSign.write(new byte[] { 0 });

Signature signature = Signature.getInstance("SHA256withECDSA");
Expand Down
Loading