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