Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Android设备上验证C#生成的数字签名_C#_Java_.net_Android_Rsacryptoserviceprovider - Fatal编程技术网

在Android设备上验证C#生成的数字签名

在Android设备上验证C#生成的数字签名,c#,java,.net,android,rsacryptoserviceprovider,C#,Java,.net,Android,Rsacryptoserviceprovider,我正在编写一个Android应用程序,希望验证C#程序生成的字符串是否真实(即,由我编写的另一个应用程序生成)。为此,我对字符串进行签名,并将字符串和字符串的散列传输到Android设备。我可以在Android应用程序中包含用于创建哈希字符串的公钥,这样就不必传输它。产生所有这些的C#代码类似于以下内容: bytes = ASCIIEncoding.ASCII.GetBytes(someString); provider = new RSACryptoServiceProvider(); si

我正在编写一个Android应用程序,希望验证C#程序生成的字符串是否真实(即,由我编写的另一个应用程序生成)。为此,我对字符串进行签名,并将字符串和字符串的散列传输到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.ToBase64字符串(签名)

我从关键参数中手动提取了模数和公共指数。它们似乎都已经是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));
字符串模数=”;
字符串指数=”;
BigInteger双模=新的BigInteger(1,Base64.解码(模));
BigInteger双指数=新的BigInteger(1,Base64.decode(指数));
RSAPublicKeySpec publicKeySpec=新的RSAPublicKeySpec(双模块,双指标);
PublicKey PublicKey=KeyFactory.getInstance(“RSA”).generatePublic(publicKeySpec);
Cipher Cipher=Cipher.getInstance(“RSA”);
cipher.init(cipher.DECRYPT_模式,公钥);
字节[]decodedBytes=cipher.doFinal(Base64.decode(签名));
当我将
decodedBytes
与原始字符串的SHA1哈希进行比较时,它们是不同的。为了找出原因,我用大量的日志记录语句逐步完成了这个过程。似乎模的BigInteger与C#代码使用的模不同。指数也是如此。我怀疑这是因为Java的字节类型是无符号的

因此,有两个问题:

1) 我做错了(或没有做错)什么?是否有方法手动将模数和指数从一个设备移动到另一个设备以验证签名

2) 有没有一种方法可以在更合适的抽象层次上实现我的目标?

问题1:

您希望验证签名,因此不应使用
密码
类,而应使用
签名

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专家,我不知道
rsacyptoserviceprovider.SignData(…)
是否使用此标准

大多数情况下,签名密钥是通过将公钥(RSA中的模数+指数)绑定到实体(密钥的所有者可以是个人、计算机、公司……)的方式传输的

问题2:

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


更新:

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


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

它的身份验证和完整性。我们希望确保C#app已经生成了一个字符串(可能是200字节的数据),并且此后没有被修改。