SignedXml。CheckSignature只有在我用私钥验证时才返回true
-
20-12-2019 - |
题
我见过几个类似的问题,但没有一个确切地解决我所问的问题。
我试图签署一个XML,然后使用c#使用公钥验证它。
我用密钥对XML进行签名,然后将密钥导出到XML。然后将密钥和签名的XML带到另一台计算机,使用以下方法导入密钥 rsa.FromXmlString(doc.InnerXml)
, ,并验证XML签名。
如果我使用以下方法将公钥和私钥导出到XML,则可以使用 rsa.ToXmlString(True)
.但是,我想只使用我的公钥导出 rsa.ToXmlString(False)
.如果我只导出公钥并在第二台计算机上导入它并尝试验证XML签名,则表示签名无效。
首先,我应该能够仅使用公钥验证签名的XML吗?
其次,如果这是真的,为什么我的验证XML函数只与pub/priv密钥对一起工作,而不是只与公钥一起工作?
你对如何调试这个问题有什么智慧吗?我不确定还能做什么,因为 signedXml.CheckSignature(Key);
不提供有关失败原因的任何信息。
我的导入密钥,导出密钥,签名XML和验证XML功能如下。如果您需要更多信息,请告诉我。
public static void ImportKeyFromFile(string ContainerName, string inputFile)
{
try
{
// Create new XmlDocument.
XmlDocument doc = new XmlDocument();
// Load XML Document.
doc.Load(inputFile);
// Create the CspParameters object and set the key container
// name used to store the RSA key pair.
CspParameters cp = new CspParameters();
cp.KeyContainerName = ContainerName;
// Create a new instance of RSACryptoServiceProvider that accesses
// the key container MyKeyContainerName.
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
// Get RSA Parameters from xml document.
rsa.FromXmlString(doc.InnerXml);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public static void ExportKeyToFile(string ContainerName, string outputPath, bool private_key)
{
try
{
// Create the CspParameters object and set the key container
// name used to store the RSA key pair.
CspParameters cp = new CspParameters();
cp.KeyContainerName = ContainerName;
// Create a new instance of RSACryptoServiceProvider that accesses
// the key container MyKeyContainerName.
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
// Create new XmlDocument.
XmlDocument doc = new XmlDocument();
// Store rsa key.
doc.InnerXml = rsa.ToXmlString(private_key);
// Save Document.
doc.Save(outputPath);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public static Boolean VerifyXml(XmlDocument Doc, RSA Key)
{
// Check arguments.
if (Doc == null)
throw new ArgumentException("Doc");
if (Key == null)
throw new ArgumentException("Key");
// Create a new SignedXml object and pass it
// the XML document class.
SignedXml signedXml = new SignedXml(Doc);
// Find the "Signature" node and create a new
// XmlNodeList object.
XmlNodeList nodeList = Doc.GetElementsByTagName("Signature");
// Throw an exception if no signature was found.
if (nodeList.Count <= 0)
{
throw new CryptographicException("Verification failed: No Signature was found in the document.");
}
// Load the first <signature> node.
signedXml.LoadXml((XmlElement)nodeList[0]);
// Check the signature and return the result.
return signedXml.CheckSignature(Key);
}
public static void SignXml(XmlDocument xmlDoc, RSA Key)
{
// Check arguments.
if (xmlDoc == null)
throw new ArgumentException("xmlDoc");
if (Key == null)
throw new ArgumentException("Key");
// Create a SignedXml object.
SignedXml signedXml = new SignedXml(xmlDoc);
// Add the key to the SignedXml document.
signedXml.SigningKey = Key;
// Create a reference to be signed.
Reference reference = new Reference();
reference.Uri = "";
// Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
// Compute the signature.
signedXml.ComputeSignature();
// Get the XML representation of the signature and save
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
// Append the element to the XML document.
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
}
解决方案
问题是因为您无法将公钥存储在密钥容器中。若要仅使用公钥验证签名,应使用以下方法从XML导入密钥 rsa.FromXmlString
然后将rsa直接传递给Verify Signature函数。如果您尝试将公钥存储在密钥容器中并稍后检索它,则最终只会创建一个新密钥。如何在机器级RSA密钥容器中存储公钥
不隶属于 StackOverflow