Pad a short RSA puzzle answer instead of failing the connect
An answer with a leading zero byte comes out of toByteArray() as 63 bytes, and copying it started one byte too far, failing about one connect in 256. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+14
-10
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+33
@@ -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))));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user