I'm writing an Android application that would like to verify that a string produced by a C# program is authentic (i.e. produced by another application that I've written). To do that, I'm signing the string and transmitting the string and the hash of the string to the Android device. I can include the public key used to create the hashed string in the Android application so I don't have to transmit it. The C# code that produces all of that is akin to what follows:
bytes = ASCIIEncoding.ASCII.GetBytes(someString);
provider = new RSACryptoServiceProvider();
signature = provider.SignData(bytes, new SHA1CryptoServiceProvider());
keyParameters = cryptoProvider.ExportParameters(false);
To transmit the data, I encode the signature as base64 using:
signatureString = System.Convert.ToBase64String(signature);
I manually extracted the modulus and the public exponent from the key Parameters. They appear to both be Base64 encoded already. In the android application I'm attempting to verify the signature as follows:
String modulus = "<modulus string here...>";
String exponent = "<exponent string here...>";
BigInteger BIModulus = new BigInteger(1, Base64.decode(modulus));
BigInteger BIExponent = new BigInteger(1, Base64.decode(exponent));
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(BIModulus, BIExponent);
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] decodedBytes = cipher.doFinal(Base64.decode(signature));
When I compare decodedBytes
to the SHA1 hash of the original string, they're different. Trying to figure out why, I stepped through the process with oodles of logging statements. It appears that the BigInteger for the modulus is different from the modulus used by the C# code. The same happens with the exponent. My suspicion is that this is because Java's byte type is unsigned?
So, two questions:
1) What am I doing (or not doing) wrong? Is there a way to manually move the modulus and exponent from one device to another to verify a signature?
2) Is there a way to accomplish what I'm aiming for that works at a more appropriate level of abstraction?