I'm trying to Hash a BigInteger/BigNum and I'm getting different results in Android/iOS. I need to get the same Hash result so that both the apps work as per the SRP protocol. On closer inspection it is working fine for positive numbers but not working for negative numbers (first nibble greater than 7). Not sure which one is correct and which one is to be adjusted to match with the other.
Android:
void hashBigInteger(String s) {
try {
BigInteger a = new BigInteger(s, 16);
MessageDigest sha = MessageDigest.getInstance("SHA-256");
byte[] b = a.toByteArray();
sha.update(b, 0, b.length);
byte[] digest = sha.digest();
BigInteger d = new BigInteger(digest);
Log.d("HASH", "H = " + d.toString(16));
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
}
}
iOS:
void hashBigNum(unsigned char *c) {
BIGNUM *n = BN_new();
BN_hex2bn(&n, c);
unsigned char buff[ SHA256_DIGEST_LENGTH ];
int len = BN_num_bytes(n);
unsigned char * bin = (unsigned char *) malloc( len );
BN_bn2bin(n, bin);
hash( SRP_SHA256, bin, len, buff );
fprintf(stderr, "H: ");
for (int z = 0; z < SHA256_DIGEST_LENGTH; z++)
fprintf(stderr, "%2x", buff[z]);
fprintf(stderr, "\n");
free(bin);
}
Results:
Source String = "6F"
Android Hash = 65c74c15a686187bb6bbf9958f494fc6b80068034a659a9ad44991b08c58f2d2
iOS Hash = 65c74c15a686187bb6bbf9958f494fc6b80068034a659a9ad44991b08c58f2d2
Source String = "FF"
Android Hash = 06eb7d6a69ee19e5fbdf749018d3d2abfa04bcbd1365db312eb86dc7169389b8
iOS Hash = a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89
The problem is in the JAVA code. new BigInteger(s, 16).toByteArray()
is not safe for leading zeros. See poster comment at Convert a string representation of a hex dump to a byte array using Java?
The bit representation of FF with Android is 00000000
11111111
whereas in iOS is 11111111
. The leading zeros is the reason because the SHA256 hashing is different.
Just change the Hex to byte converter using one method of the linked post to get the same byte array (without zeros). For example
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
void hashBigInteger(String s){
try{
MessageDigest sha = MessageDigest.getInstance("SHA-256");
byte b[] = hexStringToByteArray(s);
sha.update(b,0,b.length);
byte digest[] = sha.digest();
BigInteger d = new BigInteger(1,digest);
System.out.println("H "+d.toString(16));
}catch (NoSuchAlgorithmException e){
throw new UnsupportedOperationException(e);
}
}
To proper HEX printing, change also BigInteger d = new BigInteger(digest);
with
BigInteger d = new BigInteger(1,digest);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With