-
The Problem
- I was using protobufs to transfer a ecdsa public key over a tcp connection.
- The server was written in go, the client was an Android app (Google Play services)
- The public key consists of two large numbers (X and Y).
- The X and Y values generated are always positive(not sure why yet, need to see if this is as per design)
- Client also performs a check using signum to see if the values are negative and throws and exception. The following message is from the adb logs
-
ehou: Cannot parse public key: Point encoding must use only non-negative integers
-
The numbers that were positive on the server somehow turned negative on the client.
- This behaviour was intermittent. The transfer was successful sometimes.
-
Experiments and Observations
- Tried checking if endianness is the problem. But the client continued to throw the same exception.
- The values X and Y are 32 bytes long.
- Since I cannot really go and debug what’s going on in the client, since its a system app on android and my phone is not rooted at the moment. I have tried to mimic the conditions using the following snippet.
- The Golang server is as below
- To my surprise I found that byte array implementation was different in golang and java.
- In golang each byte in the byte array is unsigned.
- In java each byte is a signed byte.
- Though both are same in memory, we see the difference in interpretation of the byte value.
- And the byte array in java considers the msb as a signed bit.
- So whenever there is a 1 in the msb the biginteger in java interpreted is as a negative number, this explains the intermittent behaviour.
- To fix this issue I had to prefix a 0 byte to the beginning of the byte array that was sent from golang. This would make java BigInteger to parse the number correctly since the msb is not 1 anymore.
- The change in golang code is as below