diff --git a/common/pom.xml b/common/pom.xml
index 6a0a6ff04..d54730ff0 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -10,6 +10,12 @@
common
+
+ org.projectlombok
+ lombok
+ 1.18.4
+ providec
+
com.github.steveice10
opennbt
diff --git a/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java b/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java
new file mode 100644
index 000000000..f4efa9716
--- /dev/null
+++ b/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java
@@ -0,0 +1,35 @@
+package org.geysermc.floodgate.util;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public class BedrockData {
+ public static final int EXPECTED_LENGTH = 6;
+ private String version;
+ private String username;
+ private String xuid;
+ private int deviceId;
+ private String languageCode;
+ private int inputMode;
+ private int dataLength;
+
+ public BedrockData(String version, String username, String xuid, int deviceId, String languageCode, int inputMode) {
+ this(version, username, xuid, deviceId, languageCode, inputMode, EXPECTED_LENGTH);
+ }
+
+ public static BedrockData fromString(String data) {
+ String[] split = data.split("\0");
+ if (split.length != EXPECTED_LENGTH) return null;
+ return new BedrockData(split[0], split[1], split[2], Integer.parseInt(split[3]), split[4], Integer.parseInt(split[5]), split.length);
+ }
+
+ public static BedrockData fromRawData(byte[] data) {
+ return fromString(new String(data));
+ }
+
+ public String toString() {
+ return version +'\0'+ username +'\0'+ xuid +'\0'+ deviceId +'\0'+ languageCode +'\0'+ inputMode;
+ }
+}
diff --git a/common/src/main/java/org/geysermc/floodgate/util/EncryptionUtil.java b/common/src/main/java/org/geysermc/floodgate/util/EncryptionUtil.java
new file mode 100644
index 000000000..881d01ba9
--- /dev/null
+++ b/common/src/main/java/org/geysermc/floodgate/util/EncryptionUtil.java
@@ -0,0 +1,76 @@
+package org.geysermc.floodgate.util;
+
+import javax.crypto.*;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.*;
+import java.security.spec.EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+
+public class EncryptionUtil {
+ public static String encrypt(Key key, String data) throws IllegalBlockSizeException,
+ InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
+ KeyGenerator generator = KeyGenerator.getInstance("AES");
+ generator.init(128);
+ SecretKey secretKey = generator.generateKey();
+
+ Cipher cipher = Cipher.getInstance("AES");
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+ byte[] encryptedText = cipher.doFinal(data.getBytes());
+
+ cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ cipher.init(key instanceof PublicKey ? Cipher.PUBLIC_KEY : Cipher.PRIVATE_KEY, key);
+ return Base64.getEncoder().encodeToString(cipher.doFinal(secretKey.getEncoded())) + '\0' +
+ Base64.getEncoder().encodeToString(encryptedText);
+ }
+
+ public static String encryptBedrockData(Key key, BedrockData data) throws IllegalBlockSizeException,
+ InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
+ return encrypt(key, data.toString());
+ }
+
+ public static byte[] decrypt(Key key, String encryptedData) throws IllegalBlockSizeException,
+ InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
+ String[] split = encryptedData.split("\0");
+ if (split.length != 2) {
+ throw new IllegalArgumentException("Expected two arguments, got " + split.length);
+ }
+
+ Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ cipher.init(key instanceof PublicKey ? Cipher.PUBLIC_KEY : Cipher.PRIVATE_KEY, key);
+ byte[] decryptedKey = cipher.doFinal(Base64.getDecoder().decode(split[0]));
+
+ SecretKey secretKey = new SecretKeySpec(decryptedKey, 0, decryptedKey.length, "AES");
+ cipher = Cipher.getInstance("AES");
+ cipher.init(Cipher.DECRYPT_MODE, secretKey);
+ return cipher.doFinal(Base64.getDecoder().decode(split[1]));
+ }
+
+ public static BedrockData decryptBedrockData(Key key, String encryptedData) throws IllegalBlockSizeException,
+ InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
+ return BedrockData.fromRawData(decrypt(key, encryptedData));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T getKeyFromFile(Path fileLocation, Class keyType) throws
+ IOException, InvalidKeySpecException, NoSuchAlgorithmException {
+ boolean isPublicKey = keyType == PublicKey.class;
+ if (!isPublicKey && keyType != PrivateKey.class) {
+ throw new RuntimeException("I can only read public and private keys!");
+ }
+
+ byte[] key = Files.readAllBytes(fileLocation);
+
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ EncodedKeySpec keySpec = isPublicKey ? new X509EncodedKeySpec(key) : new PKCS8EncodedKeySpec(key);
+ return (T) (isPublicKey ?
+ keyFactory.generatePublic(keySpec) :
+ keyFactory.generatePrivate(keySpec)
+ );
+ }
+}
diff --git a/connector/pom.xml b/connector/pom.xml
index 5b4a2bcf5..60ecfc557 100644
--- a/connector/pom.xml
+++ b/connector/pom.xml
@@ -22,12 +22,6 @@
1.0-SNAPSHOT
compile
-
- org.geysermc
- floodgate-common
- 1.0-SNAPSHOT
- compile
-
com.fasterxml.jackson.dataformat
jackson-dataformat-yaml