From 2c9a6505c080c6dbdd081f394780f3687ff948a8 Mon Sep 17 00:00:00 2001 From: Manevolent Date: Fri, 27 Jul 2018 09:54:01 -0400 Subject: [PATCH] More tests; I identified two issues. First, the temp key generation was wrong and the clientek would have been wrong. Second, the clientek packet ID is incorrect. It needs to start at 1. --- .../Ed25519Ref10/GroupOperations.java | 15 ++++- .../manevolent/ts3j/identity/Identity.java | 1 - .../manevolent/ts3j/license/License.java | 2 - .../manevolent/ts3j/protocol/Packet.java | 7 ++ .../protocol/packet/PacketBody8Init1.java | 6 -- .../local/LocalClientHandlerConnecting.java | 2 +- .../transformation/PacketTransformation.java | 3 + .../client/AbstractTeamspeakClientSocket.java | 66 ++++++++++++------- .../github/manevolent/ts3j/util/Ts3Crypt.java | 10 +-- .../manevolent/ts3j/EncryptionTest.java | 4 +- .../manevolent/ts3j/ServerConnectionTest.java | 17 ++--- 11 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/main/java/Punisher/NaCl/Internal/Ed25519Ref10/GroupOperations.java b/src/main/java/Punisher/NaCl/Internal/Ed25519Ref10/GroupOperations.java index 2a0303b..26393a9 100644 --- a/src/main/java/Punisher/NaCl/Internal/Ed25519Ref10/GroupOperations.java +++ b/src/main/java/Punisher/NaCl/Internal/Ed25519Ref10/GroupOperations.java @@ -1065,6 +1065,19 @@ public class GroupOperations FieldOperations.fe_mul(x, h.X, recip); FieldOperations.fe_mul(y, h.Y, recip); FieldOperations.fe_tobytes(s, offset, y); - //s[offset + 31] ^= (byte) (FieldOperations.fe_isnegative(x) << 7); + } + + public static void ge_p3_tobytes_negate(byte[] s, int offset, GroupElementP3 h) + { + FieldElement recip = new FieldElement(); + FieldElement x = new FieldElement(); + FieldElement y = new FieldElement(); + + FieldOperations.fe_invert(recip, h.Z); + FieldOperations.fe_mul(x, h.X, recip); + FieldOperations.fe_mul(y, h.Y, recip); + FieldOperations.fe_tobytes(s, offset, y); + + s[offset + 31] ^= (byte) (FieldOperations.fe_isnegative(x) << 7); } } diff --git a/src/main/java/com/github/manevolent/ts3j/identity/Identity.java b/src/main/java/com/github/manevolent/ts3j/identity/Identity.java index 8e89a87..6f49140 100644 --- a/src/main/java/com/github/manevolent/ts3j/identity/Identity.java +++ b/src/main/java/com/github/manevolent/ts3j/identity/Identity.java @@ -115,7 +115,6 @@ public class Identity { return getLeadingZeroBits(outHash); } - // GOOD private static int getLeadingZeroBits(byte[] data) { int curr = 0; int i ; diff --git a/src/main/java/com/github/manevolent/ts3j/license/License.java b/src/main/java/com/github/manevolent/ts3j/license/License.java index 160e77a..d2498e5 100644 --- a/src/main/java/com/github/manevolent/ts3j/license/License.java +++ b/src/main/java/com/github/manevolent/ts3j/license/License.java @@ -219,8 +219,6 @@ public class License { byte[] final_ = new byte[32]; GroupOperations.ge_p3_tobytes(final_, 0, r2); - //final_[1] ^= 0x80; - return final_; } diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/Packet.java b/src/main/java/com/github/manevolent/ts3j/protocol/Packet.java index 8c1ce48..a1d43d9 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/Packet.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/Packet.java @@ -20,6 +20,13 @@ public final class Packet { this.role = role; } + public Packet(ProtocolRole role, PacketHeader header) { + if (role == null) throw new NullPointerException("role"); + + this.role = role; + this.header = header; + } + public ProtocolRole getRole() { return role; } diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBody8Init1.java b/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBody8Init1.java index 559450d..2d58b35 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBody8Init1.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/packet/PacketBody8Init1.java @@ -19,12 +19,6 @@ public class PacketBody8Init1 extends PacketBody { super(INIT1, role); } - @Override - public void setHeaderValues(PacketHeader header) { - header.setPacketFlag(HeaderFlag.UNENCRYPTED, true); - header.setPacketId((short)101); - } - public byte[] getVersion() { return version; } diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/local/LocalClientHandlerConnecting.java b/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/local/LocalClientHandlerConnecting.java index 1a3ed77..c0e2149 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/local/LocalClientHandlerConnecting.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/local/LocalClientHandlerConnecting.java @@ -91,7 +91,7 @@ public class LocalClientHandlerConnecting extends LocalClientHandler { // CITE: https://github.com/Splamy/TS3AudioBot/blob/master/TS3Client/Full/Ts3Crypt.cs // Prepare solution if (serverReplyStep3.getLevel() < 0 || serverReplyStep3.getLevel() > 1_000_000) - throw new IllegalArgumentException("RSA challange level is not within an acceptable range"); + throw new IllegalArgumentException("RSA challenge level is not within an acceptable range"); BigInteger x = new BigInteger(1, serverReplyStep3.getX()); BigInteger n = new BigInteger(1, serverReplyStep3.getN()); diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java b/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java index ff78856..66ad968 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java @@ -104,6 +104,9 @@ public class PacketTransformation { ByteBuffer outputBuffer = ByteBuffer.allocate(MAC_LEN + headerWithoutMac.length + (len - MAC_LEN)); + // Copy the mac to the packet header + System.arraycopy(result, len - MAC_LEN, packet.getHeader().getMac(), 0, MAC_LEN); + // MAC outputBuffer.put(result, len - MAC_LEN, MAC_LEN); diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java index f87e793..c2f18f6 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java @@ -10,15 +10,13 @@ import com.github.manevolent.ts3j.protocol.client.ClientConnectionState; import com.github.manevolent.ts3j.protocol.header.ClientPacketHeader; import com.github.manevolent.ts3j.protocol.header.HeaderFlag; import com.github.manevolent.ts3j.protocol.header.PacketHeader; -import com.github.manevolent.ts3j.protocol.packet.PacketBody; -import com.github.manevolent.ts3j.protocol.packet.PacketBody6Ack; -import com.github.manevolent.ts3j.protocol.packet.PacketBodyFragment; -import com.github.manevolent.ts3j.protocol.packet.PacketBodyType; +import com.github.manevolent.ts3j.protocol.packet.*; import com.github.manevolent.ts3j.protocol.packet.handler.PacketHandler; import com.github.manevolent.ts3j.protocol.packet.handler.local.LocalClientHandler; import com.github.manevolent.ts3j.protocol.packet.transformation.DefaultPacketTransformation; import com.github.manevolent.ts3j.protocol.packet.transformation.PacketTransformation; import com.github.manevolent.ts3j.protocol.socket.AbstractTeamspeakSocket; +import com.github.manevolent.ts3j.util.QuickLZ; import com.github.manevolent.ts3j.util.Ts3Crypt; import com.github.manevolent.ts3j.util.Ts3Debugging; @@ -213,7 +211,7 @@ public abstract class AbstractTeamspeakClientSocket // Set header values packet.getBody().setHeaderValues(packet.getHeader()); - if (packet.getHeader().getType() != PacketBodyType.INIT1) { + if (packet.getHeader().getType() != PacketBodyType.INIT1 && packet.getHeader().getType() != PacketBodyType.ACK) { packetId++; packetId = packetId & 0x0000FFFF; @@ -226,20 +224,35 @@ public abstract class AbstractTeamspeakClientSocket packet.getHeader().setPacketId(packetId); } - if (packet.getHeader().getType() == PacketBodyType.COMMAND || - packet.getHeader().getType() == PacketBodyType.COMMAND_LOW) - packet.getHeader().setPacketFlag(HeaderFlag.NEW_PROTOCOL, true); + switch (packet.getHeader().getType()) { + case INIT1: + packet.getHeader().setPacketFlag(HeaderFlag.UNENCRYPTED, true); + packet.getHeader().setPacketId((short)101); + break; + case COMMAND: + case COMMAND_LOW: + packet.getHeader().setPacketFlag(HeaderFlag.NEW_PROTOCOL, true); + break; + } if (packet.getSize() > 500) { - if (!packet.getHeader().getType().isSplittable()) - throw new IllegalArgumentException("packet too large: " + packet.getSize()); - - // Split int totalSize = packet.getBody().getSize(); ByteBuffer outputBuffer = ByteBuffer.allocate(totalSize); packet.getBody().write(outputBuffer); + byte[] compressed = QuickLZ.compress(outputBuffer.array(), 1); + packet.getHeader().setPacketFlag(HeaderFlag.COMPRESSED, true); + packet.setBody(new PacketBodyCompressed(packet.getHeader().getType(), packet.getRole(), compressed)); + + if (packet.getSize() <= 500) { + writePacketIntl(packet); + return; + } + + if (!packet.getHeader().getType().isSplittable()) + throw new IllegalArgumentException("packet too large: " + packet.getSize()); + for (int offs = 0; offs < totalSize;) { int flush = Math.min(500 - packet.getHeader().getSize(), totalSize - offs); boolean first = offs == 0; @@ -391,22 +404,31 @@ public abstract class AbstractTeamspeakClientSocket if (fragment) { Ts3Debugging.debug("[PROTOCOL] READ " + networkPacket.getHeader().getType().name() + " fragment"); - packet.setBody( - new PacketBodyFragment( - networkPacket.getHeader().getType(), - getRole().getIn() - ) - ); + packet.setBody(new PacketBodyFragment(networkPacket.getHeader().getType(), getRole().getIn())); } else { + if (packet.getHeader().getPacketFlag(HeaderFlag.COMPRESSED)) + packet.setBody(new PacketBodyCompressed(networkPacket.getHeader().getType(), getRole().getIn())); + Ts3Debugging.debug("[PROTOCOL] READ " + networkPacket.getHeader().getType().name()); } - // Compression? - // TODO - - // Read packet body + // Read raw packet body packet.readBody(packetBuffer); + // Finally, handle compressed bodies + if (packet.getBody() instanceof PacketBodyCompressed) { + byte[] decompressed = QuickLZ.decompress(((PacketBodyCompressed) packet.getBody()).getCompressed()); + + packetBuffer = ByteBuffer.wrap(decompressed); + + packet = new Packet(packet.getRole(), packet.getHeader()); + + packet.readBody(packetBuffer); + + Ts3Debugging.debug("[PROTOCOL] DECOMPRESS " + networkPacket.getHeader().getType().name()); + } + + // Return to parent handler return packet; } diff --git a/src/main/java/com/github/manevolent/ts3j/util/Ts3Crypt.java b/src/main/java/com/github/manevolent/ts3j/util/Ts3Crypt.java index c92d31a..a8e66ae 100644 --- a/src/main/java/com/github/manevolent/ts3j/util/Ts3Crypt.java +++ b/src/main/java/com/github/manevolent/ts3j/util/Ts3Crypt.java @@ -217,21 +217,21 @@ public final class Ts3Crypt { public static Pair generateKeypair() { byte[] privateKey = new byte[32]; new SecureRandom().nextBytes(privateKey); + return generateKeypair(privateKey); + } + public static Pair generateKeypair(byte[] privateKey) { ScalarOperations.sc_clamp(privateKey, 0); GroupElementP3 A = new GroupElementP3(); GroupOperations.ge_scalarmult_base(A, privateKey, 0); byte[] publicKey = new byte[32]; - GroupOperations.ge_p3_tobytes(publicKey, 0, A); - - Ts3Debugging.debug(publicKey); - Ts3Debugging.debug(privateKey); + GroupOperations.ge_p3_tobytes_negate(publicKey, 0, A); return new Pair<>(publicKey, privateKey); } - + public static final class SecureChannelParameters { private final byte[] fakeSignature; private final byte[] ivStruct; diff --git a/src/test/java/com/github/manevolent/ts3j/EncryptionTest.java b/src/test/java/com/github/manevolent/ts3j/EncryptionTest.java index 12a283f..c1c19f7 100644 --- a/src/test/java/com/github/manevolent/ts3j/EncryptionTest.java +++ b/src/test/java/com/github/manevolent/ts3j/EncryptionTest.java @@ -13,6 +13,7 @@ import javafx.util.Pair; import junit.framework.TestCase; import java.math.BigInteger; +import java.nio.ByteBuffer; import java.util.Base64; public class EncryptionTest extends TestCase { @@ -51,8 +52,7 @@ public class EncryptionTest extends TestCase { packet.setBody(new PacketBody2Command(ProtocolRole.CLIENT, "clientinit client_nickname=TestClient client_version=3.1.8\\s[Build:\\s1516614607] client_platform=Windows client_input_hardware=1 client_output_hardware=1 client_default_channel= client_default_channel_password= client_server_password=QL0AFWMIX8NRZTKeof9cXsvbvu8= client_meta_data= client_version_sign=gDEgQf\\/BiOQZdAheKccM1XWcMUj2OUQqt75oFuvF2c0MQMXyv88cZQdUuckKbcBRp7RpmLInto4PIgd7mPO7BQ== client_key_offset=6199 client_nickname_phonetic= client_default_token= hwid=+LyYqbDqOvJJpN5pdAbF8\\/v5kZ0=")); byte[] packetBytes = transformation.encrypt(packet).array(); - - Ts3Debugging.debug(Base64.getEncoder().encode(packetBytes)); + transformation.decrypt(header, ByteBuffer.wrap(packetBytes), packet.getBody().getSize()); } } diff --git a/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java b/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java index 4c8f339..4e18262 100644 --- a/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java +++ b/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java @@ -10,20 +10,19 @@ import java.math.BigInteger; import java.net.InetSocketAddress; import java.util.Base64; -public class ServerConnectionTest extends TestCase { - public ServerConnectionTest() { - super("ServerConnectionTest"); - } +import static org.junit.Assert.assertEquals; - public void testParser() throws Exception { +public class ServerConnectionTest { + public static void main(String[] args) throws Exception { try { - LocalIdentity localIdentity = LocalIdentity.load( + /**LocalIdentity localIdentity = LocalIdentity.load( Ts3Crypt.decodePublicKey(Base64.getDecoder() .decode("MEsDAgcAAgEgAiBpPRbTliVt9KxtIz8saYdwcnNgcwaKLbKYSpDNO87u9gIgSWWPKcSJ9P6VZKJfRdpWwcfMdJv+NA9/hXUtz1uwRVI=")), new BigInteger(Base64.getDecoder().decode("Tj6YXM3qyRv8n25L2pH+OEJnRUl4auQf8+znjYrOmWU=")), 2294, 2295 - ); + );**/ + LocalIdentity localIdentity = LocalIdentity.generateNew(10); LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket(); @@ -41,8 +40,4 @@ public class ServerConnectionTest extends TestCase { ex.printStackTrace(); } } - - public static void main(String[] args) throws Exception { - new ServerConnectionTest().testParser(); - } }