Add encryption support

This commit is contained in:
TheMode 2021-08-08 19:02:36 +02:00
parent f75f755194
commit b56509718c
3 changed files with 54 additions and 13 deletions

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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 {