From c6bdceffc3c3db601ed3451f215108432c832547 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Sun, 13 Apr 2025 06:01:46 +0200 Subject: [PATCH] Encrypted authentication --- .../saturnclient/SaturnClient.java | 4 +- .../auth/{SaturnSocket.java => Auth.java} | 66 +++++-------- .../saturnclient/auth/Network.java | 99 +++++++++++++++++++ .../saturnclient/auth/PlayerTracker.java | 4 +- .../cosmetics/CloakFeatureRenderer.java | 9 +- .../cosmetics/HatFeatureRenderer.java | 6 +- .../saturnclient/cosmetics/Hats.java | 10 +- .../saturnclient/cosmetics/cloaks/Cloaks.java | 14 +-- .../saturnclient/menus/CloaksMenu.java | 4 +- .../saturnclient/menus/HatsMenu.java | 4 +- .../saturnclient/mixin/NameTagMixin.java | 9 +- .../saturnclient/mixin/SaturnReload.java | 6 +- .../saturnclient/mixin/TabListMixin.java | 4 +- 13 files changed, 159 insertions(+), 80 deletions(-) rename src/main/java/org/saturnclient/saturnclient/auth/{SaturnSocket.java => Auth.java} (77%) create mode 100644 src/main/java/org/saturnclient/saturnclient/auth/Network.java diff --git a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java index 8758a62..273ff05 100644 --- a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java +++ b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java @@ -5,7 +5,7 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.minecraft.client.gui.screen.TitleScreen; -import org.saturnclient.saturnclient.auth.SaturnSocket; +import org.saturnclient.saturnclient.auth.Auth; import org.saturnclient.saturnclient.config.ConfigManager; import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; @@ -45,7 +45,7 @@ public class SaturnClient implements ModInitializer { }); KeyInputHandler.register(); - if (SaturnSocket.authenticate()) { + if (Auth.authenticate()) { Cloaks.initialize(); Hats.initialize(); LOGGER.info(MOD_ID + " initialization complete"); diff --git a/src/main/java/org/saturnclient/saturnclient/auth/SaturnSocket.java b/src/main/java/org/saturnclient/saturnclient/auth/Auth.java similarity index 77% rename from src/main/java/org/saturnclient/saturnclient/auth/SaturnSocket.java rename to src/main/java/org/saturnclient/saturnclient/auth/Auth.java index 85d1a21..eadd851 100644 --- a/src/main/java/org/saturnclient/saturnclient/auth/SaturnSocket.java +++ b/src/main/java/org/saturnclient/saturnclient/auth/Auth.java @@ -1,7 +1,5 @@ package org.saturnclient.saturnclient.auth; -import java.io.*; -import java.net.Socket; import java.util.HashMap; import java.util.Map; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; @@ -10,18 +8,10 @@ import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import org.saturnclient.saturnclient.SaturnClient; -public class SaturnSocket { - - private static final String server = "77.247.92.168"; - private static final int port = 8080; - +public class Auth { public static Map players = new HashMap<>(); public static Map playerNames = new HashMap<>(); public static String uuid; - - private static Socket socket; - private static BufferedReader reader; - private static PrintWriter writer; private static Thread listenerThread; private static Thread pingThread; private static volatile boolean running = false; @@ -41,15 +31,11 @@ public class SaturnSocket { String accessToken = client.getSession().getAccessToken(); SaturnClient.LOGGER.info("Authenticating"); - // Establish a persistent connection - socket = new Socket(server, port); - reader = new BufferedReader( - new InputStreamReader(socket.getInputStream())); - writer = new PrintWriter(socket.getOutputStream(), true); + Network.init(); - // Send authentication request - writer.println(accessToken); - String response = reader.readLine(); + Network.write(accessToken); + + String response = Network.read(); SaturnParser parser = new SaturnParser(response); @@ -75,7 +61,7 @@ public class SaturnSocket { startPingThread(); return true; - } catch (IOException e) { + } catch (Exception e) { SaturnClient.LOGGER.error("Authentication failed", e); return false; } @@ -86,7 +72,7 @@ public class SaturnSocket { listenerThread = new Thread(() -> { try { while (running) { - String message = reader.readLine(); + String message = Network.read(); if (message == null) { SaturnClient.LOGGER.error("Connection closed"); running = false; @@ -117,7 +103,7 @@ public class SaturnSocket { break; } } - } catch (IOException e) { + } catch (Exception e) { SaturnClient.LOGGER.error("Error reading from server", e); } finally { close(); @@ -133,12 +119,12 @@ public class SaturnSocket { try { while (running) { Thread.sleep(25000); // 25 seconds - if (running && writer != null) { - writer.println("ping"); + if (running) { + Network.write("ping"); } } } catch (InterruptedException e) { - SaturnClient.LOGGER.error("Ping thread interrupted", e); + SaturnClient.LOGGER.warn("Ping thread interrupted", e); } catch (Exception e) { SaturnClient.LOGGER.error("Error in ping thread", e); } @@ -150,24 +136,16 @@ public class SaturnSocket { public static void close() { running = false; + if (pingThread != null) { + pingThread.interrupt(); + } + if (listenerThread != null) { + listenerThread.interrupt(); + } try { - if (pingThread != null) { - pingThread.interrupt(); - } - if (listenerThread != null) { - listenerThread.interrupt(); - } - if (writer != null) { - writer.close(); - } - if (reader != null) { - reader.close(); - } - if (socket != null) { - socket.close(); - } + close(); SaturnClient.LOGGER.info("SaturnApi connection closed."); - } catch (IOException e) { + } catch (Exception e) { SaturnClient.LOGGER.error("Failed to close resources", e); } } @@ -178,7 +156,7 @@ public class SaturnSocket { public static void setCloak(String cloakName) { try { - writer.println("set_cloak@cloak=" + cloakName); + Network.write("set_cloak@cloak=" + cloakName); } catch (Exception e) { SaturnClient.LOGGER.error("Request failed", e); } @@ -186,7 +164,7 @@ public class SaturnSocket { public static void setHat(String hatName) { try { - writer.println("set_hat@hat=" + hatName); + Network.write("set_hat@hat=" + hatName); } catch (Exception e) { SaturnClient.LOGGER.error("Request failed", e); } @@ -195,7 +173,7 @@ public class SaturnSocket { public static void player(String name, String uuid) { try { playerNames.put(name, uuid.replaceAll("-", "")); - writer.println("player@uuid=" + uuid.replaceAll("-", "")); + Network.write("player@uuid=" + uuid.replaceAll("-", "")); } catch (Exception e) { SaturnClient.LOGGER.error("Request failed", e); } diff --git a/src/main/java/org/saturnclient/saturnclient/auth/Network.java b/src/main/java/org/saturnclient/saturnclient/auth/Network.java new file mode 100644 index 0000000..33cc245 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/auth/Network.java @@ -0,0 +1,99 @@ +package org.saturnclient.saturnclient.auth; + +import java.io.*; +import java.net.*; +import java.security.*; +import java.util.Base64; +import javax.crypto.*; +import javax.crypto.spec.*; +import java.security.interfaces.*; +import java.security.spec.X509EncodedKeySpec; + +public class Network { + static Socket socket; + static DataOutputStream out; + static BufferedReader in; + static byte[] key = new byte[32]; + + public static class AES { + public static byte[] encryptAES256(String message, byte[] key) throws Exception { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); + byte[] encryptedMessage = cipher.doFinal(message.getBytes()); + return encryptedMessage; + } + + public static String decryptAES256(byte[] encryptedMessage, byte[] key) throws Exception { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); + byte[] decryptedMessage = cipher.doFinal(encryptedMessage); + return new String(decryptedMessage); + } + } + + public static void init() throws Exception { + // Generate AES key + new SecureRandom().nextBytes(key); + + socket = new Socket("localhost", 8080); + out = new DataOutputStream(socket.getOutputStream()); + in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + StringBuilder publicKeyBuilder = new StringBuilder(); + String line; + while (!(line = in.readLine()).contains("-----END PUBLIC KEY-----")) { + publicKeyBuilder.append(line).append("\n"); + } + publicKeyBuilder.append(line); + + String publicKeyPem = publicKeyBuilder.toString(); + + String publicKeyBase64 = publicKeyPem.replace("-----BEGIN PUBLIC KEY-----", "") + .replace("-----END PUBLIC KEY-----", "").replace("\n", "").replace("\r", ""); + byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyBase64); + + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); + + Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey); + byte[] encryptedKey = rsaCipher.doFinal(key); + + out.write(Base64.getEncoder().encode(encryptedKey)); + out.write('\n'); + } + + public static void write(String message) { + try { + out.write(Base64.getEncoder().encode(AES.encryptAES256(message, key))); + out.write('\n'); + out.flush(); + } catch (Exception e) { + } + } + + public static String read() { + try { + String msg = in.readLine(); + if (msg != null) { + return AES.decryptAES256(Base64.getDecoder().decode(msg), key); + } else { + return ""; + } + } catch (Exception e) { + return ""; + } + } + + public static void close() { + try { + socket.close(); + out.close(); + in.close(); + } catch (Exception e) { + } + } +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/saturnclient/auth/PlayerTracker.java b/src/main/java/org/saturnclient/saturnclient/auth/PlayerTracker.java index 52baafc..043425a 100644 --- a/src/main/java/org/saturnclient/saturnclient/auth/PlayerTracker.java +++ b/src/main/java/org/saturnclient/saturnclient/auth/PlayerTracker.java @@ -45,7 +45,7 @@ public class PlayerTracker { private static void onPlayerJoin(MinecraftClient client, PlayerListEntry player) { GameProfile profile = player.getProfile(); String uuid = profile.getId().toString(); - if (uuid != SaturnSocket.uuid) - SaturnSocket.player(profile.getName(), uuid); + if (uuid != Auth.uuid) + Auth.player(profile.getName(), uuid); } } diff --git a/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java b/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java index e59915c..93f5105 100644 --- a/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java +++ b/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java @@ -1,6 +1,6 @@ package org.saturnclient.saturnclient.cosmetics; -import org.saturnclient.saturnclient.auth.SaturnSocket; +import org.saturnclient.saturnclient.auth.Auth; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import net.minecraft.client.render.OverlayTexture; @@ -57,14 +57,15 @@ public class CloakFeatureRenderer extends FeatureRenderer availableHats = new ArrayList<>(); @@ -14,14 +14,14 @@ public class Hats { public static void setHat(String uuid, String hatName) { setHatSilent(uuid, hatName); - SaturnSocket.setHat(hatName); - SaturnSocket.sendReload(); + Auth.setHat(hatName); + Auth.sendReload(); } public static void setHatSilent(String uuid, String hatName) { - SaturnPlayer player = SaturnSocket.players.get(uuid); + SaturnPlayer player = Auth.players.get(uuid); if (player == null) { - SaturnSocket.players.put(uuid, new SaturnPlayer("", hatName)); + Auth.players.put(uuid, new SaturnPlayer("", hatName)); } else { player.hat = hatName; } diff --git a/src/main/java/org/saturnclient/saturnclient/cosmetics/cloaks/Cloaks.java b/src/main/java/org/saturnclient/saturnclient/cosmetics/cloaks/Cloaks.java index c06e7c0..0c3b791 100644 --- a/src/main/java/org/saturnclient/saturnclient/cosmetics/cloaks/Cloaks.java +++ b/src/main/java/org/saturnclient/saturnclient/cosmetics/cloaks/Cloaks.java @@ -1,7 +1,7 @@ package org.saturnclient.saturnclient.cosmetics.cloaks; import net.minecraft.util.Identifier; -import org.saturnclient.saturnclient.auth.SaturnSocket; +import org.saturnclient.saturnclient.auth.Auth; import org.saturnclient.saturnclient.cosmetics.cloaks.utils.AnimatedCloakData; import org.saturnclient.saturnclient.cosmetics.cloaks.utils.IdentifierUtils; import org.saturnclient.saturnclient.auth.SaturnPlayer; @@ -42,9 +42,9 @@ public class Cloaks { * @param cloakName Name of the cloak file to load */ public static void setCloak(String uuid, String cloakName) { - SaturnSocket.setCloak(cloakName); + Auth.setCloak(cloakName); setCloakSilent(uuid, cloakName); - SaturnSocket.sendReload(); + Auth.sendReload(); SaturnClient.LOGGER.info("Cloak set to " + cloakName); } @@ -55,9 +55,9 @@ public class Cloaks { * @param cloakName Name of the cloak file to load */ public static void setCloakSilent(String uuid, String cloakName) { - SaturnPlayer player = SaturnSocket.players.get(uuid); + SaturnPlayer player = Auth.players.get(uuid); if (player == null) { - SaturnSocket.players.put(uuid, new SaturnPlayer(cloakName, null)); + Auth.players.put(uuid, new SaturnPlayer(cloakName, null)); } else { player.cloak = cloakName; } @@ -137,11 +137,11 @@ public class Cloaks { } public static Identifier getCurrentCloakTexture(String uuid) { - if (!SaturnSocket.players.containsKey(uuid)) { + if (!Auth.players.containsKey(uuid)) { return null; } - String cloakName = SaturnSocket.players.get(uuid).cloak; + String cloakName = Auth.players.get(uuid).cloak; if (cloakName.isEmpty()) { return null; diff --git a/src/main/java/org/saturnclient/saturnclient/menus/CloaksMenu.java b/src/main/java/org/saturnclient/saturnclient/menus/CloaksMenu.java index 64d7b1d..b6111db 100644 --- a/src/main/java/org/saturnclient/saturnclient/menus/CloaksMenu.java +++ b/src/main/java/org/saturnclient/saturnclient/menus/CloaksMenu.java @@ -2,7 +2,7 @@ package org.saturnclient.saturnclient.menus; import net.minecraft.text.Text; import org.saturnclient.saturnclient.SaturnClientConfig; -import org.saturnclient.saturnclient.auth.SaturnSocket; +import org.saturnclient.saturnclient.auth.Auth; import org.saturnclient.saturnclient.config.Property; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import org.saturnclient.ui.SaturnUi; @@ -123,7 +123,7 @@ public class CloaksMenu extends SaturnUi { scroll.draw( new SaturnClickableSprite(Textures.BUTTON_BORDER, () -> { - Cloaks.setCloak(SaturnSocket.uuid, cloak); + Cloaks.setCloak(Auth.uuid, cloak); }) .setX(modX) .setY(modY) diff --git a/src/main/java/org/saturnclient/saturnclient/menus/HatsMenu.java b/src/main/java/org/saturnclient/saturnclient/menus/HatsMenu.java index 7df0dc2..6065b14 100644 --- a/src/main/java/org/saturnclient/saturnclient/menus/HatsMenu.java +++ b/src/main/java/org/saturnclient/saturnclient/menus/HatsMenu.java @@ -2,7 +2,7 @@ package org.saturnclient.saturnclient.menus; import net.minecraft.text.Text; import org.saturnclient.saturnclient.SaturnClientConfig; -import org.saturnclient.saturnclient.auth.SaturnSocket; +import org.saturnclient.saturnclient.auth.Auth; import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.ui.SaturnUi; import org.saturnclient.ui.Textures; @@ -88,7 +88,7 @@ public class HatsMenu extends SaturnUi { for (String hat : Hats.availableHats) { modsScroll.draw( new SaturnClickableSprite(Textures.BUTTON_BORDER, () -> { - Hats.setHat(SaturnSocket.uuid, hat); + Hats.setHat(Auth.uuid, hat); }) .setX(modX) .setY(modY) diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java index 041fee7..b25f4f4 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java @@ -14,7 +14,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.client.render.LightmapTextureManager; import org.saturnclient.saturnclient.SaturnClientConfig; -import org.saturnclient.saturnclient.auth.SaturnSocket; +import org.saturnclient.saturnclient.auth.Auth; import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -33,7 +33,8 @@ public abstract class NameTagMixin { @Overwrite public void renderLabelIfPresent(S state, Text text_o, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) { - Text text = isSaturn(state) ? Text.literal(SaturnClientConfig.getSaturnIndicator() + text_o.getString()) : text_o; + Text text = isSaturn(state) ? Text.literal(SaturnClientConfig.getSaturnIndicator() + text_o.getString()) + : text_o; Vec3d vec3d = state.nameLabelPos; if (vec3d != null) { @@ -61,8 +62,8 @@ public abstract class NameTagMixin { private boolean isSaturn(S state) { if (state instanceof PlayerEntityRenderState) { String name = ((PlayerEntityRenderState) state).name; - String uuid = SaturnSocket.playerNames.get(name); - return uuid != null && SaturnSocket.players.containsKey(uuid); + String uuid = Auth.playerNames.get(name); + return uuid != null && Auth.players.containsKey(uuid); } return false; } diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/SaturnReload.java b/src/main/java/org/saturnclient/saturnclient/mixin/SaturnReload.java index e6f2356..8242371 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/SaturnReload.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/SaturnReload.java @@ -3,7 +3,7 @@ package org.saturnclient.saturnclient.mixin; import java.util.Map; import org.jetbrains.annotations.Nullable; -import org.saturnclient.saturnclient.auth.SaturnSocket; +import org.saturnclient.saturnclient.auth.Auth; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -21,10 +21,10 @@ public class SaturnReload { @Nullable MessageIndicator indicator, CallbackInfo ci) { String msg = message.toString(); if (msg.contains("$SATURN_RELOAD")) { - for (Map.Entry player : SaturnSocket.playerNames.entrySet()) { + for (Map.Entry player : Auth.playerNames.entrySet()) { String name = player.getKey(); if (msg.contains(name)) { - SaturnSocket.player(name, player.getValue()); + Auth.player(name, player.getValue()); } ci.cancel(); } diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java index ebab482..1eadb68 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java @@ -4,7 +4,7 @@ import net.minecraft.client.network.PlayerListEntry; import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; import org.saturnclient.saturnclient.SaturnClientConfig; -import org.saturnclient.saturnclient.auth.SaturnSocket; +import org.saturnclient.saturnclient.auth.Auth; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -30,6 +30,6 @@ public abstract class TabListMixin { String uuid = profile.getId().toString().replaceAll("-", ""); return Text.literal( - SaturnSocket.players.containsKey(uuid) ? SaturnClientConfig.getSaturnIndicator() + name : name); + Auth.players.containsKey(uuid) ? SaturnClientConfig.getSaturnIndicator() + name : name); } }