.NET 中的 RSA 加密 - JAVA 中的解密 -> Java 抛出“模数不为正”错误错误
我在与第三方供应商实施单点登录时遇到问题。他们在验证我的签名时收到以下错误:
java.lang.ArithmeticException: BigInteger: modulus not Positive--at java.math.BigInteger.modPow(BigInteger.java:1556)
我无法控制他们的 Java 代码。这是我现在正在做的事情:
我使用以下代码在 C# 中创建了一个密钥对:
CspParameters csp = new CspParameters();
csp.KeyNumber = (int)KeyNumber.Signature;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024, csp))
{
File.AppendAllText(path + "PrivateKey.xml", rsa.ToXmlString(true));
File.AppendAllText(path + "PublicKey.xml", rsa.ToXmlString(false));
}
这是签名的代码:(
public string MD5withRSASignature(string encryptedStringToSign)
{
byte[] signature;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024))
{
XmlDocument xDoc = new XmlDocument();
xDoc.Load(PRIVATE_KEY_PATH);
rsa.FromXmlString(xDoc.OuterXml);
byte[] bytes = Encoding.UTF8.GetBytes(encryptedStringToSign);
signature = rsa.SignData(bytes, new MD5CryptoServiceProvider());
}
return Convert.ToBase64String(signature);
}
是的,我知道私钥应该位于密钥存储中)。
这是他们用来转换 xml 键的代码(这是 Java)
private static RSAPublicKey ReadXMLKey(String fileName)
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse( new File(fileName) );
byte[] modBytes = GetBytesFromElement(document, "Modulus");
byte[] expBytes = GetBytesFromElement(document, "Exponent");
RSAPublicKeySpec rsaKeyspec = new RSAPublicKeySpec(new BigInteger(modBytes), new BigInteger(expBytes));
RSAPublicKey key = (RSAPublicKey)KeyFactory.getInstance("RSA").generatePublic(rsaKeyspec);
return key;
}
private static byte[] GetBytesFromElement(Document doc, String tag) throws IOException
{
BASE64Decoder decoder = new BASE64Decoder();
NodeList list = doc.getElementsByTagName(tag);
byte[] results = null;
if (list.getLength() == 1)
{
Element item = (Element)list.item(0);
Text text = (Text)item.getFirstChild();
results = decoder.decodeBuffer(text.getNodeValue().trim());
}
return results;
}
I am having problems with our third party vendor implimenting an sso. They are receiving the following error when verifying my signature:
java.lang.ArithmeticException: BigInteger: modulus not positive--at java.math.BigInteger.modPow(BigInteger.java:1556)
I have no control over their Java code. Here is what I am doing now:
I created a key pair in C# using this code:
CspParameters csp = new CspParameters();
csp.KeyNumber = (int)KeyNumber.Signature;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024, csp))
{
File.AppendAllText(path + "PrivateKey.xml", rsa.ToXmlString(true));
File.AppendAllText(path + "PublicKey.xml", rsa.ToXmlString(false));
}
Here is the code for the signature:
public string MD5withRSASignature(string encryptedStringToSign)
{
byte[] signature;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024))
{
XmlDocument xDoc = new XmlDocument();
xDoc.Load(PRIVATE_KEY_PATH);
rsa.FromXmlString(xDoc.OuterXml);
byte[] bytes = Encoding.UTF8.GetBytes(encryptedStringToSign);
signature = rsa.SignData(bytes, new MD5CryptoServiceProvider());
}
return Convert.ToBase64String(signature);
}
(Yes I know the private key should be in a key store).
Here is the code they use to convert xml keys (this is Java)
private static RSAPublicKey ReadXMLKey(String fileName)
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse( new File(fileName) );
byte[] modBytes = GetBytesFromElement(document, "Modulus");
byte[] expBytes = GetBytesFromElement(document, "Exponent");
RSAPublicKeySpec rsaKeyspec = new RSAPublicKeySpec(new BigInteger(modBytes), new BigInteger(expBytes));
RSAPublicKey key = (RSAPublicKey)KeyFactory.getInstance("RSA").generatePublic(rsaKeyspec);
return key;
}
private static byte[] GetBytesFromElement(Document doc, String tag) throws IOException
{
BASE64Decoder decoder = new BASE64Decoder();
NodeList list = doc.getElementsByTagName(tag);
byte[] results = null;
if (list.getLength() == 1)
{
Element item = (Element)list.item(0);
Text text = (Text)item.getFirstChild();
results = decoder.decodeBuffer(text.getNodeValue().trim());
}
return results;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
该例外与 Java 使用的 RSA 公钥有关。您的代码都没有解决这一点。 Java端如何获得该密钥,使用什么格式?
导致该错误的一个常见错误是,如果模数转换为字节数组,但在需要时没有出现前导零字节。基本上,这个BigInteger 构造函数的使用比乍一看要复杂一些。它旨在与 DER 编码的 ASN.1 整数兼容。其结果是,如果模数的第一个字节
b
具有高位设置,即128 <= b << 256
,您必须在前面添加一个前导零字节,否则您的模数将被解释为负数。为了简单起见,您始终可以在前面添加一个前导零字节;如果没有必要的话,不会造成任何伤害。The exception has to do with the RSA public key that Java is using. None of your code addresses that point. How did the Java side obtain that key, what format is being used?
One common mistake that can account for the error is if the modulus is converted to an array of bytes but a leading zero byte is not present when it needs to be. Basically, this BigInteger constructor is a little trickier to use than it may first appear. It is designed for compatibility with DER-encoded ASN.1 integers. The upshot of it all is that if the first byte
b
of your modulus has the high bit set, i.e.128 <= b < 256
, you must prepend a leading zero byte or your modulus will be interpreted as a negative number. For simplicity you can always prepend a leading zero byte; no harm will come if it wasn't necessary.