From 0af11d75c33ea37ef6cb4d01596c19f57f22ced1 Mon Sep 17 00:00:00 2001 From: Graham Date: Mon, 31 Aug 2020 09:28:09 +0100 Subject: [PATCH] Add flag to disable encryption of uncompressed containers by default These don't work in the 550 client due to a bug. Signed-off-by: Graham --- .../java/dev/openrs2/cache/Js5Compression.kt | 39 +++++++++++++++---- .../dev/openrs2/cache/Js5CompressionTest.kt | 21 ++++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/cache/src/main/java/dev/openrs2/cache/Js5Compression.kt b/cache/src/main/java/dev/openrs2/cache/Js5Compression.kt index d110b4e2..3b6d40cf 100644 --- a/cache/src/main/java/dev/openrs2/cache/Js5Compression.kt +++ b/cache/src/main/java/dev/openrs2/cache/Js5Compression.kt @@ -49,14 +49,39 @@ public object Js5Compression { } } - public fun compressBest(input: ByteBuf, enableLzma: Boolean = false, key: XteaKey = XteaKey.ZERO): ByteBuf { - var best = compress(input.slice(), Js5CompressionType.NONE, key) - try { - for (type in Js5CompressionType.values()) { - if (type == Js5CompressionType.NONE || (type == Js5CompressionType.LZMA && !enableLzma)) { - continue - } + public fun compressBest( + input: ByteBuf, + enableLzma: Boolean = false, + enableUncompressedEncryption: Boolean = false, + key: XteaKey = XteaKey.ZERO + ): ByteBuf { + val types = mutableListOf(Js5CompressionType.BZIP2, Js5CompressionType.GZIP) + if (enableLzma) { + types += Js5CompressionType.LZMA + } + if (enableUncompressedEncryption || key.isZero) { + /* + * The 550 client doesn't strip the 2 byte version trailer before + * passing a group to the XTEA decryption function. This causes the + * last block to be incorrectly decrypt in many cases (depending + * on the length of the group mod the XTEA block size). + * + * This doesn't cause any problems with the client's GZIP/BZIP2 + * implementations, as the last block is always part of the trailer + * and the trailer isn't checked. However, it would corrupt the + * last block of an unencrypted group. + * + * TODO(gpe): are there any clients with LZMA support _and_ the + * decryption bug? Could the enableLzma flag be re-used for + * enableNoneWithKey? Or should LZMA also be disabled in clients + * with the decryption bug? + */ + types += Js5CompressionType.NONE + } + var best = compress(input.slice(), types.first(), key) + try { + for (type in types.drop(1)) { compress(input.slice(), type, key).use { output -> if (output.readableBytes() < best.readableBytes()) { best.release() diff --git a/cache/src/test/java/dev/openrs2/cache/Js5CompressionTest.kt b/cache/src/test/java/dev/openrs2/cache/Js5CompressionTest.kt index 2151283d..723e4fd1 100644 --- a/cache/src/test/java/dev/openrs2/cache/Js5CompressionTest.kt +++ b/cache/src/test/java/dev/openrs2/cache/Js5CompressionTest.kt @@ -234,6 +234,27 @@ object Js5CompressionTest { } } + @Test + fun testUncompressedEncryption() { + Unpooled.wrappedBuffer("OpenRS2".toByteArray()).use { buf -> + Js5Compression.compressBest(buf.slice()).use { compressed -> + assertEquals(Js5CompressionType.NONE.ordinal, compressed.getUnsignedByte(0).toInt()) + } + + Js5Compression.compressBest(buf.slice(), enableUncompressedEncryption = true).use { compressed -> + assertEquals(Js5CompressionType.NONE.ordinal, compressed.getUnsignedByte(0).toInt()) + } + + Js5Compression.compressBest(buf.slice(), key = KEY).use { compressed -> + assertNotEquals(Js5CompressionType.NONE.ordinal, compressed.getUnsignedByte(0).toInt()) + } + + Js5Compression.compressBest(buf.slice(), key = KEY, enableUncompressedEncryption = true).use { compressed -> + assertEquals(Js5CompressionType.NONE.ordinal, compressed.getUnsignedByte(0).toInt()) + } + } + } + private fun read(name: String): ByteBuf { Js5CompressionTest::class.java.getResourceAsStream("compression/$name").use { input -> return Unpooled.wrappedBuffer(input.readAllBytes())