mirror of https://github.com/Minestom/Minestom.git
85 lines
3.7 KiB
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);
|
|
}
|
|
}
|