我正在编写一个想要验证由 C# 程序生成的字符串是否真实的 Android 应用程序(即由我编写的另一个应用程序生成)。为此,我对字符串进行签名并将字符串和字符串的散列传输到 Android 设备。我可以在 Android 应用程序中包含用于创建散列字符串的公钥,这样我就不必传输它了。产生所有这些的 C# 代码类似于以下内容:
bytes = ASCIIEncoding.ASCII.GetBytes(someString);
provider = new RSACryptoServiceProvider();
signature = provider.SignData(bytes, new SHA1CryptoServiceProvider());
keyParameters = cryptoProvider.ExportParameters(false);
为了传输数据,我将签名编码为 base64,使用:
signatureString = System.Convert.ToBase64String(signature);
我从关键参数中手动提取模数和公共指数。它们似乎都已经是 Base64 编码的。在android应用程序中,我试图验证签名如下:
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));
当我与decodedBytes
原始字符串的 SHA1 哈希值进行比较时,它们是不同的。试图找出原因,我用大量的日志语句逐步完成了这个过程。模数的 BigInteger 似乎与 C# 代码使用的模数不同。指数也是如此。我怀疑这是因为 Java 的字节类型是无符号的?
所以,两个问题:
1)我做错了什么(或没做错)?有没有办法手动将模数和指数从一个设备移动到另一个设备以验证签名?
2)有没有办法在更合适的抽象级别上完成我的目标?