对于你指出的问题,原因是你正在通知 SignatureMethod 作为SHA-1:
SignatureMethod
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
但你是 的 不通知 强> 该 reference.DigestMethod 作为SHA-1,你可以看到只是作为SHA-256的XML部分,所以你必须添加这一行(实际上你做了,但它被注释掉了):
reference.DigestMethod
reference.DigestMethod = SignedXml.XmlDsigSHA1Url;
看看这个答案(在葡萄牙语的Stack Overflow上,但代码部分全是英文),它使用SHA-256,但想法是一样的:
E-社会。 Assinatura做eventoinv lida
但是,您的代码有点令人困惑,您正在做一些看似不必要的事情,比如将XML文件作为流打开,然后加载 XmlDocument 使用从流中读取的字符串(为什么不直接打开XML文件 XmlDocument ?),你打开另一个 XmlDocument 再到最后......
XmlDocument
但我认为最重要的部分是你期待的那样 Signature 标签已经存在于您的输入XML中,但不应该这样,您应该签署一个未签名的XML文件,如果文件中已经存在签名,则应该在签名之前删除旧签名,因为签名进程采取整个文档生成签名。
Signature
以下是如何使用SHA-1算法执行签名XML文件的功能的建议:
using System; using System.Xml; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.Xml; private void SignXmlNodes( string filename, string mainChildTag, string idAttributeTag, X509Certificate2 x509Cert) { XmlDocument xmlDoc = new XmlDocument(); // Format the document to ignore white spaces. xmlDoc.PreserveWhitespace = false; xmlDoc.Load(filename); XmlNodeList mainChildList = xmlDoc.GetElementsByTagName(mainChildTag); // Loop through the nodes that need to be signed. foreach (XmlNode mainChildNode in mainChildList) { XmlNode nodeForSigning = mainChildNode.ParentNode; // It's necessary to create a namespace manager to use with SelectNode methods, // otherwise they won't work, because the node has a specific namespace. var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable); nsmgr.AddNamespace("ns", nodeForSigning.NamespaceURI); nsmgr.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); XmlNode nodeWithTheId = nodeForSigning.SelectSingleNode($"ns:{idAttributeTag}", nsmgr); if (nodeWithTheId == null) { throw new Exception($"The tag with ID attribute '{idAttributeTag}' does not exist in the XML file. (Error code: 4)"); } // Uses null-conditional (?.) and null-coalescing (??) operators to set the reference Uri. string refUri = nodeWithTheId.Attributes?["id"]?.Value ?? ""; if (!string.IsNullOrEmpty(refUri)) { refUri = $"#{refUri}"; } // Remove existing signatures in the node, if there's any. foreach (XmlNode node in nodeForSigning.SelectNodes("ds:Signature", nsmgr)) { node.ParentNode.RemoveChild(node); } SignedXml signedXml = new SignedXml((XmlElement) nodeForSigning); // Add the key to the SignedXml document signedXml.SigningKey = x509Cert.PrivateKey; signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url; // Create a reference with the specified Uri (id of the informed tag). Reference reference = new Reference(refUri); reference.AddTransform(new XmlDsigEnvelopedSignatureTransform()); reference.AddTransform(new XmlDsigC14NTransform()); reference.DigestMethod = SignedXml.XmlDsigSHA1Url; // Add the reference to the SignedXml object. signedXml.AddReference(reference); signedXml.KeyInfo = new KeyInfo(); // Load the certificate into a KeyInfoX509Data object // and add it to the KeyInfo object. signedXml.KeyInfo.AddClause(new KeyInfoX509Data(x509Cert)); // 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 signature element to the XML document. //xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true)); nodeForSigning.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true)); } xmlDoc.Save(filename); }
你可以像这样使用它:
SignXmlNodes("E:\\nota.xml", "InfDeclaracaoPrestacaoServico", "InfDeclaracaoPrestacaoServico", SelectCertificate());