在 C# 中创建的数字签名在 Java 验证中不匹配
Digital Signature created in C# doesn't match in Java verification
我需要在使用 "SHA1withRSA" 的 JAVA 程序中使用 "SHA1" 算法验证从 C# 创建的签名。签名字节不匹配。我正在使用 C# 程序生成的 Public 密钥来验证存储在文件中的签名。我是密码学的新手。下面是创建签名的 C# 代码:
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSA.FromXmlString(privateKey);
var encoder = new UTF8Encoding();
byte[] originalData = encoder.GetBytes(message);
SHA1 sha1 = SHA1.Create();
byte[] signedBytes = RSA.SignData(originalData, sha1);
return signedBytes;
我正在尝试验证 Java 程序中的签名,如下所示:
//read xml file to get modulus and exponent bytes
File publicKeyFileQA = new File(PUBLIC_KEY_FILE_QA);
Map<String, BigInteger> publicKeyModulusExponentValues = DSXCRM_3YBP_Global_WebServicesUtil.readXMLFile(publicKeyFileQA);
BigInteger publicKeyModulus = publicKeyModulusExponentValues.get("modulus");
BigInteger publicKeyExponent = publicKeyModulusExponentValues.get("exponent");
System.out.println("BigInteger Modulus : "+ publicKeyModulus + "BigInteger Exponent : " + publicKeyExponent);
String messageWithSignature = (String) mapDataToPost.get("SignedMessage");
String encryptedMessage = (String) mapDataToPost.get("EncryptedMessage");
byte[] signatureBytes = DatatypeConverter.parseBase64Binary(messageWithSignature);
System.out.println("Signature bytes : "+ new String(signatureBytes));
byte[] cipherMessage = DatatypeConverter.parseBase64Binary(encryptedMessage);
System.out.println("Cipher Message : "+ new String(cipherMessage));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(publicKeyModulus, publicKeyExponent);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(publicKey); //public key of sender
sig.update(cipherMessage);
boolean isRightSender = sig.verify(signatureBytes);
System.out.println("isRightSender : "+isRightSender);
但匹配签名的结果是错误的。我不明白哪里出了问题。你能提供任何建议吗?是否有任何其他算法兼容 C# 和 JAVA 以具有相同的签名?谢谢!
您正在读取一个名为 "SignedMessage" 的字段,将其存储在一个名为 "messageWithSignature" 的变量中,然后将其视为签名。该 blob 中实际存在哪些数据?
您正在进一步打印二进制数据,就好像它是文本一样(通过 new String(byte[])
)。您应该在两侧打印 Base64 或十六进制以查看它们是否匹配,对于消息字节(在您的验证程序中似乎被称为 cipherMessage
)和签名。
如果你切换到静态数据(以避免在读取时计算换行符之类的事情)那么这样做应该是有效的
byte[] originalData = Encoding.UTF8.GetBytes("This is a static message test.");
Console.WriteLine(Convert.ToBase64String(rsa.SignData(originalData), "SHA1"));
然后获取该输出,将其放入您的 Java 程序并验证
byte[] originalData = "This is a static message test.".getBytes("UTF-8");
byte[] signature = Base64.getDecoder().decode(theOutputFromTheCSharpProgram);
Signature verifier = new Signature("SHA1withRSA");
verifier.initVerify(publicKey);
verifier.update(originalData);
System.out.println(verifier.verify(signature));
如果那部分不起作用,那么你一定没有忠实地在两边代表同一个键。
RSA签名的二进制格式在C#和Java中是一样的;因此,一旦您将数据传输安排好,一切都应该正常工作。
我需要在使用 "SHA1withRSA" 的 JAVA 程序中使用 "SHA1" 算法验证从 C# 创建的签名。签名字节不匹配。我正在使用 C# 程序生成的 Public 密钥来验证存储在文件中的签名。我是密码学的新手。下面是创建签名的 C# 代码:
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSA.FromXmlString(privateKey);
var encoder = new UTF8Encoding();
byte[] originalData = encoder.GetBytes(message);
SHA1 sha1 = SHA1.Create();
byte[] signedBytes = RSA.SignData(originalData, sha1);
return signedBytes;
我正在尝试验证 Java 程序中的签名,如下所示:
//read xml file to get modulus and exponent bytes
File publicKeyFileQA = new File(PUBLIC_KEY_FILE_QA);
Map<String, BigInteger> publicKeyModulusExponentValues = DSXCRM_3YBP_Global_WebServicesUtil.readXMLFile(publicKeyFileQA);
BigInteger publicKeyModulus = publicKeyModulusExponentValues.get("modulus");
BigInteger publicKeyExponent = publicKeyModulusExponentValues.get("exponent");
System.out.println("BigInteger Modulus : "+ publicKeyModulus + "BigInteger Exponent : " + publicKeyExponent);
String messageWithSignature = (String) mapDataToPost.get("SignedMessage");
String encryptedMessage = (String) mapDataToPost.get("EncryptedMessage");
byte[] signatureBytes = DatatypeConverter.parseBase64Binary(messageWithSignature);
System.out.println("Signature bytes : "+ new String(signatureBytes));
byte[] cipherMessage = DatatypeConverter.parseBase64Binary(encryptedMessage);
System.out.println("Cipher Message : "+ new String(cipherMessage));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(publicKeyModulus, publicKeyExponent);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(publicKey); //public key of sender
sig.update(cipherMessage);
boolean isRightSender = sig.verify(signatureBytes);
System.out.println("isRightSender : "+isRightSender);
但匹配签名的结果是错误的。我不明白哪里出了问题。你能提供任何建议吗?是否有任何其他算法兼容 C# 和 JAVA 以具有相同的签名?谢谢!
您正在读取一个名为 "SignedMessage" 的字段,将其存储在一个名为 "messageWithSignature" 的变量中,然后将其视为签名。该 blob 中实际存在哪些数据?
您正在进一步打印二进制数据,就好像它是文本一样(通过 new String(byte[])
)。您应该在两侧打印 Base64 或十六进制以查看它们是否匹配,对于消息字节(在您的验证程序中似乎被称为 cipherMessage
)和签名。
如果你切换到静态数据(以避免在读取时计算换行符之类的事情)那么这样做应该是有效的
byte[] originalData = Encoding.UTF8.GetBytes("This is a static message test.");
Console.WriteLine(Convert.ToBase64String(rsa.SignData(originalData), "SHA1"));
然后获取该输出,将其放入您的 Java 程序并验证
byte[] originalData = "This is a static message test.".getBytes("UTF-8");
byte[] signature = Base64.getDecoder().decode(theOutputFromTheCSharpProgram);
Signature verifier = new Signature("SHA1withRSA");
verifier.initVerify(publicKey);
verifier.update(originalData);
System.out.println(verifier.verify(signature));
如果那部分不起作用,那么你一定没有忠实地在两边代表同一个键。
RSA签名的二进制格式在C#和Java中是一样的;因此,一旦您将数据传输安排好,一切都应该正常工作。