diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/client/LocalClientHandlerConnecting.java b/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/client/LocalClientHandlerConnecting.java index dc5fe7a..9f95695 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/client/LocalClientHandlerConnecting.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/client/LocalClientHandlerConnecting.java @@ -159,16 +159,7 @@ public class LocalClientHandlerConnecting extends LocalClientHandler { BigInteger x = new BigInteger(1, serverReplyStep3.getX()); BigInteger n = new BigInteger(1, serverReplyStep3.getN()); - byte[] y = new byte[64]; - - byte[] solution = - x.modPow(BigInteger.valueOf(2L).pow(serverReplyStep3.getLevel()), n).toByteArray(); - - System.arraycopy( - solution, Math.abs(solution.length - 64), - y, solution.length < 64 ? 64 - solution.length : 0, - solution.length < 64 ? solution.length : 64 - ); + byte[] y = unsigned64(x.modPow(BigInteger.valueOf(2L).pow(serverReplyStep3.getLevel()), n)); // Build response PacketBody8Init1.Step4 step4 = new PacketBody8Init1.Step4(); @@ -360,4 +351,17 @@ public class LocalClientHandlerConnecting extends LocalClientHandler { getClient().writePacket(new PacketBody2Command(ProtocolRole.CLIENT, clientinit)); } + + /** + * The puzzle's answer as 64 unsigned big-endian bytes. {@link BigInteger#toByteArray()} + * adds a sign byte when the top bit is set and drops leading zero bytes, so it can be + * 65 bytes or fewer than 64. + */ + static byte[] unsigned64(BigInteger value) { + byte[] bytes = value.toByteArray(); + byte[] y = new byte[64]; + int length = Math.min(bytes.length, 64); + System.arraycopy(bytes, bytes.length - length, y, 64 - length, length); + return y; + } } diff --git a/src/test/java/com/github/manevolent/ts3j/protocol/packet/handler/client/PuzzleAnswerTest.java b/src/test/java/com/github/manevolent/ts3j/protocol/packet/handler/client/PuzzleAnswerTest.java new file mode 100644 index 0000000..d1cb81b --- /dev/null +++ b/src/test/java/com/github/manevolent/ts3j/protocol/packet/handler/client/PuzzleAnswerTest.java @@ -0,0 +1,33 @@ +package com.github.manevolent.ts3j.protocol.packet.handler.client; + +import junit.framework.TestCase; + +import java.math.BigInteger; +import java.util.Arrays; + +public class PuzzleAnswerTest extends TestCase { + private static byte[] bytes(int length, int first) { + byte[] b = new byte[length]; + Arrays.fill(b, (byte) 0x11); + b[0] = (byte) first; + return b; + } + + /** Top bit set: toByteArray() gives 65 bytes, the first a sign byte. */ + public void testDropsTheSignByte() { + byte[] answer = bytes(64, 0x80); + assertTrue(Arrays.equals(answer, LocalClientHandlerConnecting.unsigned64(new BigInteger(1, answer)))); + } + + public void testKeepsSixtyFourBytes() { + byte[] answer = bytes(64, 0x7f); + assertTrue(Arrays.equals(answer, LocalClientHandlerConnecting.unsigned64(new BigInteger(1, answer)))); + } + + /** A leading zero byte: toByteArray() gives 63 bytes, which used to fail the connect. */ + public void testPadsAShortAnswerWithZeros() { + byte[] answer = bytes(64, 0x00); + answer[1] = 0x42; + assertTrue(Arrays.equals(answer, LocalClientHandlerConnecting.unsigned64(new BigInteger(1, answer)))); + } +}