问题描述
我正在尝试在服务器应用程序(用C#编写)上生成RSA SHA512签名,并在客户端应用程序(用Java编写)上验证该签名.在签名交换之前,服务器会生成一个公钥和私钥对,并通过为其提供模数和指数值来与客户端应用程序共享公钥.当需要验证签名时,客户端应用程序将存储这些值以供以后使用.
I'm attempting to generate an RSA SHA512 signature on my server application (written in C#) and verify that signature on a client application (written in Java). Prior to the signature exchange, the server generates a public- and private-key pair and shares the public key with the client app by giving it the modulus and exponent values that were generated. The client app stores the values for later, when the signature needs to be verified.
服务器正在生成128字节的模数和128字节的签名.在测试时,我只是使用[0x00、0x01、0x02、0x03]字节数组作为签名的源数据.
The server is generating a 128-byte modulus and a 128-byte signature. I'm just using a byte array of [0x00, 0x01, 0x02, 0x03] as my source data for the signature while I'm testing.
由于某种原因,我的Java应用程序在验证签名时总是失败.
For some reason, my Java application always fails when validating the signature.
我的C#代码(创建签名):
My C# code (creates the signature):
RSACryptoServiceProvider crypto = new RSACryptoServiceProvider();
crypto.FromXmlString(this.myStoredPrivateKeyXml);
List<byte> signatureBytes = new List<byte>();
signatureBytes.Add(0x00);
signatureBytes.Add(0x01);
signatureBytes.Add(0x02);
signatureBytes.Add(0x03);
byte[] signature = crypto.SignData(signatureBytes.ToArray(), "SHA512");
我的Java代码(接收/验证签名):
My Java code (that receives/validates the signature):
byte[] expectedData = new byte[4];
expectedData[0] = 0;
expectedData[1] = 1;
expectedData[2] = 2;
expectedData[3] = 3;
byte[] exponent = getStoredExponent(); // three-byte value from server
byte[] modulus = getStoredModulus(); // 128-byte value from server
RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(exponent));
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(spec);
Signature verifier = Signature.getInstance("SHA512withRSA");
verifier.initVerify(publicKey);
verifier.update(expectedData);
if(verifier.verify(signature)) {
System.out.println("signature verified");
} else {
System.out.println("signature failed verification"); // always ends up here :(
}
C#端的加密对象来自System.Security.Cryptography命名空间,而Java端则来自java.security.
The crypto objects on the C# side are from the System.Security.Cryptography namespace and java.security on the Java side.
字节通过Web服务和base64字符串在应用之间传递.我仔细研究并打印了字节数组本身的值,以确保这两个应用程序之间的指数,模数和签名的值正确.有什么原因导致两种语言/应用程序之间的签名不兼容?可能我缺少一个参数吗?我用SHA512将它们都制成了RSA,但也许还需要考虑签名的其他方面?
The bytes are passed between the apps via web services and base64 strings. I've gone through and printed the values of the byte arrays themselves to make sure the values are correct for the exponent, modulus, and signature between the two applications. Is there any reason why the signature wouldn't be compatible between the two languages/apps? Is there a parameter that I'm missing, maybe? I made them both RSA with SHA512, but perhaps other aspects of the signature need to be accounted for as well?
推荐答案
在C#端的XML表示中,数据存储为 unsigned big endian (和Base64编码).
In the XML representation on the C# side, the data are stored as unsigned big endian (and Base64 encoded).
但是,Java BigInteger(byte [] val)
-constructor期望数据为 signed(二进制补码)big endian .
因此, BigInteger(int signum,byte []大小)
构造函数,它期望第一个参数中的符号而第二个参数中的数据为 unsigned big endian ,即需要进行以下更改:
Therefore the BigInteger(int signum, byte[] magnitude)
-constructor must be used, which expects the sign in the first parameter and the data in the second parameter as unsigned big endian, i.e. the following change is necessary:
RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(1, modulus), new BigInteger(1, exponent));
这篇关于从Java中的C#验证rsa签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!