aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/1018-Use-Velocity-compression-and-cipher-natives.patch
blob: ed8b42ddf61d5f5aaf47c5a893b0923aba3163a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrew Steinborn <git@steinborn.me>
Date: Mon, 26 Jul 2021 02:15:17 -0400
Subject: [PATCH] Use Velocity compression and cipher natives


diff --git a/build.gradle.kts b/build.gradle.kts
index 7c563ef33d12b227856e65392905bffa5289285a..376e8983fdfdbb6c3e5fd8ad0f6a05e655b622bf 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -40,6 +40,11 @@ dependencies {
     runtimeOnly("org.xerial:sqlite-jdbc:3.42.0.1")
     runtimeOnly("com.mysql:mysql-connector-j:8.2.0")
     runtimeOnly("com.lmax:disruptor:3.4.4") // Paper
+    // Paper start - Use Velocity cipher
+    implementation("com.velocitypowered:velocity-native:3.1.2-SNAPSHOT") {
+        isTransitive = false
+    }
+    // Paper end - Use Velocity cipher
 
     runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6")
     runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
diff --git a/src/main/java/net/minecraft/network/CipherDecoder.java b/src/main/java/net/minecraft/network/CipherDecoder.java
index 778beb445eac5769b9e4e07b4d1294c50ae2602b..7b895b6a626da6297f07582e96d98ecfb6c8c951 100644
--- a/src/main/java/net/minecraft/network/CipherDecoder.java
+++ b/src/main/java/net/minecraft/network/CipherDecoder.java
@@ -7,13 +7,29 @@ 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
     }
 
     protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
-        list.add(this.cipher.decipher(channelHandlerContext, byteBuf));
+        // Paper start - Use Velocity cipher
+        ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), cipher, byteBuf);
+        try {
+            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) throws Exception {
+        cipher.close();
+    }
+    // Paper end - Use Velocity cipher
 }
diff --git a/src/main/java/net/minecraft/network/CipherEncoder.java b/src/main/java/net/minecraft/network/CipherEncoder.java
index 0f3d502a9680006bcdcd7d272240a2e5c3b46790..ffa1c48585fbbc1d30826d435043527f6183a3ee 100644
--- a/src/main/java/net/minecraft/network/CipherEncoder.java
+++ b/src/main/java/net/minecraft/network/CipherEncoder.java
@@ -4,15 +4,32 @@ import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.MessageToByteEncoder;
 import javax.crypto.Cipher;
+import java.util.List;
 
-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
     }
 
-    protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception {
-        this.cipher.encipher(byteBuf, byteBuf2);
+    protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
+        // Paper start - Use Velocity cipher
+        ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), cipher, byteBuf);
+        try {
+            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) throws Exception {
+        cipher.close();
+    }
+    // Paper end - Use Velocity cipher
 }
diff --git a/src/main/java/net/minecraft/network/CompressionDecoder.java b/src/main/java/net/minecraft/network/CompressionDecoder.java
index 2758c257cb4e2b0497bd9243c635f8fe3dbc414c..2763052eb2d5b8eb432022ab00a417976f4b2927 100644
--- a/src/main/java/net/minecraft/network/CompressionDecoder.java
+++ b/src/main/java/net/minecraft/network/CompressionDecoder.java
@@ -13,13 +13,20 @@ public class CompressionDecoder extends ByteToMessageDecoder {
     public static final int MAXIMUM_COMPRESSED_LENGTH = 2097152;
     public static final int MAXIMUM_UNCOMPRESSED_LENGTH = 8388608;
     private final Inflater inflater;
+    private final com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper - Use Velocity cipher
     private int threshold;
     private boolean validateDecompressed;
 
+    // Paper start - Use Velocity cipher
     public CompressionDecoder(int compressionThreshold, boolean rejectsBadPackets) {
+        this(null, compressionThreshold, rejectsBadPackets);
+    }
+    public CompressionDecoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold, boolean rejectsBadPackets) {
         this.threshold = compressionThreshold;
         this.validateDecompressed = rejectsBadPackets;
-        this.inflater = new Inflater();
+        this.inflater = compressor == null ? new Inflater() : null;
+        this.compressor = compressor;
+        // Paper end - Use Velocity cipher
     }
 
     protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
@@ -38,14 +45,42 @@ public class CompressionDecoder extends ByteToMessageDecoder {
                     }
                 }
 
