3

我正在编写一个想要验证由 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)有没有办法在更合适的抽象级别上完成我的目标?

4

1 回答 1

7

问题一:

您想验证签名,因此您不应该使用Cipher该类,而是Signature该类。

PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);
Signature sign = Signature.getInstance("SHA1withRSA");
sign.initVerify(publicKey);
sign.update(someString.getBytes("ASCII"));
boolean ok = sign.verify(Base64.decode(signature));

注意:SHA1withRSA算法使用带有 SHA-1 的 RSA,如 PKCS#1 标准中所述。我不是 .net 专家,我不知道是否RSACryptoServiceProvider.SignData(...)使用此标准。

大多数时间签名密钥通过将公钥(在 RSA 情况下为模数 + 指数)绑定到实体(密钥的所有者,可以是个人、计算机、公司......)的证书进行传输

问题2:

绝对取决于您的用例:为什么需要签名(身份验证、完整性)?你在签什么?


更新:

使用简单的 RSA 签名,只要与适当的方案/协议一起使用(例如PKCS#1,在任何地方实现,至少是 1.5 版本),都可以。另一种解决方案是使用提供身份验证和完整性服务并使用对称密钥的消息身份验证代码(如HMAC )。

要携带公钥,您可以在验证应用程序中对密钥进行硬编码(或使用自签名证书)。您必须知道,如果私钥被泄露、丢失或破坏,您将不得不更新所有客户端。第二种解决方案是使用PKI颁发签名证书;此解决方案支持密钥撤销和更新,但有几个缺点:设置和维护不那么容易,根据您的需求和环境,可能有点过分了。

于 2011-04-18T17:12:31.087 回答