mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-08 01:17:47 +01:00
Add encryption support
This commit is contained in:
parent
f75f755194
commit
b56509718c
@ -14,8 +14,7 @@ import java.security.*;
|
|||||||
public final class MojangCrypt {
|
public final class MojangCrypt {
|
||||||
private static final Logger LOGGER = LogManager.getLogger();
|
private static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
|
||||||
@Nullable
|
public static @Nullable KeyPair generateKeyPair() {
|
||||||
public static KeyPair generateKeyPair() {
|
|
||||||
try {
|
try {
|
||||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||||
keyGen.initialize(1024);
|
keyGen.initialize(1024);
|
||||||
@ -27,8 +26,7 @@ public final class MojangCrypt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
public static byte @Nullable [] digestData(String data, PublicKey publicKey, SecretKey secretKey) {
|
||||||
public static byte[] digestData(String data, PublicKey publicKey, SecretKey secretKey) {
|
|
||||||
try {
|
try {
|
||||||
return digestData("SHA-1", data.getBytes("ISO_8859_1"), secretKey.getEncoded(), publicKey.getEncoded());
|
return digestData("SHA-1", data.getBytes("ISO_8859_1"), secretKey.getEncoded(), publicKey.getEncoded());
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
@ -37,15 +35,12 @@ public final class MojangCrypt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private static byte @Nullable [] digestData(String algorithm, byte[]... data) {
|
||||||
private static byte[] digestData(String algorithm, byte[]... data) {
|
|
||||||
try {
|
try {
|
||||||
MessageDigest digest = MessageDigest.getInstance(algorithm);
|
MessageDigest digest = MessageDigest.getInstance(algorithm);
|
||||||
|
|
||||||
for (byte[] bytes : data) {
|
for (byte[] bytes : data) {
|
||||||
digest.update(bytes);
|
digest.update(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return digest.digest();
|
return digest.digest();
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
MinecraftServer.getExceptionManager().handleException(e);
|
||||||
@ -67,7 +62,6 @@ public final class MojangCrypt {
|
|||||||
} catch (IllegalBlockSizeException | BadPaddingException var4) {
|
} catch (IllegalBlockSizeException | BadPaddingException var4) {
|
||||||
MinecraftServer.getExceptionManager().handleException(var4);
|
MinecraftServer.getExceptionManager().handleException(var4);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.error("Cipher data failed!");
|
LOGGER.error("Cipher data failed!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -80,7 +74,6 @@ public final class MojangCrypt {
|
|||||||
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException var4) {
|
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException var4) {
|
||||||
MinecraftServer.getExceptionManager().handleException(var4);
|
MinecraftServer.getExceptionManager().handleException(var4);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.error("Cipher creation failed!");
|
LOGGER.error("Cipher creation failed!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import net.minestom.server.MinecraftServer;
|
|||||||
import net.minestom.server.adventure.MinestomAdventure;
|
import net.minestom.server.adventure.MinestomAdventure;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.entity.PlayerSkin;
|
import net.minestom.server.entity.PlayerSkin;
|
||||||
|
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
||||||
import net.minestom.server.network.ConnectionState;
|
import net.minestom.server.network.ConnectionState;
|
||||||
import net.minestom.server.network.PacketProcessor;
|
import net.minestom.server.network.PacketProcessor;
|
||||||
import net.minestom.server.network.packet.FramedPacket;
|
import net.minestom.server.network.packet.FramedPacket;
|
||||||
@ -20,7 +21,9 @@ import org.jetbrains.annotations.ApiStatus;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.ShortBufferException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.BufferUnderflowException;
|
import java.nio.BufferUnderflowException;
|
||||||
@ -47,6 +50,8 @@ public class NettyPlayerConnection extends PlayerConnection {
|
|||||||
|
|
||||||
//Could be null. Only used for Mojang Auth
|
//Could be null. Only used for Mojang Auth
|
||||||
private byte[] nonce = new byte[4];
|
private byte[] nonce = new byte[4];
|
||||||
|
private Cipher decryptCipher;
|
||||||
|
private Cipher encryptCipher;
|
||||||
|
|
||||||
// Data from client packets
|
// Data from client packets
|
||||||
private String loginUsername;
|
private String loginUsername;
|
||||||
@ -74,6 +79,20 @@ public class NettyPlayerConnection extends PlayerConnection {
|
|||||||
|
|
||||||
public void processPackets(Worker.Context workerContext, PacketProcessor packetProcessor) {
|
public void processPackets(Worker.Context workerContext, PacketProcessor packetProcessor) {
|
||||||
final var readBuffer = workerContext.readBuffer;
|
final var readBuffer = workerContext.readBuffer;
|
||||||
|
// Decrypt data
|
||||||
|
if (encrypted) {
|
||||||
|
final Cipher cipher = decryptCipher;
|
||||||
|
final int remainingBytes = readBuffer.readableBytes();
|
||||||
|
final byte[] bytes = readBuffer.readRemainingBytes();
|
||||||
|
byte[] output = new byte[cipher.getOutputSize(remainingBytes)];
|
||||||
|
try {
|
||||||
|
cipher.update(bytes, 0, remainingBytes, output, 0);
|
||||||
|
} catch (ShortBufferException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
readBuffer.clear();
|
||||||
|
readBuffer.writeBytes(output);
|
||||||
|
}
|
||||||
final int limit = readBuffer.writerOffset();
|
final int limit = readBuffer.writerOffset();
|
||||||
// Read all packets
|
// Read all packets
|
||||||
while (readBuffer.readableBytes() > 0) {
|
while (readBuffer.readableBytes() > 0) {
|
||||||
@ -146,8 +165,9 @@ public class NettyPlayerConnection extends PlayerConnection {
|
|||||||
*/
|
*/
|
||||||
public void setEncryptionKey(@NotNull SecretKey secretKey) {
|
public void setEncryptionKey(@NotNull SecretKey secretKey) {
|
||||||
Check.stateCondition(encrypted, "Encryption is already enabled!");
|
Check.stateCondition(encrypted, "Encryption is already enabled!");
|
||||||
|
this.decryptCipher = MojangCrypt.getCipher(2, secretKey);
|
||||||
|
this.encryptCipher = MojangCrypt.getCipher(1, secretKey);
|
||||||
this.encrypted = true;
|
this.encrypted = true;
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -221,9 +241,21 @@ public class NettyPlayerConnection extends PlayerConnection {
|
|||||||
synchronized (tickBuffer) {
|
synchronized (tickBuffer) {
|
||||||
if (tickBuffer.readableBytes() == 0) return;
|
if (tickBuffer.readableBytes() == 0) return;
|
||||||
try {
|
try {
|
||||||
|
if (encrypted) {
|
||||||
|
final Cipher cipher = encryptCipher;
|
||||||
|
// Encrypt data first
|
||||||
|
final int remainingBytes = tickBuffer.readableBytes();
|
||||||
|
final byte[] bytes = tickBuffer.readRemainingBytes();
|
||||||
|
byte[] outTempArray = new byte[cipher.getOutputSize(remainingBytes)];
|
||||||
|
cipher.update(bytes, 0, remainingBytes, outTempArray);
|
||||||
|
this.tickBuffer.clear();
|
||||||
|
this.tickBuffer.writeBytes(outTempArray);
|
||||||
|
}
|
||||||
this.tickBuffer.writeChannel(channel);
|
this.tickBuffer.writeChannel(channel);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
MinecraftServer.getExceptionManager().handleException(e);
|
||||||
|
} catch (ShortBufferException e) {
|
||||||
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
this.tickBuffer.clear();
|
this.tickBuffer.clear();
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ public final class BinaryBuffer {
|
|||||||
public void write(ByteBuffer buffer) {
|
public void write(ByteBuffer buffer) {
|
||||||
final int size = buffer.remaining();
|
final int size = buffer.remaining();
|
||||||
// TODO jdk 13 put with index
|
// TODO jdk 13 put with index
|
||||||
asByteBuffer(writerOffset, writerOffset + size).put(buffer);
|
this.nioBuffer.position(writerOffset).put(buffer);
|
||||||
this.writerOffset += size;
|
this.writerOffset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,13 +98,29 @@ public final class BinaryBuffer {
|
|||||||
return writerOffset - readerOffset;
|
return writerOffset - readerOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeBytes(byte[] bytes) {
|
||||||
|
this.nioBuffer.position(writerOffset).put(bytes);
|
||||||
|
this.writerOffset += bytes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] readBytes(int length) {
|
||||||
|
byte[] bytes = new byte[length];
|
||||||
|
this.nioBuffer.position(readerOffset).get(bytes, 0, length);
|
||||||
|
this.readerOffset += length;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] readRemainingBytes() {
|
||||||
|
return readBytes(readableBytes());
|
||||||
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
this.readerOffset = 0;
|
this.readerOffset = 0;
|
||||||
this.writerOffset = 0;
|
this.writerOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer asByteBuffer(int reader, int writer) {
|
public ByteBuffer asByteBuffer(int reader, int writer) {
|
||||||
return nioBuffer.duplicate().position(reader).limit(writer);
|
return nioBuffer.position(reader).slice().limit(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeChannel(WritableByteChannel channel) throws IOException {
|
public void writeChannel(WritableByteChannel channel) throws IOException {
|
||||||
|
Loading…
Reference in New Issue
Block a user