mirror of
https://github.com/TuxCoding/FastLogin.git
synced 2026-07-06 16:40:47 +02:00
dfbfe9c4e5227fc7924437b4e2ad559eb08b8951
156 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2fa6700666 |
Merge pull request #1004 from games647/dependabot/maven/me.clip-placeholderapi-2.11.3
Bump placeholderapi from 2.11.2 to 2.11.3 |
||
|
|
d6389f0474 |
Bump loginsecurity from 3.1 to 3.1.1
Bumps loginsecurity from 3.1 to 3.1.1. --- updated-dependencies: - dependency-name: com.lenis0012.bukkit:loginsecurity dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
d153b5e2d5 |
Bump placeholderapi from 2.11.2 to 2.11.3
Bumps placeholderapi from 2.11.2 to 2.11.3. --- updated-dependencies: - dependency-name: me.clip:placeholderapi dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
e7208e6a5d |
Merge pull request #971 from games647/dependabot/maven/io.papermc-paperlib-1.0.8
Bump paperlib from 1.0.7 to 1.0.8 |
||
|
|
0adadd02a1 | Find the correct floodgate version | ||
|
|
f706f428a3 |
Bump paperlib from 1.0.7 to 1.0.8
Bumps [paperlib](https://github.com/PaperMC/PaperLib) from 1.0.7 to 1.0.8. - [Release notes](https://github.com/PaperMC/PaperLib/releases) - [Changelog](https://github.com/PaperMC/PaperLib/blob/master/CHANGELOG.md) - [Commits](https://github.com/PaperMC/PaperLib/compare/v1.0.7...v1.0.8) --- updated-dependencies: - dependency-name: io.papermc:paperlib dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
c63712a949 |
Bump maven-shade-plugin from 3.3.0 to 3.4.1
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.3.0 to 3.4.1. - [Release notes](https://github.com/apache/maven-shade-plugin/releases) - [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.3.0...maven-shade-plugin-3.4.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-shade-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
b242a7b3ce | Update dependencies | ||
|
|
ca17c3f377 | Fix project building | ||
|
|
5a29eede69 | Bump Geyser version to 2.1.0-SNAPSHOT | ||
|
|
520bb0d761 | Reformat work and build files | ||
|
|
55e3531718 | Extract channel from ProtocolLib event | ||
|
|
e3778c865c | Update dependencies | ||
|
|
1e732d62cb | Replace Field- and MethodUtils from breaking changes in ProtocolLib | ||
|
|
564f713fce | Simplify version setting | ||
|
|
05708a256c | Perform check for available reflection during compile time | ||
|
|
b4ddf4fb19 | Reduce dependency list to improve on build time | ||
|
|
7c8de84a34 | Bump dependencies | ||
|
|
dac5cd7639 |
Verify signed nonce
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 9b3c5c5..c1f63ba 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -179,6 +179,19 @@
<version>1.0.7</version>
</dependency>
+ <dependency>
+ <groupId>com.mojang</groupId>
+ <artifactId>datafixerupper</artifactId>
+ <version>5.0.28</version>
+ <scope>provided</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
<!--Library for listening and sending Minecraft packets-->
<dependency>
<groupId>com.comphenix.protocol</groupId>
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java
index 556def1..4f4af4d 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java
@@ -26,6 +26,7 @@
package com.github.games647.fastlogin.bukkit;
import com.github.games647.craftapi.model.skin.SkinProperty;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession;
@@ -42,30 +43,33 @@ public class BukkitLoginSession extends LoginSession {
private final byte[] verifyToken;
+ private final ClientPublicKey clientPublicKey;
+
private boolean verified;
private SkinProperty skinProperty;
- public BukkitLoginSession(String username, byte[] verifyToken, boolean registered
+ public BukkitLoginSession(String username, byte[] verifyToken, ClientPublicKey publicKey, boolean registered
, StoredProfile profile) {
super(username, registered, profile);
+ this.clientPublicKey = publicKey;
this.verifyToken = verifyToken.clone();
}
//available for BungeeCord
public BukkitLoginSession(String username, boolean registered) {
- this(username, EMPTY_ARRAY, registered, null);
+ this(username, EMPTY_ARRAY, null, registered, null);
}
//cracked player
public BukkitLoginSession(String username, StoredProfile profile) {
- this(username, EMPTY_ARRAY, false, profile);
+ this(username, EMPTY_ARRAY, null, false, profile);
}
//ProtocolSupport
public BukkitLoginSession(String username, boolean registered, StoredProfile profile) {
- this(username, EMPTY_ARRAY, registered, profile);
+ this(username, EMPTY_ARRAY, null, registered, profile);
}
/**
@@ -79,6 +83,10 @@ public class BukkitLoginSession extends LoginSession {
return verifyToken.clone();
}
+ public ClientPublicKey getClientPublicKey() {
+ return clientPublicKey;
+ }
+
/**
* @return premium skin if available
*/
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
index 956a60f..713fa68 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
@@ -27,6 +27,7 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.google.common.io.Resources;
+import com.google.common.primitives.Longs;
import java.io.IOException;
import java.math.BigInteger;
@@ -115,9 +116,9 @@ class EncryptionUtil {
/**
* Generate the server id based on client and server data.
*
- * @param sessionId session for the current login attempt
+ * @param sessionId session for the current login attempt
* @param sharedSecret shared secret between the client and the server
- * @param publicKey public key of the server
+ * @param publicKey public key of the server
* @return the server id formatted as a hexadecimal string.
*/
public static String getServerIdHashString(String sessionId, SecretKey sharedSecret, PublicKey publicKey) {
@@ -136,7 +137,7 @@ class EncryptionUtil {
* Decrypts the content and extracts the key spec.
*
* @param privateKey private server key
- * @param sharedKey the encrypted shared key
+ * @param sharedKey the encrypted shared key
* @return shared secret key
* @throws GeneralSecurityException if it fails to decrypt the data
*/
@@ -151,10 +152,20 @@ class EncryptionUtil {
return false;
}
- Signature signature = Signature.getInstance("SHA1withRSA");
- signature.initVerify(mojangSessionKey);
- signature.update(toSignable(clientKey).getBytes(StandardCharsets.US_ASCII));
- return signature.verify(clientKey.getSignature());
+ Signature verifier = Signature.getInstance("SHA1withRSA");
+ verifier.initVerify(mojangSessionKey);
+ verifier.update(toSignable(clientKey).getBytes(StandardCharsets.US_ASCII));
+ return verifier.verify(clientKey.getSignature());
+ }
+
+ public static boolean verifySignedNonce(byte[] nonce, PublicKey clientKey, long signatureSalt, byte[] signature)
+ throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ Signature verifier = Signature.getInstance("SHA256withRSA");
+ verifier.initVerify(clientKey);
+
+ verifier.update(nonce);
+ verifier.update(Longs.toByteArray(signatureSalt));
+ return verifier.verify(signature);
}
private static PublicKey loadMojangSessionKey()
@@ -183,7 +194,7 @@ class EncryptionUtil {
* Decrypted the given data using the cipher.
*
* @param cipher decryption cypher initialized with the private key
- * @param data the encrypted data
+ * @param data the encrypted data
* @return clear text data
* @throws GeneralSecurityException if it fails to decrypt the data
*/
@@ -194,7 +205,7 @@ class EncryptionUtil {
}
private static byte[] getServerIdHash(String sessionId, PublicKey publicKey, SecretKey sharedSecret)
- throws NoSuchAlgorithmException {
+ throws NoSuchAlgorithmException {
// byte[] a(String var0, PublicKey var1, SecretKey var2)
MessageDigest digest = MessageDigest.getInstance("SHA-1");
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java
index f0a4083..485c065 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java
@@ -27,21 +27,25 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.wrappers.BukkitConverters;
+import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.JoinManagement;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import java.security.PublicKey;
+import java.util.Optional;
import java.util.Random;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class NameCheckTask extends JoinManagement<Player, CommandSender, ProtocolLibLoginSource>
- implements Runnable {
+ implements Runnable {
private final FastLoginBukkit plugin;
private final PacketEvent packetEvent;
@@ -67,7 +71,9 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
@Override
public void run() {
try {
- super.onLogin(username, new ProtocolLibLoginSource(player, random, publicKey));
+ Optional<WrappedProfileKeyData> publicKey = packetEvent.getPacket().getOptionals(BukkitConverters.getWrappedPublicKeyDataConverter()).read(0);
+
+ super.onLogin(username, new ProtocolLibLoginSource(player, random, publicKey.get(), this.publicKey));
} finally {
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
}
@@ -85,7 +91,7 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L161
@Override
public void requestPremiumLogin(ProtocolLibLoginSource source, StoredProfile profile
- , String username, boolean registered) {
+ , String username, boolean registered) {
try {
source.enableOnlinemode();
} catch (Exception ex) {
@@ -97,8 +103,10 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
core.getPendingLogin().put(ip + username, new Object());
byte[] verify = source.getVerifyToken();
+ WrappedProfileKeyData key = source.getClientPublicKey();
+ ClientPublicKey clientKey = new ClientPublicKey(key.getExpireTime(), key.getKey(), key.getSignature());
- BukkitLoginSession playerSession = new BukkitLoginSession(username, verify, registered, profile);
+ BukkitLoginSession playerSession = new BukkitLoginSession(username, verify, clientKey, registered, profile);
plugin.putSession(player.getAddress(), playerSession);
//cancel only if the player has a paid account otherwise login as normal offline player
synchronized (packetEvent.getAsyncMarker().getProcessingLock()) {
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java
index 27c0335..a3bb3d0 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java
@@ -30,6 +30,7 @@ import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey;
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
@@ -38,6 +39,7 @@ import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.github.games647.fastlogin.core.antibot.AntiBotService;
import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
+import com.mojang.datafixers.util.Either;
import java.net.InetSocketAddress;
import java.security.InvalidKeyException;
@@ -139,9 +141,24 @@ public class ProtocolLibListener extends PacketAdapter {
plugin.getLog().warn("GameProfile {} tried to send encryption response at invalid state", sender.getAddress());
sender.kickPlayer(plugin.getCore().getMessage("invalid-request"));
} else {
- packetEvent.getAsyncMarker().incrementProcessingDelay();
- Runnable verifyTask = new VerifyResponseTask(plugin, packetEvent, sender, session, sharedSecret, keyPair);
- plugin.getScheduler().runAsync(verifyTask);
+ Either<byte[], ?> either = packetEvent.getPacket().getSpecificModifier(Either.class).read(0);
+ Object signatureData = either.right().get();
+ long salt = FuzzyReflection.getFieldValue(signatureData, Long.TYPE, true);
+ byte[] signature = FuzzyReflection.getFieldValue(signatureData, byte[].class, true);
+
+ BukkitLoginSession session = plugin.getSession(sender.getAddress());
+ PublicKey publicKey = session.getClientPublicKey().getKey();
+ try {
+ if (EncryptionUtil.verifySignedNonce(session.getVerifyToken(), publicKey, salt, signature)) {
+ packetEvent.getAsyncMarker().incrementProcessingDelay();
+ Runnable verifyTask = new VerifyResponseTask(plugin, packetEvent, sender, sharedSecret, keyPair);
+ plugin.getScheduler().runAsync(verifyTask);
+ } else {
+ sender.kickPlayer("Invalid signature");
+ }
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ sender.kickPlayer("Invalid signature");
+ }
}
}
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java
index dd191f1..d87b602 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java
@@ -30,6 +30,7 @@ import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
+import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
import com.github.games647.fastlogin.core.shared.LoginSource;
import java.lang.reflect.InvocationTargetException;
@@ -48,15 +49,18 @@ class ProtocolLibLoginSource implements LoginSource {
private final Player player;
private final Random random;
+
+ private final WrappedProfileKeyData clientPublicKey;
private final PublicKey publicKey;
private final String serverId = "";
private byte[] verifyToken;
- public ProtocolLibLoginSource(Player player, Random random, PublicKey publicKey) {
+ public ProtocolLibLoginSource(Player player, Random random, WrappedProfileKeyData clientPublicKey, PublicKey serverPublicKey) {
this.player = player;
this.random = random;
- this.publicKey = publicKey;
+ this.clientPublicKey = clientPublicKey;
+ this.publicKey = serverPublicKey;
}
@Override
@@ -109,6 +113,10 @@ class ProtocolLibLoginSource implements LoginSource {
return player.getAddress();
}
+ public WrappedProfileKeyData getClientPublicKey() {
+ return clientPublicKey;
+ }
+
public String getServerId() {
return serverId;
}
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java
index e974b09..d13a5c9 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java
@@ -29,12 +29,15 @@ import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.temporary.TemporaryPlayerFactory;
+import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
+import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
+import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
import com.github.games647.craftapi.model.auth.Verification;
import com.github.games647.craftapi.model.skin.SkinProperty;
import com.github.games647.craftapi.resolver.MojangResolver;
@@ -120,7 +123,7 @@ public class VerifyResponseTask implements Runnable {
}
try {
- if (!checkVerifyToken(session) || !enableEncryption(loginKey)) {
+ if (!enableEncryption(loginKey)) {
return;
}
} catch (Exception ex) {
@@ -180,23 +183,6 @@ public class VerifyResponseTask implements Runnable {
}
}
- private boolean checkVerifyToken(BukkitLoginSession session) throws GeneralSecurityException {
- byte[] requestVerify = session.getVerifyToken();
- //encrypted verify token
- byte[] responseVerify = packetEvent.getPacket().getByteArrays().read(1);
-
- //https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L182
- if (!Arrays.equals(requestVerify, EncryptionUtil.decrypt(serverKey.getPrivate(), responseVerify))) {
- //check if the verify-token are equal to the server sent one
- disconnect("invalid-verify-token",
- "GameProfile {0} ({1}) tried to login with an invalid verify token. Server: {2} Client: {3}",
- session.getRequestUsername(), packetEvent.getPlayer().getAddress(), requestVerify, responseVerify);
- return false;
- }
-
- return true;
- }
-
//try to get the networkManager from ProtocolLib
private Object getNetworkManager() throws IllegalAccessException, ClassNotFoundException {
Object injectorContainer = TemporaryPlayerFactory.getInjectorFromPlayer(player);
@@ -273,6 +259,9 @@ public class VerifyResponseTask implements Runnable {
if (MinecraftVersion.atOrAbove(new MinecraftVersion(1, 19, 0))) {
startPacket.getStrings().write(0, username);
+
+ EquivalentConverter<WrappedProfileKeyData> converter = BukkitConverters.getWrappedPublicKeyDataConverter();
+ startPacket.getOptionals(converter).write(0, Optional.empty());
} else {
//uuid is ignored by the packet definition
WrappedGameProfile fakeProfile = new WrappedGameProfile(UUID.randomUUID(), username);
diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/Base64Adapter.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/Base64Adapter.java
new file mode 100644
index 0000000..c2a2d1a
--- /dev/null
+++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/Base64Adapter.java
@@ -0,0 +1,48 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2022 games647 and contributors
+ *
+ * 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 com.github.games647.fastlogin.bukkit.listener.protocollib;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+import java.util.Base64;
+
+public class Base64Adapter extends TypeAdapter<byte[]> {
+
+ @Override
+ public void write(JsonWriter out, byte[] value) throws IOException {
+ var encoded = Base64.getEncoder().encodeToString(value);
+ out.value(encoded);
+ }
+
+ @Override
+ public byte[] read(JsonReader in) throws IOException {
+ String encoded = in.nextString();
+ return Base64.getDecoder().decode(encoded);
+ }
+}
diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
index 904405a..63a24ba 100644
--- a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
+++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
@@ -25,6 +25,7 @@
*/
package com.github.games647.fastlogin.bukkit.listener.protocollib;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.SignatureTestData.SignatureData;
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.google.common.io.Resources;
import com.google.gson.Gson;
@@ -36,9 +37,12 @@ import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
@@ -65,7 +69,7 @@ public class EncryptionUtilTest {
@Test
public void testExpiredClientKey() throws Exception {
- var clientKey = loadClientKey("client_keys/valid.json");
+ var clientKey = loadClientKey("client_keys/valid_public_key.json");
// Client expires at the exact second mentioned, so use it for verification
var expiredTimestamp = clientKey.getExpiry();
@@ -78,7 +82,9 @@ public class EncryptionUtilTest {
// expiration date changed should make the signature invalid
// expiration should still be valid
var clientKey = loadClientKey("client_keys/invalid_wrong_expiration.json");
- assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ Instant expireTimestamp = clientKey.getExpiry().minus(5, ChronoUnit.HOURS);
+
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp), is(false));
}
// @Test(expected = Exception.class)
@@ -86,31 +92,119 @@ public class EncryptionUtilTest {
public void testInvalidChangedKey() throws Exception {
// changed public key no longer corresponding to the signature
var clientKey = loadClientKey("client_keys/invalid_wrong_key.json");
- assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ Instant expireTimestamp = clientKey.getExpiry().minus(5, ChronoUnit.HOURS);
+
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp), is(false));
}
@Test
public void testInvalidChangedSignature() throws Exception {
// signature modified no longer corresponding to key and expiration date
var clientKey = loadClientKey("client_keys/invalid_wrong_signature.json");
- assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ Instant expireTimestamp = clientKey.getExpiry().minus(5, ChronoUnit.HOURS);
+
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp), is(false));
}
@Test
public void testValidClientKey() throws Exception {
- var clientKey = loadClientKey("client_keys/valid.json");
-
+ var clientKey = loadClientKey("client_keys/valid_public_key.json");
var verificationTimestamp = clientKey.getExpiry().minus(5, ChronoUnit.HOURS);
+
assertThat(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp), is(true));
}
+ @Test
+ public void testValidSignedNonce() throws Exception {
+ ClientPublicKey clientKey = loadClientKey("client_keys/valid_public_key.json");
+ PublicKey clientPublicKey = clientKey.getKey();
+
+ SignatureTestData testData = loadSignatureResource("signature/valid_signature.json");
+ byte[] nonce = testData.getNonce();
+ SignatureData signature = testData.getSignature();
+ long salt = signature.getSalt();
+ assertThat(EncryptionUtil.verifySignedNonce(nonce, clientPublicKey, salt, signature.getSignature()), is(true));
+ }
+
+ @Test
+ public void testIncorrectNonce() throws Exception {
+ ClientPublicKey clientKey = loadClientKey("client_keys/valid_public_key.json");
+ PublicKey clientPublicKey = clientKey.getKey();
+
+ SignatureTestData testData = loadSignatureResource("signature/incorrect_nonce.json");
+ byte[] nonce = testData.getNonce();
+ SignatureData signature = testData.getSignature();
+ long salt = signature.getSalt();
+ assertThat(EncryptionUtil.verifySignedNonce(nonce, clientPublicKey, salt, signature.getSignature()), is(false));
+ }
+
+ @Test
+ public void testIncorrectSalt() throws Exception {
+ // client generated
+ ClientPublicKey clientKey = loadClientKey("client_keys/valid_public_key.json");
+ PublicKey clientPublicKey = clientKey.getKey();
+
+ SignatureTestData testData = loadSignatureResource("signature/incorrect_salt.json");
+ byte[] nonce = testData.getNonce();
+ SignatureData signature = testData.getSignature();
+ long salt = signature.getSalt();
+ assertThat(EncryptionUtil.verifySignedNonce(nonce, clientPublicKey, salt, signature.getSignature()), is(false));
+ }
+
+ @Test
+ public void testIncorrectSignature() throws Exception {
+ // client generated
+ ClientPublicKey clientKey = loadClientKey("client_keys/valid_public_key.json");
+ PublicKey clientPublicKey = clientKey.getKey();
+
+ SignatureTestData testData = loadSignatureResource("signature/incorrect_signature.json");
+ byte[] nonce = testData.getNonce();
+ SignatureData signature = testData.getSignature();
+ long salt = signature.getSalt();
+ assertThat(EncryptionUtil.verifySignedNonce(nonce, clientPublicKey, salt, signature.getSignature()), is(false));
+ }
+
+ @Test
+ public void testWrongPublicKeySigned() throws Exception {
+ // load a different public key
+ ClientPublicKey clientKey = loadClientKey("client_keys/invalid_wrong_key.json");
+ PublicKey clientPublicKey = clientKey.getKey();
+
+ SignatureTestData testData = loadSignatureResource("signature/valid_signature.json");
+ byte[] nonce = testData.getNonce();
+ SignatureData signature = testData.getSignature();
+ long salt = signature.getSalt();
+ assertThat(EncryptionUtil.verifySignedNonce(nonce, clientPublicKey, salt, signature.getSignature()), is(false));
+ }
+
+ private SignatureTestData loadSignatureResource(String resourceName) throws IOException {
+ var keyUrl = Resources.getResource(resourceName);
+ var encodedSignature = Resources.toString(keyUrl, StandardCharsets.US_ASCII);
+
+ return new Gson().fromJson(encodedSignature, SignatureTestData.class);
+ }
+
+ private RSAPrivateKey parsePrivateKey(String keySpec)
+ throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
+ try (
+ Reader reader = new StringReader(keySpec);
+ PemReader pemReader = new PemReader(reader)
+ ) {
+ PemObject pemObject = pemReader.readPemObject();
+ byte[] content = pemObject.getContent();
+ var privateKeySpec = new PKCS8EncodedKeySpec(content);
+
+ var factory = KeyFactory.getInstance("RSA");
+ return (RSAPrivateKey) factory.generatePrivate(privateKeySpec);
+ }
+ }
+
private ClientPublicKey loadClientKey(String path)
throws NoSuchAlgorithmException, IOException, InvalidKeySpecException {
var keyUrl = Resources.getResource(path);
- var gson = new Gson();
var lines = Resources.toString(keyUrl, StandardCharsets.US_ASCII);
- var object = gson.fromJson(lines, JsonObject.class);
+ var object = new Gson().fromJson(lines, JsonObject.class);
Instant expires = Instant.parse(object.getAsJsonPrimitive("expires_at").getAsString());
String key = object.getAsJsonPrimitive("key").getAsString();
@@ -120,10 +214,10 @@ public class EncryptionUtilTest {
return new ClientPublicKey(expires, publicKey, signature);
}
- private RSAPublicKey parsePublicKey(String lines)
+ private RSAPublicKey parsePublicKey(String keySpec)
throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
try (
- Reader reader = new StringReader(lines);
+ Reader reader = new StringReader(keySpec);
PemReader pemReader = new PemReader(reader)
) {
PemObject pemObject = pemReader.readPemObject();
diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SignatureTestData.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SignatureTestData.java
new file mode 100644
index 0000000..8ea85f6
--- /dev/null
+++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SignatureTestData.java
@@ -0,0 +1,60 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2022 games647 and contributors
+ *
+ * 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 com.github.games647.fastlogin.bukkit.listener.protocollib;
+
+import com.google.gson.annotations.JsonAdapter;
+
+public class SignatureTestData {
+
+ @JsonAdapter(Base64Adapter.class)
+ private byte[] nonce;
+
+ private SignatureData signature;
+
+ public byte[] getNonce() {
+ return nonce;
+ }
+
+ public SignatureData getSignature() {
+ return signature;
+ }
+
+ public static class SignatureData {
+
+ private long salt;
+
+ @JsonAdapter(Base64Adapter.class)
+ private byte[] signature;
+
+ public long getSalt() {
+ return salt;
+ }
+
+ public byte[] getSignature() {
+ return signature;
+ }
+ }
+}
diff --git a/bukkit/src/test/resources/client_keys/README.md b/bukkit/src/test/resources/client_keys/README.md
new file mode 100644
index 0000000..1165e23
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/README.md
@@ -0,0 +1,27 @@
+# About
+
+This contains test resources for the unit tests. The file are extracted from the Minecraft directory with slight
+modifications. The files are found in `$MINECRAFT_HOME$/profilekeys/`, where `$MINECRAFT_HOME$` represents the
+OS-dependent minecraft folder.
+
+**Notable the files in this folder do not contain the private key information. It should be explicitly
+stripped before including it.**
+
+## Minecraft folder
+
+* Windows: `%appdata%\.minecraft`
+* Linux: `/home/username/.minecraft`
+* Mac: `~/Library/Application Support/minecraft`
+
+## Directory structure
+
+* `invalid_wrong_expiration.json`: Changed the expiration date
+* `invalid_wrong_key.json`: Modified public key while keeping the RSA structure valid
+* `invalid_wrong_signature.json`: Changed a character in the public key signature
+* `valid_public_key.json`: Extracted from actual file
+
+## File content
+
+* `expires_at`: Expiration date
+* `key`: Public key from the original file out of `public_key.key`
+* `signature`: Mojang signed signature of this public key
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json b/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json
index 7ecc12e..ea509fe 100644
--- a/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json
@@ -1,5 +1,5 @@
{
- "expires_at": "2022-06-12T09:46:26.421156927Z",
- "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xm\nDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/\n33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZ\nOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF\n4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWc\nPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
- "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+ "expires_at": "2022-06-20T07:31:47.318722344Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApd3ZxDhcRWWru1XEBke6uYqmbnS2Oxyk\nOMj+QDKrkwUqhVJYciyXGsMx46Mgr/KIoGCcokP5OtIxc6+69/ZLqJ9PvM81kLIxAqyvfBMKMGjP\n376LgxTF1FeDpbe5zXaNRxfmnvQhS5YTLbzgk36qWVjqxJMG4VLVmh7RV5zWsb7XlckZb2zRHM2Y\nMHbEC+ggX+l6zQyfG1KK0MH5k+O6b0xD0rv1wm24sLOesTXH6RZG8cNE3ofdnavxjFodTOnra6w1\naiVcoUTdEPSS86wQwq9j0YCcAKOwMXsqbk9NhpujrdyJ94dev+ELwkNS7P0pPrcfiyFTQeJCZTXz\nJB36MwIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "lfRXK4zL213wBKg760eiPV7yvnLZ6a6v9Iohmw78yxIzqXO3tfrC5Z+P2LGiO1BdI4xckx8yz4ktn82zX97+r2zktBw0As7g71H/FjInpoZ76j3gMUaiFNrQJ0vKCCI7xsjonemroWAVDCAqlvdyqwUu/Fnz85+WoR2kCQ721vwy6IjWA3xhq8XrWjkI/AlBmoS/kVqnvjjjc9vocdddJXbUYzCse/hWWIbsFeBXyiGCd3v7apgtXwQfM++tt87fq7444zQskiYb14oQP8/uNwqZWQ9jAs00i1BZ0MNM6+TZYGHOfS6rbHZ1bcX34VZdcCwpapK/Z2HBRIgDN4QOcgJkyq1GcjvlM2wjfhN8gXTsmbF9Ee+5Y6a4ONRkxRZK2sT8oAXdm0OlTEGB0P0+WRRFOQ/PnRqbI7lvANao2METT2EUHHrtqFMe53kqCHdzy5qyuHxdCEa6l/gSR08fybx9DdRRmhOlhSPGxhgwqyi1fEMrN4CsSKNrv5u+sMqhspA05b3DQJeLDX+UV5ujRHwm0A49NF+h1ZYlrcefz5IMUUisOOw6HiLc/YGLD2jHwSePGdfMwMnrIxbxjCta7/7A91aaN7eYm16KW9erCOwAfJmBSQC6Pbmg5f7rd7rAKVOPxglq7nayXmd+BK53Mal5tltMSgd/0iY6SEtGSEU="
}
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_key.json b/bukkit/src/test/resources/client_keys/invalid_wrong_key.json
index 37bb3ad..98ea33f 100644
--- a/bukkit/src/test/resources/client_keys/invalid_wrong_key.json
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_key.json
@@ -1,5 +1,5 @@
{
- "expires_at": "2022-06-12T10:46:26.421156927Z",
+ "expires_at": "2022-06-20T08:31:47.318722344Z",
"key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU3I+xmDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWcPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
- "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+ "signature": "lfRXK4zL213wBKg760eiPV7yvnLZ6a6v9Iohmw78yxIzqXO3tfrC5Z+P2LGiO1BdI4xckx8yz4ktn82zX97+r2zktBw0As7g71H/FjInpoZ76j3gMUaiFNrQJ0vKCCI7xsjonemroWAVDCAqlvdyqwUu/Fnz85+WoR2kCQ721vwy6IjWA3xhq8XrWjkI/AlBmoS/kVqnvjjjc9vocdddJXbUYzCse/hWWIbsFeBXyiGCd3v7apgtXwQfM++tt87fq7444zQskiYb14oQP8/uNwqZWQ9jAs00i1BZ0MNM6+TZYGHOfS6rbHZ1bcX34VZdcCwpapK/Z2HBRIgDN4QOcgJkyq1GcjvlM2wjfhN8gXTsmbF9Ee+5Y6a4ONRkxRZK2sT8oAXdm0OlTEGB0P0+WRRFOQ/PnRqbI7lvANao2METT2EUHHrtqFMe53kqCHdzy5qyuHxdCEa6l/gSR08fybx9DdRRmhOlhSPGxhgwqyi1fEMrN4CsSKNrv5u+sMqhspA05b3DQJeLDX+UV5ujRHwm0A49NF+h1ZYlrcefz5IMUUisOOw6HiLc/YGLD2jHwSePGdfMwMnrIxbxjCta7/7A91aaN7eYm16KW9erCOwAfJmBSQC6Pbmg5f7rd7rAKVOPxglq7nayXmd+BK53Mal5tltMSgd/0iY6SEtGSEU="
}
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json b/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json
index cbca4b1..2b80c2c 100644
--- a/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json
@@ -1,5 +1,5 @@
{
- "expires_at": "2022-06-12T10:46:26.421156927Z",
- "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xm\nDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/\n33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZ\nOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF\n4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWc\nPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
- "signature": "bYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+ "expires_at": "2022-06-20T08:31:47.318722344Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApd3ZxDhcRWWru1XEBke6uYqmbnS2Oxyk\nOMj+QDKrkwUqhVJYciyXGsMx46Mgr/KIoGCcokP5OtIxc6+69/ZLqJ9PvM81kLIxAqyvfBMKMGjP\n376LgxTF1FeDpbe5zXaNRxfmnvQhS5YTLbzgk36qWVjqxJMG4VLVmh7RV5zWsb7XlckZb2zRHM2Y\nMHbEC+ggX+l6zQyfG1KK0MH5k+O6b0xD0rv1wm24sLOesTXH6RZG8cNE3ofdnavxjFodTOnra6w1\naiVcoUTdEPSS86wQwq9j0YCcAKOwMXsqbk9NhpujrdyJ94dev+ELwkNS7P0pPrcfiyFTQeJCZTXz\nJB36MwIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "lfRxK4zL213wBKg760eiPV7yvnLZ6a6v9Iohmw78yxIzqXO3tfrC5Z+P2LGiO1BdI4xckx8yz4ktn82zX97+r2zktBw0As7g71H/FjInpoZ76j3gMUaiFNrQJ0vKCCI7xsjonemroWAVDCAqlvdyqwUu/Fnz85+WoR2kCQ721vwy6IjWA3xhq8XrWjkI/AlBmoS/kVqnvjjjc9vocdddJXbUYzCse/hWWIbsFeBXyiGCd3v7apgtXwQfM++tt87fq7444zQskiYb14oQP8/uNwqZWQ9jAs00i1BZ0MNM6+TZYGHOfS6rbHZ1bcX34VZdcCwpapK/Z2HBRIgDN4QOcgJkyq1GcjvlM2wjfhN8gXTsmbF9Ee+5Y6a4ONRkxRZK2sT8oAXdm0OlTEGB0P0+WRRFOQ/PnRqbI7lvANao2METT2EUHHrtqFMe53kqCHdzy5qyuHxdCEa6l/gSR08fybx9DdRRmhOlhSPGxhgwqyi1fEMrN4CsSKNrv5u+sMqhspA05b3DQJeLDX+UV5ujRHwm0A49NF+h1ZYlrcefz5IMUUisOOw6HiLc/YGLD2jHwSePGdfMwMnrIxbxjCta7/7A91aaN7eYm16KW9erCOwAfJmBSQC6Pbmg5f7rd7rAKVOPxglq7nayXmd+BK53Mal5tltMSgd/0iY6SEtGSEU="
}
diff --git a/bukkit/src/test/resources/client_keys/valid.json b/bukkit/src/test/resources/client_keys/valid.json
deleted file mode 100644
index a2d6a41..0000000
--- a/bukkit/src/test/resources/client_keys/valid.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "expires_at": "2022-06-12T10:46:26.421156927Z",
- "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xmDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWcPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
- "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
-}
diff --git a/bukkit/src/test/resources/client_keys/valid_public_key.json b/bukkit/src/test/resources/client_keys/valid_public_key.json
new file mode 100644
index 0000000..8943e87
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/valid_public_key.json
@@ -0,0 +1,5 @@
+{
+ "expires_at": "2022-06-20T08:31:47.318722344Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApd3ZxDhcRWWru1XEBke6uYqmbnS2Oxyk\nOMj+QDKrkwUqhVJYciyXGsMx46Mgr/KIoGCcokP5OtIxc6+69/ZLqJ9PvM81kLIxAqyvfBMKMGjP\n376LgxTF1FeDpbe5zXaNRxfmnvQhS5YTLbzgk36qWVjqxJMG4VLVmh7RV5zWsb7XlckZb2zRHM2Y\nMHbEC+ggX+l6zQyfG1KK0MH5k+O6b0xD0rv1wm24sLOesTXH6RZG8cNE3ofdnavxjFodTOnra6w1\naiVcoUTdEPSS86wQwq9j0YCcAKOwMXsqbk9NhpujrdyJ94dev+ELwkNS7P0pPrcfiyFTQeJCZTXz\nJB36MwIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "lfRXK4zL213wBKg760eiPV7yvnLZ6a6v9Iohmw78yxIzqXO3tfrC5Z+P2LGiO1BdI4xckx8yz4ktn82zX97+r2zktBw0As7g71H/FjInpoZ76j3gMUaiFNrQJ0vKCCI7xsjonemroWAVDCAqlvdyqwUu/Fnz85+WoR2kCQ721vwy6IjWA3xhq8XrWjkI/AlBmoS/kVqnvjjjc9vocdddJXbUYzCse/hWWIbsFeBXyiGCd3v7apgtXwQfM++tt87fq7444zQskiYb14oQP8/uNwqZWQ9jAs00i1BZ0MNM6+TZYGHOfS6rbHZ1bcX34VZdcCwpapK/Z2HBRIgDN4QOcgJkyq1GcjvlM2wjfhN8gXTsmbF9Ee+5Y6a4ONRkxRZK2sT8oAXdm0OlTEGB0P0+WRRFOQ/PnRqbI7lvANao2METT2EUHHrtqFMe53kqCHdzy5qyuHxdCEa6l/gSR08fybx9DdRRmhOlhSPGxhgwqyi1fEMrN4CsSKNrv5u+sMqhspA05b3DQJeLDX+UV5ujRHwm0A49NF+h1ZYlrcefz5IMUUisOOw6HiLc/YGLD2jHwSePGdfMwMnrIxbxjCta7/7A91aaN7eYm16KW9erCOwAfJmBSQC6Pbmg5f7rd7rAKVOPxglq7nayXmd+BK53Mal5tltMSgd/0iY6SEtGSEU="
+}
diff --git a/bukkit/src/test/resources/signature/README.md b/bukkit/src/test/resources/signature/README.md
new file mode 100644
index 0000000..cc603bc
--- /dev/null
+++ b/bukkit/src/test/resources/signature/README.md
@@ -0,0 +1,16 @@
+# About
+
+This contains test resources for the unit tests. Files in this folder include pre-made cryptographic signatures.
+
+## Directory structure
+
+* `valid_signature.json`: Extracted using packet extract from actual authentication
+* `incorrect_nonce.json`: Different nonce token simulating that the server expected a different token than signed
+* `incorrect_salt.json`: Salt sent is different to the content signed by the signature (changed salt field)
+* `incorrect_signature.json`: Changed signature
+
+## File content
+
+* `nonce`: Server generated nonce token
+* `salt`: Client generated random token
+* `signature`: Nonce and salt signed using the client key from `valid_public_key.json`
diff --git a/bukkit/src/test/resources/signature/incorrect_nonce.json b/bukkit/src/test/resources/signature/incorrect_nonce.json
new file mode 100644
index 0000000..b88c0f5
--- /dev/null
+++ b/bukkit/src/test/resources/signature/incorrect_nonce.json
@@ -0,0 +1,7 @@
+{
+ "nonce": "galNig\u003d\u003d",
+ "signature": {
+ "signature": "JlXAUtIGDjxUOnF5vkg/NUEN2wlzXcqADyYIw2WRTb5hgKwIgxyUPO5v/2M7xU3hxz2Zf0iYHM97h8qNMGQ43cLgfVH9VWZ1kGMuOby2LNSb6nDaMzm0b02ftThaWOWj9kJXbR8fN7qdpB+28t2CTW5ILT+2AZYI/Sn8gFFR+LvJJt1ENMfEj2ZIIkHecpNBuKyLz1aDCZ5BEASSLfAqHEAA3dpHV1DIgzfpO6xwo7bVFDtcBEeusl/Nc3KyGyT8sDFTsZWgitgz53xNKrZUK8Q2BaJfP0zrGAX36rpYURJSVD0AtI1ic9s5aG+OFUC1YhLXb/1cDv37ZjHcdV2ppw\u003d\u003d",
+ "salt": -2985008842905108412
+ }
+}
diff --git a/bukkit/src/test/resources/signature/incorrect_salt.json b/bukkit/src/test/resources/signature/incorrect_salt.json
new file mode 100644
index 0000000..8edffb6
--- /dev/null
+++ b/bukkit/src/test/resources/signature/incorrect_salt.json
@@ -0,0 +1,7 @@
+{
+ "nonce": "GalNig\u003d\u003d",
+ "signature": {
+ "signature": "JlXAUtIGDjxUOnF5vkg/NUEN2wlzXcqADyYIw2WRTb5hgKwIgxyUPO5v/2M7xU3hxz2Zf0iYHM97h8qNMGQ43cLgfVH9VWZ1kGMuOby2LNSb6nDaMzm0b02ftThaWOWj9kJXbR8fN7qdpB+28t2CTW5ILT+2AZYI/Sn8gFFR+LvJJt1ENMfEj2ZIIkHecpNBuKyLz1aDCZ5BEASSLfAqHEAA3dpHV1DIgzfpO6xwo7bVFDtcBEeusl/Nc3KyGyT8sDFTsZWgitgz53xNKrZUK8Q2BaJfP0zrGAX36rpYURJSVD0AtI1ic9s5aG+OFUC1YhLXb/1cDv37ZjHcdV2ppw\u003d\u003d",
+ "salt": -1985008842905108412
+ }
+}
diff --git a/bukkit/src/test/resources/signature/incorrect_signature.json b/bukkit/src/test/resources/signature/incorrect_signature.json
new file mode 100644
index 0000000..ba6bac5
--- /dev/null
+++ b/bukkit/src/test/resources/signature/incorrect_signature.json
@@ -0,0 +1,7 @@
+{
+ "nonce": "GalNig\u003d\u003d",
+ "signature": {
+ "signature": "jlXAUtIGDjxUOnF5vkg/NUEN2wlzXcqADyYIw2WRTb5hgKwIgxyUPO5v/2M7xU3hxz2Zf0iYHM97h8qNMGQ43cLgfVH9VWZ1kGMuOby2LNSb6nDaMzm0b02ftThaWOWj9kJXbR8fN7qdpB+28t2CTW5ILT+2AZYI/Sn8gFFR+LvJJt1ENMfEj2ZIIkHecpNBuKyLz1aDCZ5BEASSLfAqHEAA3dpHV1DIgzfpO6xwo7bVFDtcBEeusl/Nc3KyGyT8sDFTsZWgitgz53xNKrZUK8Q2BaJfP0zrGAX36rpYURJSVD0AtI1ic9s5aG+OFUC1YhLXb/1cDv37ZjHcdV2ppw\u003d\u003d",
+ "salt": -2985008842905108412
+ }
+}
diff --git a/bukkit/src/test/resources/signature/valid_signature.json b/bukkit/src/test/resources/signature/valid_signature.json
new file mode 100644
index 0000000..7f4f4ad
--- /dev/null
+++ b/bukkit/src/test/resources/signature/valid_signature.json
@@ -0,0 +1,7 @@
+{
+ "nonce": "GalNig\u003d\u003d",
+ "signature": {
+ "signature": "JlXAUtIGDjxUOnF5vkg/NUEN2wlzXcqADyYIw2WRTb5hgKwIgxyUPO5v/2M7xU3hxz2Zf0iYHM97h8qNMGQ43cLgfVH9VWZ1kGMuOby2LNSb6nDaMzm0b02ftThaWOWj9kJXbR8fN7qdpB+28t2CTW5ILT+2AZYI/Sn8gFFR+LvJJt1ENMfEj2ZIIkHecpNBuKyLz1aDCZ5BEASSLfAqHEAA3dpHV1DIgzfpO6xwo7bVFDtcBEeusl/Nc3KyGyT8sDFTsZWgitgz53xNKrZUK8Q2BaJfP0zrGAX36rpYURJSVD0AtI1ic9s5aG+OFUC1YhLXb/1cDv37ZjHcdV2ppw\u003d\u003d",
+ "salt": -2985008842905108412
+ }
+}
|
||
|
|
456342c686 |
Migrate to ProtocolLib field extractors for better compatibility
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index c4caae8..9b3c5c5 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -183,7 +183,7 @@
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
- <version>5.0.0-20220603.031413-2</version>
+ <version>5.0.0-SNAPSHOT</version>
<scope>provided</scope>
<exclusions>
<exclusion>
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java
index c9e72fc..3c66e7b 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java
@@ -27,12 +27,12 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
-import com.comphenix.protocol.events.InternalStructure;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
-import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
+import com.comphenix.protocol.wrappers.WrappedProfilePublicKey;
+import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
@@ -47,7 +47,6 @@ import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.time.Instant;
-import java.util.Optional;
import org.bukkit.entity.Player;
@@ -171,15 +170,15 @@ public class ProtocolLibListener extends PacketAdapter {
}
private boolean verifyPublicKey(PacketContainer packet) {
- Optional<InternalStructure> internalStructure = packet.getOptionalStructures().readSafely(0);
- if (internalStructure == null) {
+ WrappedProfileKeyData profileKey = packet.getProfilePublicKeys().optionRead(0)
+ .map(WrappedProfilePublicKey::getKeyData).orElse(null);
+ if (profileKey == null) {
return true;
}
- Object instance = internalStructure.get().getHandle();
- Instant expires = FuzzyReflection.getFieldValue(instance, Instant.class, true);
- PublicKey key = FuzzyReflection.getFieldValue(instance, PublicKey.class, true);
- byte[] signature = FuzzyReflection.getFieldValue(instance, byte[].class, true);
+ Instant expires = profileKey.getExpireTime();
+ PublicKey key = profileKey.getKey();
+ byte[] signature = profileKey.getSignature();
ClientPublicKey clientKey = new ClientPublicKey(expires, key.getEncoded(), signature);
try {
return EncryptionUtil.verifyClientKey(clientKey, Instant.now());
|
||
|
|
d353ac66ab |
Verify public keys from players
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 2e1ccc4..c4caae8 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -119,9 +119,6 @@
<repository>
<id>dmulloy2-repo</id>
<url>https://repo.dmulloy2.net/repository/public/</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
</repository>
<!-- AuthMe Reloaded, xAuth and LoginSecurity -->
@@ -186,7 +183,7 @@
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
- <version>5.0.0-SNAPSHOT</version>
+ <version>5.0.0-20220603.031413-2</version>
<scope>provided</scope>
<exclusions>
<exclusion>
@@ -351,5 +348,12 @@
<scope>system</scope>
<systemPath>${project.basedir}/lib/UltraAuth v2.1.2.jar</systemPath>
</dependency>
+
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk18on</artifactId>
+ <version>1.71</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
index 1197514..143dda9 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
@@ -25,15 +25,28 @@
*/
package com.github.games647.fastlogin.bukkit.listener.protocollib;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
+import com.google.common.io.Resources;
+
+import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.time.Instant;
+import java.util.Base64;
+import java.util.Base64.Encoder;
import java.util.Random;
import javax.crypto.Cipher;
@@ -46,11 +59,25 @@ import javax.crypto.spec.SecretKeySpec;
*
* @see net.minecraft.server.MinecraftEncryption
*/
-public class EncryptionUtil {
+class EncryptionUtil {
public static final int VERIFY_TOKEN_LENGTH = 4;
public static final String KEY_PAIR_ALGORITHM = "RSA";
+ private static final int RSA_LENGTH = 1_024;
+
+ private static final PublicKey mojangSessionKey;
+ private static final int LINE_LENGTH = 76;
+ private static final Encoder KEY_ENCODER = Base64.getMimeEncoder(LINE_LENGTH, "\n".getBytes(StandardCharsets.UTF_8));
+
+ static {
+ try {
+ mojangSessionKey = loadMojangSessionKey();
+ } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException ex) {
+ throw new RuntimeException("Failed to load Mojang session key", ex);
+ }
+ }
+
private EncryptionUtil() {
// utility
}
@@ -65,7 +92,7 @@ public class EncryptionUtil {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM);
- keyPairGenerator.initialize(1_024);
+ keyPairGenerator.initialize(RSA_LENGTH);
return keyPairGenerator.generateKeyPair();
} catch (NoSuchAlgorithmException nosuchalgorithmexception) {
// Should be existing in every vm
@@ -120,6 +147,33 @@ public class EncryptionUtil {
return new SecretKeySpec(decrypt(privateKey, sharedKey), "AES");
}
+ public static boolean verifyClientKey(ClientPublicKey clientKey, Instant verifyTimstamp)
+ throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
+ if (!verifyTimstamp.isBefore(clientKey.getExpiry())) {
+ return false;
+ }
+
+ Signature signature = Signature.getInstance("SHA1withRSA");
+ signature.initVerify(mojangSessionKey);
+ signature.update(toSignable(clientKey).getBytes(StandardCharsets.US_ASCII));
+ return signature.verify(clientKey.getSignature());
+ }
+
+ private static PublicKey loadMojangSessionKey()
+ throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
+ var keyUrl = Resources.getResource("yggdrasil_session_pubkey.der");
+ var keyData = Resources.toByteArray(keyUrl);
+ var keySpec = new X509EncodedKeySpec(keyData);
+
+ return KeyFactory.getInstance("RSA").generatePublic(keySpec);
+ }
+
+ private static String toSignable(ClientPublicKey clientPublicKey) {
+ long expiry = clientPublicKey.getExpiry().toEpochMilli();
+ String encoded = KEY_ENCODER.encodeToString(clientPublicKey.getKey());
+ return expiry + "-----BEGIN RSA PUBLIC KEY-----\n" + encoded + "\n-----END RSA PUBLIC KEY-----\n";
+ }
+
public static byte[] decrypt(PrivateKey key, byte[] data) throws GeneralSecurityException {
// b(Key var0, byte[] var1)
Cipher cipher = Cipher.getInstance(key.getAlgorithm());
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java
index f8b8de2..c9e72fc 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java
@@ -27,18 +27,27 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
+import com.comphenix.protocol.events.InternalStructure;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
-import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
+import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
+import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.github.games647.fastlogin.core.antibot.AntiBotService;
import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
import java.net.InetSocketAddress;
+import java.security.InvalidKeyException;
import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.time.Instant;
+import java.util.Optional;
import org.bukkit.entity.Player;
@@ -149,6 +158,11 @@ public class ProtocolLibListener extends PacketAdapter {
username = (String) packetEvent.getPacket().getMeta("original_name").get();
}
+ if (!verifyPublicKey(packet)) {
+ plugin.getLog().warn("Invalid public key from player {}", username);
+ return;
+ }
+
plugin.getLog().trace("GameProfile {} with {} connecting", sessionKey, username);
packetEvent.getAsyncMarker().incrementProcessingDelay();
@@ -156,6 +170,24 @@ public class ProtocolLibListener extends PacketAdapter {
plugin.getScheduler().runAsync(nameCheckTask);
}
+ private boolean verifyPublicKey(PacketContainer packet) {
+ Optional<InternalStructure> internalStructure = packet.getOptionalStructures().readSafely(0);
+ if (internalStructure == null) {
+ return true;
+ }
+
+ Object instance = internalStructure.get().getHandle();
+ Instant expires = FuzzyReflection.getFieldValue(instance, Instant.class, true);
+ PublicKey key = FuzzyReflection.getFieldValue(instance, PublicKey.class, true);
+ byte[] signature = FuzzyReflection.getFieldValue(instance, byte[].class, true);
+ ClientPublicKey clientKey = new ClientPublicKey(expires, key.getEncoded(), signature);
+ try {
+ return EncryptionUtil.verifyClientKey(clientKey, Instant.now());
+ } catch (SignatureException | InvalidKeyException | NoSuchAlgorithmException ex) {
+ return false;
+ }
+ }
+
private String getUsername(PacketContainer packet) {
WrappedGameProfile profile = packet.getGameProfiles().readSafely(0);
if (profile == null) {
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/packet/ClientPublicKey.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/packet/ClientPublicKey.java
new file mode 100644
index 0000000..495adb1
--- /dev/null
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/packet/ClientPublicKey.java
@@ -0,0 +1,53 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2022 games647 and contributors
+ *
+ * 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 com.github.games647.fastlogin.bukkit.listener.protocollib.packet;
+
+import java.time.Instant;
+
+public class ClientPublicKey {
+
+ private final Instant expiry;
+ private final byte[] key;
+ private final byte[] signature;
+
+ public ClientPublicKey(Instant expiry, byte[] key, byte[] signature) {
+ this.expiry = expiry;
+ this.key = key;
+ this.signature = signature;
+ }
+
+ public Instant getExpiry() {
+ return expiry;
+ }
+
+ public byte[] getKey() {
+ return key;
+ }
+
+ public byte[] getSignature() {
+ return signature;
+ }
+}
diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
index 7a097f1..11a52f7 100644
--- a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
+++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
@@ -25,8 +25,27 @@
*/
package com.github.games647.fastlogin.bukkit.listener.protocollib;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
+import com.google.common.io.Resources;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Base64;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.bouncycastle.util.io.pem.PemReader;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
@@ -43,4 +62,77 @@ public class EncryptionUtilTest {
assertThat(token, notNullValue());
assertThat(token.length, is(4));
}
+
+ @Test
+ public void testExpiredClientKey() throws Exception {
+ var clientKey = loadClientKey("client_keys/valid.json");
+
+ // Client expires at the exact second mentioned, so use it for verification
+ var expiredTimestamp = clientKey.getExpiry();
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, expiredTimestamp), is(false));
+ }
+
+ // @Test(expected = Exception.class)
+ @Test
+ public void testInvalidChangedExpiration() throws Exception {
+ // expiration date changed should make the signature invalid
+ // expiration should still be valid
+ var clientKey = loadClientKey("client_keys/invalid_wrong_expiration.json");
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ }
+
+ // @Test(expected = Exception.class)
+ @Test
+ public void testInvalidChangedKey() throws Exception {
+ // changed public key no longer corresponding to the signature
+ var clientKey = loadClientKey("client_keys/invalid_wrong_key.json");
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ }
+
+ @Test
+ public void testInvalidChangedSignature() throws Exception {
+ // signature modified no longer corresponding to key and expiration date
+ var clientKey = loadClientKey("client_keys/invalid_wrong_signature.json");
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ }
+
+ @Test
+ public void testValidClientKey() throws Exception {
+ var clientKey = loadClientKey("client_keys/valid.json");
+
+ var verificationTimestamp = clientKey.getExpiry().minus(5, ChronoUnit.HOURS);
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp), is(true));
+ }
+
+ private ClientPublicKey loadClientKey(String path)
+ throws NoSuchAlgorithmException, IOException, InvalidKeySpecException {
+ var keyUrl = Resources.getResource(path);
+ var gson = new Gson();
+
+ var lines = Resources.toString(keyUrl, StandardCharsets.US_ASCII);
+ var object = gson.fromJson(lines, JsonObject.class);
+
+ Instant expires = Instant.parse(object.getAsJsonPrimitive("expires_at").getAsString());
+ String key = object.getAsJsonPrimitive("key").getAsString();
+ RSAPublicKey publicKey = parsePublicKey(key);
+
+ byte[] signature = Base64.getDecoder().decode(object.getAsJsonPrimitive("signature").getAsString());
+ return new ClientPublicKey(expires, publicKey.getEncoded(), signature);
+ }
+
+ private RSAPublicKey parsePublicKey(String lines)
+ throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
+ try (
+ Reader reader = new StringReader(lines);
+ PemReader pemReader = new PemReader(reader)
+ ) {
+
+ PemObject pemObject = pemReader.readPemObject();
+ byte[] content = pemObject.getContent();
+ var pubKeySpec = new X509EncodedKeySpec(content);
+
+ var factory = KeyFactory.getInstance("RSA");
+ return (RSAPublicKey) factory.generatePublic(pubKeySpec);
+ }
+ }
}
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json b/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json
new file mode 100644
index 0000000..7ecc12e
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json
@@ -0,0 +1,5 @@
+{
+ "expires_at": "2022-06-12T09:46:26.421156927Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xm\nDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/\n33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZ\nOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF\n4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWc\nPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+}
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_key.json b/bukkit/src/test/resources/client_keys/invalid_wrong_key.json
new file mode 100644
index 0000000..37bb3ad
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_key.json
@@ -0,0 +1,5 @@
+{
+ "expires_at": "2022-06-12T10:46:26.421156927Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU3I+xmDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWcPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+}
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json b/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json
new file mode 100644
index 0000000..cbca4b1
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json
@@ -0,0 +1,5 @@
+{
+ "expires_at": "2022-06-12T10:46:26.421156927Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xm\nDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/\n33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZ\nOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF\n4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWc\nPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "bYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+}
diff --git a/bukkit/src/test/resources/client_keys/valid.json b/bukkit/src/test/resources/client_keys/valid.json
new file mode 100644
index 0000000..a2d6a41
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/valid.json
@@ -0,0 +1,5 @@
+{
+ "expires_at": "2022-06-12T10:46:26.421156927Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xmDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWcPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+}
|
||
|
|
d8a6e2a6fa |
Update ProtocolLib to 5.0
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 13e466e..2494a2b 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -186,7 +186,7 @@
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
- <version>4.8.0</version>
+ <version>5.0.0-SNAPSHOT</version>
<scope>provided</scope>
<exclusions>
<exclusion>
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java
index 5a2794d..2e60cd1 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java
@@ -28,7 +28,7 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
-import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
+import com.comphenix.protocol.injector.temporary.TemporaryPlayerFactory;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection;
@@ -37,18 +37,14 @@ import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.github.games647.craftapi.model.auth.Verification;
import com.github.games647.craftapi.model.skin.SkinProperty;
-import com.github.games647.craftapi.resolver.AbstractResolver;
import com.github.games647.craftapi.resolver.MojangResolver;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.net.*;
-import java.nio.charset.StandardCharsets;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
@@ -263,15 +259,11 @@ public class VerifyResponseTask implements Runnable {
private void kickPlayer(String reason) {
PacketContainer kickPacket = new PacketContainer(DISCONNECT);
kickPacket.getChatComponents().write(0, WrappedChatComponent.fromText(reason));
- try {
- //send kick packet at login state
- //the normal event.getPlayer.kickPlayer(String) method does only work at play state
- ProtocolLibrary.getProtocolManager().sendServerPacket(player, kickPacket);
- //tell the server that we want to close the connection
- player.kickPlayer("Disconnect");
- } catch (InvocationTargetException ex) {
- plugin.getLog().error("Error sending kick packet for: {}", player, ex);
- }
+ //send kick packet at login state
+ //the normal event.getPlayer.kickPlayer(String) method does only work at play state
+ ProtocolLibrary.getProtocolManager().sendServerPacket(player, kickPacket);
+ //tell the server that we want to close the connection
+ player.kickPlayer("Disconnect");
}
//fake a new login packet in order to let the server handle all the other stuff
@@ -287,14 +279,8 @@ public class VerifyResponseTask implements Runnable {
startPacket.getGameProfiles().write(0, fakeProfile);
}
- try {
- //we don't want to handle our own packets so ignore filters
- startPacket.setMeta(ProtocolLibListener.SOURCE_META_KEY, plugin.getName());
- ProtocolLibrary.getProtocolManager().recieveClientPacket(player, startPacket, true);
- } catch (InvocationTargetException | IllegalAccessException ex) {
- plugin.getLog().warn("Failed to fake a new start packet for: {}", username, ex);
- //cancel the event in order to prevent the server receiving an invalid packet
- kickPlayer(plugin.getCore().getMessage("error-kick"));
- }
+ //we don't want to handle our own packets so ignore filters
+ startPacket.setMeta(ProtocolLibListener.SOURCE_META_KEY, plugin.getName());
+ ProtocolLibrary.getProtocolManager().receiveClientPacket(player, startPacket, true);
}
}
|
||
|
|
219ebb1248 | Bump version | ||
|
|
c92f94d2e8 |
Bump api from 2.0-SNAPSHOT to 2.2.0-SNAPSHOT
Bumps api from 2.0-SNAPSHOT to 2.2.0-SNAPSHOT. --- updated-dependencies: - dependency-name: org.geysermc.floodgate:api dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
8d50a14371 | Drop SodionAuth plugin, because it's no longer reachable in Maven | ||
|
|
fc50c997ba | Dump craftapi for updated GSON version and allow . in legit usernames | ||
|
|
07dea4ac0f |
Bump maven-shade-plugin from 3.2.4 to 3.3.0
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.2.4 to 3.3.0. - [Release notes](https://github.com/apache/maven-shade-plugin/releases) - [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.2.4...maven-shade-plugin-3.3.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-shade-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
d11cd4f9a1 | Ignore META-Info in shading | ||
|
|
1d3fcb9929 |
Use custom repository settings for faster fetching
Order of repository seems to indicate maven priority fetching |
||
|
|
35b044651c |
Update dependencies
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index e57b9d2..939697a 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -272,7 +272,7 @@
<dependency>
<groupId>com.lenis0012.bukkit</groupId>
<artifactId>loginsecurity</artifactId>
- <version>3.0.2</version>
+ <version>3.1</version>
<scope>provided</scope>
<optional>true</optional>
<exclusions>
diff --git a/core/pom.xml b/core/pom.xml
index 15a1eb7..3738e9d 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -179,7 +179,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
- <version>2.8.9</version>
+ <version>2.9.0</version>
</dependency>
</dependencies>
</project>
|
||
|
|
a856356c49 |
Update license headers to 02db104
Done using `mvn license:format` |
||
|
|
8a01ddc231 |
Do not shade the MultiMap class
This class is used by ProtocolLib. Calling it, means we use its signature. With relocating this would also update the method call signature to `.WrappedGameProfile.getProperties()Lfastlogin/guava/collect/Multimap;`, which obviously not present. |
||
|
|
a5c7e7371d | Try out to minimize unnecessary classes from big dependencies | ||
|
|
35b493a708 | Typo fixes | ||
|
|
1d7c2aed61 |
Bump placeholderapi from 2.10.10 to 2.11.0
Bumps placeholderapi from 2.10.10 to 2.11.0. --- updated-dependencies: - dependency-name: me.clip:placeholderapi dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
8c33813e45 | Update to Geyser 2.0 API | ||
|
|
6c47abc76d | Update dependencies | ||
|
|
9c2068032f | Remove duplicate dependency | ||
|
|
2110e93bd6 |
Override slf4j transitive dependency from paper
Fixes #670 |
||
|
|
7439a95e16 | Reduce the amount of necessary dependencies by dropping transitive ones | ||
|
|
e1c1da199e |
Search SL4J JDK provider in our own classpath
Using the previous behavior it would look for the service file and provider in the server jar. First it requires relocating the service file to our JDK provider and let the service only be queryable from our plugin jar. Fixes #668 Search SL4J JDK provider in our own classpath Using the previous behavior it would look for the service file and provider in the server jar. First it requires relocating the service file to our JDK provider and let the service only be queryable from our plugin jar. Fixes #668 |
||
|
|
1dd27ff529 | Restore 1.8 compatibility by shading guava in Spigot versions | ||
|
|
f5a60ca0b3 |
Bump paperlib from 1.0.6 to 1.0.7
Bumps [paperlib](https://github.com/PaperMC/PaperLib) from 1.0.6 to 1.0.7. - [Release notes](https://github.com/PaperMC/PaperLib/releases) - [Changelog](https://github.com/PaperMC/PaperLib/blob/master/CHANGELOG.md) - [Commits](https://github.com/PaperMC/PaperLib/compare/1.0.6...v1.0.7) --- updated-dependencies: - dependency-name: io.papermc:paperlib dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
3ee6cb2ada |
Create stub GeyserService
The FloodgateService and GeyserService classes are not merged, because Geyser can work without Floodgate. Added Geyser as 'softdepends' in plugin.yml and bungee.yml to make it load before FastLogin. Also made Floodgate a soft dependency in bungee.yml. |
||
|
|
f39c3a1ea6 | Update Floodgate repository | ||
|
|
58cee1e26e |
Exclude more transitive dependencies
This could reduce the number of required downloads as well as to prevent download from legacy HTTP non secure (not HTTPS) sources. |
||
|
|
08b864220d | Merge branch 'main' of https://github.com/games647/FastLogin | ||
|
|
d01c368cdb | Fix identation in bukkit/pom.xml | ||
|
|
8837a1b70e | Bump SodionAuth version and fix errors. | ||
|
|
0c45c30d2f | Bump SodionAuth version |