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.

This commit is contained in:
Manevolent
2018-07-27 09:54:01 -04:00
parent 5cdedba51c
commit 2c9a6505c0
11 changed files with 82 additions and 51 deletions
@@ -1065,6 +1065,19 @@ public class GroupOperations
FieldOperations.fe_mul(x, h.X, recip); FieldOperations.fe_mul(x, h.X, recip);
FieldOperations.fe_mul(y, h.Y, recip); FieldOperations.fe_mul(y, h.Y, recip);
FieldOperations.fe_tobytes(s, offset, y); 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);
} }
} }
@@ -115,7 +115,6 @@ public class Identity {
return getLeadingZeroBits(outHash); return getLeadingZeroBits(outHash);
} }
// GOOD
private static int getLeadingZeroBits(byte[] data) { private static int getLeadingZeroBits(byte[] data) {
int curr = 0; int curr = 0;
int i ; int i ;
@@ -219,8 +219,6 @@ public class License {
byte[] final_ = new byte[32]; byte[] final_ = new byte[32];
GroupOperations.ge_p3_tobytes(final_, 0, r2); GroupOperations.ge_p3_tobytes(final_, 0, r2);
//final_[1] ^= 0x80;
return final_; return final_;
} }
@@ -20,6 +20,13 @@ public final class Packet {
this.role = role; 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() { public ProtocolRole getRole() {
return role; return role;
} }
@@ -19,12 +19,6 @@ public class PacketBody8Init1 extends PacketBody {
super(INIT1, role); super(INIT1, role);
} }
@Override
public void setHeaderValues(PacketHeader header) {
header.setPacketFlag(HeaderFlag.UNENCRYPTED, true);
header.setPacketId((short)101);
}
public byte[] getVersion() { public byte[] getVersion() {
return version; return version;
} }
@@ -91,7 +91,7 @@ public class LocalClientHandlerConnecting extends LocalClientHandler {
// CITE: https://github.com/Splamy/TS3AudioBot/blob/master/TS3Client/Full/Ts3Crypt.cs // CITE: https://github.com/Splamy/TS3AudioBot/blob/master/TS3Client/Full/Ts3Crypt.cs
// Prepare solution // Prepare solution
if (serverReplyStep3.getLevel() < 0 || serverReplyStep3.getLevel() > 1_000_000) 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 x = new BigInteger(1, serverReplyStep3.getX());
BigInteger n = new BigInteger(1, serverReplyStep3.getN()); BigInteger n = new BigInteger(1, serverReplyStep3.getN());
@@ -104,6 +104,9 @@ public class PacketTransformation {
ByteBuffer outputBuffer = ByteBuffer.allocate(MAC_LEN + headerWithoutMac.length + (len - MAC_LEN)); 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 // MAC
outputBuffer.put(result, len - MAC_LEN, MAC_LEN); outputBuffer.put(result, len - MAC_LEN, MAC_LEN);
@@ -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.ClientPacketHeader;
import com.github.manevolent.ts3j.protocol.header.HeaderFlag; import com.github.manevolent.ts3j.protocol.header.HeaderFlag;
import com.github.manevolent.ts3j.protocol.header.PacketHeader; import com.github.manevolent.ts3j.protocol.header.PacketHeader;
import com.github.manevolent.ts3j.protocol.packet.PacketBody; import com.github.manevolent.ts3j.protocol.packet.*;
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.handler.PacketHandler; 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.handler.local.LocalClientHandler;
import com.github.manevolent.ts3j.protocol.packet.transformation.DefaultPacketTransformation; import com.github.manevolent.ts3j.protocol.packet.transformation.DefaultPacketTransformation;
import com.github.manevolent.ts3j.protocol.packet.transformation.PacketTransformation; import com.github.manevolent.ts3j.protocol.packet.transformation.PacketTransformation;
import com.github.manevolent.ts3j.protocol.socket.AbstractTeamspeakSocket; 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.Ts3Crypt;
import com.github.manevolent.ts3j.util.Ts3Debugging; import com.github.manevolent.ts3j.util.Ts3Debugging;
@@ -213,7 +211,7 @@ public abstract class AbstractTeamspeakClientSocket
// Set header values // Set header values
packet.getBody().setHeaderValues(packet.getHeader()); 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 = packetId & 0x0000FFFF; packetId = packetId & 0x0000FFFF;
@@ -226,20 +224,35 @@ public abstract class AbstractTeamspeakClientSocket
packet.getHeader().setPacketId(packetId); packet.getHeader().setPacketId(packetId);
} }
if (packet.getHeader().getType() == PacketBodyType.COMMAND || switch (packet.getHeader().getType()) {
packet.getHeader().getType() == PacketBodyType.COMMAND_LOW) case INIT1:
packet.getHeader().setPacketFlag(HeaderFlag.NEW_PROTOCOL, true); 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.getSize() > 500) {
if (!packet.getHeader().getType().isSplittable())
throw new IllegalArgumentException("packet too large: " + packet.getSize());
// Split
int totalSize = packet.getBody().getSize(); int totalSize = packet.getBody().getSize();
ByteBuffer outputBuffer = ByteBuffer.allocate(totalSize); ByteBuffer outputBuffer = ByteBuffer.allocate(totalSize);
packet.getBody().write(outputBuffer); 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;) { for (int offs = 0; offs < totalSize;) {
int flush = Math.min(500 - packet.getHeader().getSize(), totalSize - offs); int flush = Math.min(500 - packet.getHeader().getSize(), totalSize - offs);
boolean first = offs == 0; boolean first = offs == 0;
@@ -391,22 +404,31 @@ public abstract class AbstractTeamspeakClientSocket
if (fragment) { if (fragment) {
Ts3Debugging.debug("[PROTOCOL] READ " + networkPacket.getHeader().getType().name() + " fragment"); Ts3Debugging.debug("[PROTOCOL] READ " + networkPacket.getHeader().getType().name() + " fragment");
packet.setBody( packet.setBody(new PacketBodyFragment(networkPacket.getHeader().getType(), getRole().getIn()));
new PacketBodyFragment(
networkPacket.getHeader().getType(),
getRole().getIn()
)
);
} else { } else {
if (packet.getHeader().getPacketFlag(HeaderFlag.COMPRESSED))
packet.setBody(new PacketBodyCompressed(networkPacket.getHeader().getType(), getRole().getIn()));
Ts3Debugging.debug("[PROTOCOL] READ " + networkPacket.getHeader().getType().name()); Ts3Debugging.debug("[PROTOCOL] READ " + networkPacket.getHeader().getType().name());
} }
// Compression? // Read raw packet body
// TODO
// Read packet body
packet.readBody(packetBuffer); 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; return packet;
} }
@@ -217,17 +217,17 @@ public final class Ts3Crypt {
public static Pair<byte[], byte[]> generateKeypair() { public static Pair<byte[], byte[]> generateKeypair() {
byte[] privateKey = new byte[32]; byte[] privateKey = new byte[32];
new SecureRandom().nextBytes(privateKey); new SecureRandom().nextBytes(privateKey);
return generateKeypair(privateKey);
}
public static Pair<byte[], byte[]> generateKeypair(byte[] privateKey) {
ScalarOperations.sc_clamp(privateKey, 0); ScalarOperations.sc_clamp(privateKey, 0);
GroupElementP3 A = new GroupElementP3(); GroupElementP3 A = new GroupElementP3();
GroupOperations.ge_scalarmult_base(A, privateKey, 0); GroupOperations.ge_scalarmult_base(A, privateKey, 0);
byte[] publicKey = new byte[32]; byte[] publicKey = new byte[32];
GroupOperations.ge_p3_tobytes(publicKey, 0, A); GroupOperations.ge_p3_tobytes_negate(publicKey, 0, A);
Ts3Debugging.debug(publicKey);
Ts3Debugging.debug(privateKey);
return new Pair<>(publicKey, privateKey); return new Pair<>(publicKey, privateKey);
} }
@@ -13,6 +13,7 @@ import javafx.util.Pair;
import junit.framework.TestCase; import junit.framework.TestCase;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Base64; import java.util.Base64;
public class EncryptionTest extends TestCase { 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=")); 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(); byte[] packetBytes = transformation.encrypt(packet).array();
transformation.decrypt(header, ByteBuffer.wrap(packetBytes), packet.getBody().getSize());
Ts3Debugging.debug(Base64.getEncoder().encode(packetBytes));
} }
} }
@@ -10,20 +10,19 @@ import java.math.BigInteger;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.Base64; import java.util.Base64;
public class ServerConnectionTest extends TestCase { import static org.junit.Assert.assertEquals;
public ServerConnectionTest() {
super("ServerConnectionTest");
}
public void testParser() throws Exception { public class ServerConnectionTest {
public static void main(String[] args) throws Exception {
try { try {
LocalIdentity localIdentity = LocalIdentity.load( /**LocalIdentity localIdentity = LocalIdentity.load(
Ts3Crypt.decodePublicKey(Base64.getDecoder() Ts3Crypt.decodePublicKey(Base64.getDecoder()
.decode("MEsDAgcAAgEgAiBpPRbTliVt9KxtIz8saYdwcnNgcwaKLbKYSpDNO87u9gIgSWWPKcSJ9P6VZKJfRdpWwcfMdJv+NA9/hXUtz1uwRVI=")), .decode("MEsDAgcAAgEgAiBpPRbTliVt9KxtIz8saYdwcnNgcwaKLbKYSpDNO87u9gIgSWWPKcSJ9P6VZKJfRdpWwcfMdJv+NA9/hXUtz1uwRVI=")),
new BigInteger(Base64.getDecoder().decode("Tj6YXM3qyRv8n25L2pH+OEJnRUl4auQf8+znjYrOmWU=")), new BigInteger(Base64.getDecoder().decode("Tj6YXM3qyRv8n25L2pH+OEJnRUl4auQf8+znjYrOmWU=")),
2294, 2294,
2295 2295
); );**/
LocalIdentity localIdentity = LocalIdentity.generateNew(10);
LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket(); LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket();
@@ -41,8 +40,4 @@ public class ServerConnectionTest extends TestCase {
ex.printStackTrace(); ex.printStackTrace();
} }
} }
public static void main(String[] args) throws Exception {
new ServerConnectionTest().testParser();
}
} }