Minestom/src/main/java/net/minestom/server/network/packet/client/login/EncryptionResponsePacket.java

85 lines
3.7 KiB
Java

package net.minestom.server.network.packet.client.login;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
import net.minestom.server.MinecraftServer;
import net.minestom.server.data.type.array.ByteArrayData;
import net.minestom.server.extras.MojangAuth;
import net.minestom.server.extras.mojangAuth.MojangCrypt;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.player.NettyPlayerConnection;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.binary.BinaryReader;
import org.jetbrains.annotations.NotNull;
import javax.crypto.SecretKey;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
public class EncryptionResponsePacket implements ClientPreplayPacket {
private final static String THREAD_NAME = "Mojang Auth Thread";
private static final AtomicInteger UNIQUE_THREAD_ID = new AtomicInteger(0);
private byte[] sharedSecret;
private byte[] verifyToken;
@Override
public void process(@NotNull PlayerConnection connection) {
// Encryption is only support for netty connection
if (!(connection instanceof NettyPlayerConnection)) {
return;
}
final NettyPlayerConnection nettyConnection = (NettyPlayerConnection) connection;
new Thread(THREAD_NAME + " #" + UNIQUE_THREAD_ID.incrementAndGet()) {
public void run() {
try {
final String loginUsername = nettyConnection.getLoginUsername();
if (!Arrays.equals(nettyConnection.getNonce(), getNonce())) {
MinecraftServer.LOGGER.error(loginUsername + " tried to login with an invalid nonce!");
return;
}
if (!loginUsername.isEmpty()) {
final byte[] digestedData = MojangCrypt.digestData("", MojangAuth.getKeyPair().getPublic(), getSecretKey());
if (digestedData == null) {
// Incorrect key, probably because of the client
MinecraftServer.LOGGER.error("Connection " + nettyConnection.getRemoteAddress() + " failed initializing encryption.");
connection.disconnect();
return;
}
final String string3 = new BigInteger(digestedData).toString(16);
final GameProfile gameProfile = MojangAuth.getSessionService().hasJoinedServer(new GameProfile(null, loginUsername), string3);
nettyConnection.setEncryptionKey(getSecretKey());
MinecraftServer.LOGGER.info("UUID of player {} is {}", loginUsername, gameProfile.getId());
CONNECTION_MANAGER.startPlayState(connection, gameProfile.getId(), gameProfile.getName());
}
} catch (AuthenticationUnavailableException e) {
e.printStackTrace();
}
}
}.start();
}
@Override
public void read(@NotNull BinaryReader reader) {
sharedSecret = ByteArrayData.decodeByteArray(reader);
verifyToken = ByteArrayData.decodeByteArray(reader);
}
public SecretKey getSecretKey() {
return MojangCrypt.decryptByteToSecretKey(MojangAuth.getKeyPair().getPrivate(), sharedSecret);
}
public byte[] getNonce() {
return MojangAuth.getKeyPair().getPrivate() == null ?
this.verifyToken : MojangCrypt.decryptUsingKey(MojangAuth.getKeyPair().getPrivate(), this.verifyToken);
}
}