aboutsummaryrefslogtreecommitdiffhomepage
path: root/paper-server/patches/features/0005-Use-Velocity-compression-and-cipher-natives.patch
diff options
context:
space:
mode:
Diffstat (limited to 'paper-server/patches/features/0005-Use-Velocity-compression-and-cipher-natives.patch')
-rw-r--r--paper-server/patches/features/0005-Use-Velocity-compression-and-cipher-natives.patch354
1 files changed, 354 insertions, 0 deletions
diff --git a/paper-server/patches/features/0005-Use-Velocity-compression-and-cipher-natives.patch b/paper-server/patches/features/0005-Use-Velocity-compression-and-cipher-natives.patch
new file mode 100644
index 0000000000..9011d342f0
--- /dev/null
+++ b/paper-server/patches/features/0005-Use-Velocity-compression-and-cipher-natives.patch
@@ -0,0 +1,354 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrew Steinborn <[email protected]>
+Date: Mon, 26 Jul 2021 02:15:17 -0400
+Subject: [PATCH] Use Velocity compression and cipher natives
+
+
+diff --git a/net/minecraft/network/CipherDecoder.java b/net/minecraft/network/CipherDecoder.java
+index 429325ffb7db2b85ed271ddf3da64c6fdc593673..d764552aea825af7bbf0f47c9d88af527d9dbe62 100644
+--- a/net/minecraft/network/CipherDecoder.java
++++ b/net/minecraft/network/CipherDecoder.java
+@@ -7,14 +7,30 @@ import java.util.List;
+ import javax.crypto.Cipher;
+
+ public class CipherDecoder extends MessageToMessageDecoder<ByteBuf> {
+- private final CipherBase cipher;
++ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper - Use Velocity cipher
+
+- public CipherDecoder(Cipher cipher) {
+- this.cipher = new CipherBase(cipher);
++ public CipherDecoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper - Use Velocity cipher
++ this.cipher = cipher; // Paper - Use Velocity cipher
+ }
+
+ @Override
+ protected void decode(ChannelHandlerContext context, ByteBuf in, List<Object> out) throws Exception {
+- out.add(this.cipher.decipher(context, in));
++ // Paper start - Use Velocity cipher
++ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(context.alloc(), this.cipher, in);
++ try {
++ this.cipher.process(compatible);
++ out.add(compatible);
++ } catch (Exception e) {
++ compatible.release(); // compatible will never be used if we throw an exception
++ throw e;
++ }
++ // Paper end - Use Velocity cipher
+ }
++
++ // Paper start - Use Velocity cipher
++ @Override
++ public void handlerRemoved(ChannelHandlerContext ctx) {
++ this.cipher.close();
++ }
++ // Paper end - Use Velocity cipher
+ }
+diff --git a/net/minecraft/network/CipherEncoder.java b/net/minecraft/network/CipherEncoder.java
+index 992b9c7aed57ce29cdd2b4f66737d39db214f0cf..b927c85923147d2b346e892a3e4deee48b3d073e 100644
+--- a/net/minecraft/network/CipherEncoder.java
++++ b/net/minecraft/network/CipherEncoder.java
+@@ -5,15 +5,31 @@ import io.netty.channel.ChannelHandlerContext;
+ import io.netty.handler.codec.MessageToByteEncoder;
+ import javax.crypto.Cipher;
+
+-public class CipherEncoder extends MessageToByteEncoder<ByteBuf> {
+- private final CipherBase cipher;
++public class CipherEncoder extends io.netty.handler.codec.MessageToMessageEncoder<ByteBuf> { // Paper - Use Velocity cipher; change superclass
++ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper - Use Velocity cipher
+
+- public CipherEncoder(Cipher cipher) {
+- this.cipher = new CipherBase(cipher);
++ public CipherEncoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper - Use Velocity cipher
++ this.cipher = cipher; // Paper - Use Velocity cipher
+ }
+
++ // Paper start - Use Velocity cipher
+ @Override
+- protected void encode(ChannelHandlerContext context, ByteBuf message, ByteBuf out) throws Exception {
+- this.cipher.encipher(message, out);
++ protected void encode(ChannelHandlerContext context, ByteBuf message, java.util.List<Object> list) throws Exception {
++ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(context.alloc(), this.cipher, message);
++ try {
++ this.cipher.process(compatible);
++ list.add(compatible);
++ } catch (Exception e) {
++ compatible.release(); // compatible will never be used if we throw an exception
++ throw e;
++ }
++ // Paper end - Use Velocity cipher
+ }
++
++ // Paper start - Use Velocity cipher
++ @Override
++ public void handlerRemoved(ChannelHandlerContext ctx) {
++ this.cipher.close();
++ }
++ // Paper end - Use Velocity cipher
+ }
+diff --git a/net/minecraft/network/CompressionDecoder.java b/net/minecraft/network/CompressionDecoder.java
+index fcf0e557fbcbd5f306625096d859578fe8511734..2c7f935fcecb24a4394fdde523219a5b5984a673 100644
+--- a/net/minecraft/network/CompressionDecoder.java
++++ b/net/minecraft/network/CompressionDecoder.java
+@@ -12,14 +12,22 @@ import java.util.zip.Inflater;
+ public class CompressionDecoder extends ByteToMessageDecoder {
+ public static final int MAXIMUM_COMPRESSED_LENGTH = 2097152;
+ public static final int MAXIMUM_UNCOMPRESSED_LENGTH = 8388608;
++ private com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper - Use Velocity cipher
+ private Inflater inflater;
+ private int threshold;
+ private boolean validateDecompressed;
+
++ // Paper start - Use Velocity cipher
++ @io.papermc.paper.annotation.DoNotUse
+ public CompressionDecoder(int threshold, boolean validateDecompressed) {
++ this(null, threshold, validateDecompressed);
++ }
++ public CompressionDecoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int threshold, boolean validateDecompressed) {
+ this.threshold = threshold;
+ this.validateDecompressed = validateDecompressed;
+- this.inflater = new Inflater();
++ this.inflater = compressor == null ? new Inflater() : null;
++ this.compressor = compressor;
++ // Paper end - Use Velocity cipher
+ }
+
+ @Override
+@@ -39,14 +47,42 @@ public class CompressionDecoder extends ByteToMessageDecoder {
+ }
+ }
+
++ if (inflater != null) { // Paper - Use Velocity cipher; fallback to vanilla inflater
+ this.setupInflaterInput(in);
+ ByteBuf byteBuf = this.inflate(context, i);
+ this.inflater.reset();
+ out.add(byteBuf);
++ return; // Paper - Use Velocity cipher
++ } // Paper - use velocity compression
++
++ // Paper start - Use Velocity cipher
++ int claimedUncompressedSize = i; // OBFHELPER
++ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(context.alloc(), this.compressor, in);
++ ByteBuf uncompressed = com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(context.alloc(), this.compressor, claimedUncompressedSize);
++ try {
++ this.compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize);
++ out.add(uncompressed);
++ in.clear();
++ } catch (Exception e) {
++ uncompressed.release();
++ throw e;
++ } finally {
++ compatibleIn.release();
++ }
++ // Paper end - Use Velocity cipher
+ }
+ }
+ }
+
++ // Paper start - Use Velocity cipher
++ @Override
++ public void handlerRemoved0(ChannelHandlerContext ctx) {
++ if (this.compressor != null) {
++ this.compressor.close();
++ }
++ }
++ // Paper end - Use Velocity cipher
++
+ private void setupInflaterInput(ByteBuf buffer) {
+ ByteBuffer byteBuffer;
+ if (buffer.nioBufferCount() > 0) {
+@@ -81,7 +117,13 @@ public class CompressionDecoder extends ByteToMessageDecoder {
+ }
+ }
+
+- public void setThreshold(int threshold, boolean validateDecompressed) {
++ // Paper start - Use Velocity cipher
++ public void setThreshold(com.velocitypowered.natives.compression.VelocityCompressor compressor, int threshold, boolean validateDecompressed) {
++ if (this.compressor == null && compressor != null) { // Only re-configure once. Re-reconfiguring would require closing the native compressor.
++ this.compressor = compressor;
++ this.inflater = null;
++ }
++ // Paper end - Use Velocity cipher
+ this.threshold = threshold;
+ this.validateDecompressed = validateDecompressed;
+ }
+diff --git a/net/minecraft/network/CompressionEncoder.java b/net/minecraft/network/CompressionEncoder.java
+index bc674b08a41d5529fe06c6d3f077051cf4138f73..ea8a894158c44c2e7943dea43ecd8e1f0075b18f 100644
+--- a/net/minecraft/network/CompressionEncoder.java
++++ b/net/minecraft/network/CompressionEncoder.java
+@@ -6,17 +6,31 @@ import io.netty.handler.codec.MessageToByteEncoder;
+ import java.util.zip.Deflater;
+
+ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
+- private final byte[] encodeBuf = new byte[8192];
++ @javax.annotation.Nullable private final byte[] encodeBuf; // Paper - Use Velocity cipher
++ @javax.annotation.Nullable // Paper - Use Velocity cipher
+ private final Deflater deflater;
++ @javax.annotation.Nullable private final com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper - Use Velocity cipher
+ private int threshold;
+
++ // Paper start - Use Velocity cipher
+ public CompressionEncoder(int threshold) {
++ this(null, threshold);
++ }
++ public CompressionEncoder(@javax.annotation.Nullable com.velocitypowered.natives.compression.VelocityCompressor compressor, int threshold) {
+ this.threshold = threshold;
+- this.deflater = new Deflater();
++ if (compressor == null) {
++ this.encodeBuf = new byte[8192];
++ this.deflater = new Deflater();
++ } else {
++ this.encodeBuf = null;
++ this.deflater = null;
++ }
++ this.compressor = compressor;
++ // Paper end - Use Velocity cipher
+ }
+
+ @Override
+- protected void encode(ChannelHandlerContext context, ByteBuf encodingByteBuf, ByteBuf byteBuf) {
++ protected void encode(ChannelHandlerContext context, ByteBuf encodingByteBuf, ByteBuf byteBuf) throws Exception { // Paper - Use Velocity cipher
+ int i = encodingByteBuf.readableBytes();
+ if (i > 8388608) {
+ throw new IllegalArgumentException("Packet too big (is " + i + ", should be less than 8388608)");
+@@ -25,6 +39,7 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
+ VarInt.write(byteBuf, 0);
+ byteBuf.writeBytes(encodingByteBuf);
+ } else {
++ if (this.deflater != null) { // Paper - Use Velocity cipher
+ byte[] bytes = new byte[i];
+ encodingByteBuf.readBytes(bytes);
+ VarInt.write(byteBuf, bytes.length);
+@@ -37,6 +52,17 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
+ }
+
+ this.deflater.reset();
++ // Paper start - Use Velocity cipher
++ return;
++ }
++
++ VarInt.write(byteBuf, i);
++ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(context.alloc(), this.compressor, encodingByteBuf);
++ try {
++ this.compressor.deflate(compatibleIn, byteBuf);
++ } finally {
++ compatibleIn.release();
++ }
+ }
+ }
+ }
+@@ -48,4 +74,31 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
+ public void setThreshold(int threshold) {
+ this.threshold = threshold;
+ }
++
++ // Paper start - Use Velocity cipher
++ @Override
++ protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception {
++ if (this.compressor != null) {
++ // We allocate bytes to be compressed plus 1 byte. This covers two cases:
++ //
++ // - Compression
++ // According to https://github.com/ebiggers/libdeflate/blob/master/libdeflate.h#L103,
++ // if the data compresses well (and we do not have some pathological case) then the maximum
++ // size the compressed size will ever be is the input size minus one.
++ // - Uncompressed
++ // This is fairly obvious - we will then have one more than the uncompressed size.
++ final int initialBufferSize = msg.readableBytes() + 1;
++ return com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(ctx.alloc(), this.compressor, initialBufferSize);
++ }
++
++ return super.allocateBuffer(ctx, msg, preferDirect);
++ }
++
++ @Override
++ public void handlerRemoved(ChannelHandlerContext ctx) {
++ if (this.compressor != null) {
++ this.compressor.close();
++ }
++ }
++ // Paper end - Use Velocity cipher
+ }
+diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
+index ad8f8428b75e37097487cdfbd0db2421ee4cbe37..208efae06c7c44f220d4192219a86ec55c98a2fe 100644
+--- a/net/minecraft/network/Connection.java
++++ b/net/minecraft/network/Connection.java
+@@ -772,11 +772,22 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
+ return connection;
+ }
+
+- public void setEncryptionKey(Cipher decryptingCipher, Cipher encryptingCipher) {
+- this.encrypted = true;
+- this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptingCipher));
+- this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptingCipher));
++ // Paper start - Use Velocity cipher
++ public void setEncryptionKey(javax.crypto.SecretKey key) throws net.minecraft.util.CryptException {
++ if (!this.encrypted) {
++ try {
++ com.velocitypowered.natives.encryption.VelocityCipher decryptionCipher = com.velocitypowered.natives.util.Natives.cipher.get().forDecryption(key);
++ com.velocitypowered.natives.encryption.VelocityCipher encryptionCipher = com.velocitypowered.natives.util.Natives.cipher.get().forEncryption(key);
++
++ this.encrypted = true;
++ this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher));
++ this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher));
++ } catch (java.security.GeneralSecurityException e) {
++ throw new net.minecraft.util.CryptException(e);
++ }
++ }
+ }
++ // Paper end - Use Velocity cipher
+
+ public boolean isEncrypted() {
+ return this.encrypted;
+@@ -815,16 +826,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
+ // Paper end - add proper async disconnect
+ public void setupCompression(int threshold, boolean validateDecompressed) {
+ if (threshold >= 0) {
++ com.velocitypowered.natives.compression.VelocityCompressor compressor = com.velocitypowered.natives.util.Natives.compress.get().create(io.papermc.paper.configuration.GlobalConfiguration.get().misc.compressionLevel.or(-1)); // Paper - Use Velocity cipher
+ if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder compressionDecoder) {
+- compressionDecoder.setThreshold(threshold, validateDecompressed);
++ compressionDecoder.setThreshold(compressor, threshold, validateDecompressed); // Paper - Use Velocity cipher
+ } else {
+- this.channel.pipeline().addAfter("splitter", "decompress", new CompressionDecoder(threshold, validateDecompressed));
++ this.channel.pipeline().addAfter("splitter", "decompress", new CompressionDecoder(compressor, threshold, validateDecompressed)); // Paper - Use Velocity cipher
+ }
+
+ if (this.channel.pipeline().get("compress") instanceof CompressionEncoder compressionEncoder) {
+ compressionEncoder.setThreshold(threshold);
+ } else {
+- this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(threshold));
++ this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressor, threshold)); // Paper - Use Velocity cipher
+ }
+ this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners
+ } else {
+diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java
+index 7de11ba404f0b60e7f7b7c16954811a343688219..bd07e6a5aa1883786d789ea71711a0c0c0a95c26 100644
+--- a/net/minecraft/server/network/ServerConnectionListener.java
++++ b/net/minecraft/server/network/ServerConnectionListener.java
+@@ -108,6 +108,10 @@ public class ServerConnectionListener {
+ LOGGER.warn("Using HAProxy, please ensure the server port is adequately firewalled.");
+ }
+ // Paper end - Warn people with console access that HAProxy is in use.
++ // Paper start - Use Velocity cipher
++ ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.compress.getLoadedVariant() + " compression from Velocity.");
++ ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.cipher.getLoadedVariant() + " cipher from Velocity.");
++ // Paper end - Use Velocity cipher
+
+ this.channels
+ .add(
+diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+index bb28453d230921d662ed69c8dd48021f428ef060..6689aeacf50d1498e8d23cce696fb4fecbd1cf39 100644
+--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
++++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+@@ -276,11 +276,9 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
+ }
+
+ SecretKey secretKey = packet.getSecretKey(_private);
+- Cipher cipher = Crypt.getCipher(2, secretKey);
+- Cipher cipher1 = Crypt.getCipher(1, secretKey);
+ string = new BigInteger(Crypt.digestData("", this.server.getKeyPair().getPublic(), secretKey)).toString(16);
+ this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING;
+- this.connection.setEncryptionKey(cipher, cipher1);
++ this.connection.setEncryptionKey(secretKey); // Paper - Use Velocity cipher
+ } catch (CryptException var7) {
+ throw new IllegalStateException("Protocol error", var7);
+ }