+                if (inflater != null) { // Paper - Use Velocity cipher; fallback to vanilla inflater
                 this.setupInflaterInput(byteBuf);
                 ByteBuf byteBuf2 = this.inflate(channelHandlerContext, i);
                 this.inflater.reset();
                 list.add(byteBuf2);
+                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(channelHandlerContext.alloc(), this.compressor, byteBuf);
+                ByteBuf uncompressed = com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(channelHandlerContext.alloc(), this.compressor, claimedUncompressedSize);
+                try {
+                    this.compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize);
+                    list.add(uncompressed);
+                    byteBuf.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) throws Exception {
+        if (this.compressor != null) {
+            this.compressor.close();
+        }
+    }
+    // Paper end - Use Velocity cipher
+
     private void setupInflaterInput(ByteBuf buf) {
         ByteBuffer byteBuffer;
         if (buf.nioBufferCount() > 0) {
diff --git a/src/main/java/net/minecraft/network/CompressionEncoder.java b/src/main/java/net/minecraft/network/CompressionEncoder.java
index 859af8c845bae9781a62fa4acae56c6e2d449e10..f67f59f287d9a5cdd685b6b56ed1daf3f091e099 100644
--- a/src/main/java/net/minecraft/network/CompressionEncoder.java
+++ b/src/main/java/net/minecraft/network/CompressionEncoder.java
@@ -6,21 +6,36 @@ import io.netty.handler.codec.MessageToByteEncoder;
 import java.util.zip.Deflater;
 
 public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
-    private final byte[] encodeBuf = new byte[8192];
+    private final byte[] encodeBuf; // Paper - Use Velocity cipher
     private final Deflater deflater;
+    private final com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper - Use Velocity cipher
     private int threshold;
 
+    // Paper start - Use Velocity cipher
     public CompressionEncoder(int compressionThreshold) {
+        this(null, compressionThreshold);
+    }
+    public CompressionEncoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold) {
         this.threshold = compressionThreshold;
-        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
     }
 
-    protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) {
+    protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception { // Paper - Use Velocity cipher
         int i = byteBuf.readableBytes();
         if (i < this.threshold) {
             VarInt.write(byteBuf2, 0);
             byteBuf2.writeBytes(byteBuf);
         } else {
+            // Paper start - Use Velocity cipher
+            if (this.deflater != null) {
             byte[] bs = new byte[i];
             byteBuf.readBytes(bs);
             VarInt.write(byteBuf2, bs.length);
@@ -33,10 +48,48 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
             }
 
             this.deflater.reset();
+                return;
+            }
+
+            VarInt.write(byteBuf2, i);
+            ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), this.compressor, byteBuf);
+            try {
+                this.compressor.deflate(compatibleIn, byteBuf2);
+            } finally {
+                compatibleIn.release();
+            }
+            // Paper end - Use Velocity cipher
         }
 
     }
 
+    // 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.
+            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) throws Exception {
+        if (this.compressor != null) {
+            this.compressor.close();
+        }
+    }
+    // Paper end - Use Velocity cipher
+
     public int getThreshold() {
         return this.threshold;
     }
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index 7f2aa5e17fe675f3404d67b1794d2ca68b188eb9..fff375fd50fa1a804636a92ded1ae55cff42977d 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -734,11 +734,28 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
         return networkmanager;
     }
 
-    public void setEncryptionKey(Cipher decryptionCipher, Cipher encryptionCipher) {
-        this.encrypted = true;
-        this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher));
-        this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher));
+    // Paper start - Use Velocity cipher
+//    public void setEncryptionKey(Cipher decryptionCipher, Cipher encryptionCipher) {
+//        this.encrypted = true;
+//        this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher));
+//        this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher));
+//    }
+
+    public void setupEncryption(javax.crypto.SecretKey key) throws net.minecraft.util.CryptException {
+        if (!this.encrypted) {
+            try {
+                com.velocitypowered.natives.encryption.VelocityCipher decryption = com.velocitypowered.natives.util.Natives.cipher.get().forDecryption(key);
+                com.velocitypowered.natives.encryption.VelocityCipher encryption = com.velocitypowered.natives.util.Natives.cipher.get().forEncryption(key);
+
+                this.encrypted = true;
+                this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryption));
+                this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryption));
+            } catch (java.security.GeneralSecurityException e) {
+                throw new net.minecraft.util.CryptException(e);
+            }
+        }
     }
+    // Paper end - Use Velocity cipher
 
     public boolean isEncrypted() {
         return this.encrypted;
@@ -771,16 +788,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
 
     public void setupCompression(int compressionThreshold, boolean rejectsBadPackets) {
         if (compressionThreshold >= 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) this.channel.pipeline().get("decompress")).setThreshold(compressionThreshold, rejectsBadPackets);
             } else {
-                this.channel.pipeline().addBefore("decoder", "decompress", new CompressionDecoder(compressionThreshold, rejectsBadPackets));
+                this.channel.pipeline().addBefore("decoder", "decompress", new CompressionDecoder(compressor, compressionThreshold, rejectsBadPackets)); // Paper - Use Velocity cipher
             }
 
             if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) {
                 ((CompressionEncoder) this.channel.pipeline().get("compress")).setThreshold(compressionThreshold);
             } else {
-                this.channel.pipeline().addBefore("encoder", "compress", new CompressionEncoder(compressionThreshold));
+                this.channel.pipeline().addBefore("encoder", "compress", new CompressionEncoder(compressor, compressionThreshold)); // 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/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
index a4a29a7ea0035ecf4c61ee8547a9eb24acb667d0..586521a2cbb1d4dcfb912029f65e4363ec7674a7 100644
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
@@ -106,6 +106,11 @@ public class ServerConnectionListener {
                 ServerConnectionListener.LOGGER.info("Using default channel type");
             }
 
+            // 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(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer<Channel>() {
                 protected void initChannel(Channel channel) {
                     Connection.setInitialProtocolAttributes(channel);
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index b8d8f14c30786321949901ca5184c43bee716355..c5fa9f4d28f9a7f64a50a902ee5e631bfc00119c 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -235,12 +235,14 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
             }
 
             SecretKey secretkey = packet.getSecretKey(privatekey);
-            Cipher cipher = Crypt.getCipher(2, secretkey);
-            Cipher cipher1 = Crypt.getCipher(1, secretkey);
+            // Paper start - Use Velocity cipher
+//            Cipher cipher = Crypt.getCipher(2, secretkey);
+//            Cipher cipher1 = Crypt.getCipher(1, secretkey);
+            // Paper end - Use Velocity cipher
 
             s = (new BigInteger(Crypt.digestData("", this.server.getKeyPair().getPublic(), secretkey))).toString(16);
             this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING;
-            this.connection.setEncryptionKey(cipher, cipher1);
+            this.connection.setupEncryption(secretkey); // Paper - Use Velocity cipher
         } catch (CryptException cryptographyexception) {
             throw new IllegalStateException("Protocol error", cryptographyexception);
         }