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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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());
|
||||||
|
|||||||
+3
@@ -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);
|
||||||
|
|
||||||
|
|||||||
+44
-22
@@ -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,21 +217,21 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class SecureChannelParameters {
|
public static final class SecureChannelParameters {
|
||||||
private final byte[] fakeSignature;
|
private final byte[] fakeSignature;
|
||||||
private final byte[] ivStruct;
|
private final byte[] ivStruct;
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user