生成无效数字签名的函数
Function generating invalid digital signature
我正在尝试使用 SHA-1 算法对 XML 文档进行数字签名,但生成的签名 XML 中包含 SHA-256 部分。我看到了这个 并试图使其适应我的功能,但它不起作用,因为它在结果 XML.
上同时引用了 SHA-1 和 SHA-256
这是我的实际代码:
private void AssinarXml(string arquivo, string tagAssinatura, string tagAtributoId, X509Certificate2 x509Cert)
{
StreamReader SR = null;
try
{
SR = System.IO.File.OpenText(arquivo);
string xmlString = SR.ReadToEnd();
SR.Close();
SR = null;
// Create a new XML document.
XmlDocument doc = new XmlDocument();
// Format the document to ignore white spaces.
doc.PreserveWhitespace = false;
// Load the passed XML file using it’s name.
doc.LoadXml(xmlString);
if (doc.GetElementsByTagName(tagAssinatura).Count == 0)
{
throw new Exception("A tag de assinatura " + tagAssinatura.Trim() + " não existe no XML. (Código do Erro: 5)");
}
else if (doc.GetElementsByTagName(tagAtributoId).Count == 0)
{
throw new Exception("A tag de assinatura " + tagAtributoId.Trim() + " não existe no XML. (Código do Erro: 4)");
}
else
{
XmlDocument XMLDoc;
XmlNodeList lists = doc.GetElementsByTagName(tagAssinatura);
foreach (XmlNode nodes in lists)
{
foreach (XmlNode childNodes in nodes.ChildNodes)
{
if (!childNodes.Name.Equals(tagAtributoId))
continue;
if (childNodes.NextSibling != null && childNodes.NextSibling.Name.Equals("Signature"))
continue;
// Create a reference to be signed
Reference reference = new Reference("");
reference.Uri = "";
XmlElement childElemen = (XmlElement)childNodes;
if (childElemen.GetAttributeNode("Id") != null)
{
reference.Uri = ""; // "#" + childElemen.GetAttributeNode("Id").Value;
}
else if (childElemen.GetAttributeNode("id") != null)
{
reference.Uri = "#" + childElemen.GetAttributeNode("id").Value;
}
//reference.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1";
// Create a SignedXml object.
SignedXml signedXml = new SignedXml(doc);
// Add the key to the SignedXml document
signedXml.SigningKey = x509Cert.PrivateKey;
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
// Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
XmlDsigC14NTransform c14 = new XmlDsigC14NTransform();
reference.AddTransform(c14);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
// Create a new KeyInfo object
KeyInfo keyInfo = new KeyInfo();
// Load the certificate into a KeyInfoX509Data object
// and add it to the KeyInfo object.
keyInfo.AddClause(new KeyInfoX509Data(x509Cert));
// Add the KeyInfo object to the SignedXml object.
signedXml.KeyInfo = keyInfo;
signedXml.ComputeSignature();
// Get the XML representation of the signature and save
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
nodes.AppendChild(doc.ImportNode(xmlDigitalSignature, true));
}
}
XMLDoc = new XmlDocument();
XMLDoc.PreserveWhitespace = false;
XMLDoc = doc;
string conteudoXMLAssinado = XMLDoc.OuterXml;
using (StreamWriter sw = System.IO.File.CreateText(arquivo))
{
sw.Write(conteudoXMLAssinado);
sw.Close();
}
}
}
finally
{
if (SR != null)
SR.Close();
}
}
如何让这个函数像SHA1一样签名?
这是输出签名的示例:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>pp8br9Yd9SdFWQhFdCOJmJlEsKGnlbpovZ6Ssp7VwC4=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>ZSWsXhFu6qw5NGy8+hVAA8oW7nUp1vX2Wv+YpnFiC9UWTdRdYlUDjAiah9symfOX2tOEUk69aJjaL/bSZoc5BFFYqQOm2kBVnlbEYQ0lQpvy4sEJodTWiVGaikVldFWUjPkhjwxy9SpreOKBHpEOPkdkyb8SS8k5bE1yA6IbTE3JfyCmeojDSha3lVZzbX8rBN6R2Mwkwg9Eh9dOPjk4+Wu/V5APDQfDa9viQlDAG+gtBTQacMb2aZrNR8fYqm8fSbwhfxgBaMbCqp3A/KqEm9M5Tj8ql/5flRRJ1zmlrwvByfff5+unhdhMzhKcPeoEAkBBJu4RlJVDgf1BNnexNw==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIIIDCCBgigAwIBAgIIE+rXn6mbRzwwDQYJKoZIhvcNAQELBQAwcjELMAkGA1UEBhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxNjA0BgNVBAsTLVNlY3JldGFyaWEgZGEgUmVjZWl0YSBGZWRlcmFsIGRvIEJyYXNpbCAtIFJGQjEWMBQGA1UEAxMNQUMgT05MSU5FIFJGQjAeFw0xNzA2MjMxMTU3MzZaFw0yMDA2MjIxMTU3MzZaMIHiMQswCQYDVQQGEwJCUjELMAkGA1UECAwCTUcxEzARBgNVBAcMClBPQ08gRlVORE8xEzARBgNVBAoMCklDUC1CcmFzaWwxNjA0BgNVBAsMLVNlY3JldGFyaWEgZGEgUmVjZWl0YSBGZWRlcmFsIGRvIEJyYXNpbCAtIFJGQjEWMBQGA1UECwwNUkZCIGUtQ05QSiBBMzEXMBUGA1UECwwOQVIgTUsgU09MVUNPRVMxMzAxBgNVBAMMKk5BVEFMSUEgTUFHQU5IQSBEQSBDT1NUQSBNRToxMjI4NzIwMzAwMDE5MDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJmbbzxDWjBeKX2VlyxwlsbLGU10kWEgO+K6HAnv8Y6YOv3JNavhIoI1++8jHjs/mgi5Fea06AQSTOPVwR3ssIYQYJbPs6e27VqHsCJaJPTFUw8rTJmVYoEn7JnuHk0yvLYmovDWKYXEUxy6sop2ckJ6u2ofAZ9HxP9qPkiZbzFk7WSXv3o/tNxcuYXDY0O+8fXtxgPocKNLGpCl/48JUM9rVoXbuobuFflsFIqMRrJbG/9OgiRKPFR1RadlPB7qzpcbFS9ceFaJ3jfem4MgqulKD2Wj2GqppBt/6HR4lRBhJmeWeA2BnKPpHz06m/M3LXI1yidpj134JHh1pMQZnNUCAwEAAaOCA0cwggNDMIGhBggrBgEFBQcBAQSBlDCBkTBcBggrBgEFBQcwAoZQaHR0cDovL2ljcC1icmFzaWwudnBraS52YWxpZGNlcnRpZmljYWRvcmEuY29tLmJyL2FjLW9ubGluZXJmYi9hYy1vbmxpbmVyZmJ2Mi5wN2IwMQYIKwYBBQUHMAGGJWh0dHA6Ly9vY3NwLnZhbGlkY2VydGlmaWNhZG9yYS5jb20uYnIwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSRmnaMK6iTGJiYegPky+y1sBkn/zB1BgNVHSAEbjBsMGoGBmBMAQIDNDBgMF4GCCsGAQUFBwIBFlJodHRwOi8vaWNwLWJyYXNpbC52cGtpLnZhbGlkY2VydGlmaWNhZG9yYS5jb20uYnIvYWMtb25saW5lcmZiL2RwYy1hYy1vbmxpbmVyZmIucGRmMIIBBgYDVR0fBIH+MIH7MFWgU6BRhk9odHRwOi8vaWNwLWJyYXNpbC52YWxpZGNlcnRpZmljYWRvcmEuY29tLmJyL2FjLW9ubGluZXJmYi9sY3ItYWMtb25saW5lcmZidjIuY3JsMFagVKBShlBodHRwOi8vaWNwLWJyYXNpbDIudmFsaWRjZXJ0aWZpY2Fkb3JhLmNvbS5ici9hYy1vbmxpbmVyZmIvbGNyLWFjLW9ubGluZXJmYnYyLmNybDBKoEigRoZEaHR0cDovL3JlcG9zaXRvcmlvLmljcGJyYXNpbC5nb3YuYnIvbGNyL1ZBTElEL2xjci1hYy1vbmxpbmVyZmJ2Mi5jcmwwDgYDVR0PAQH/BAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDCBvQYDVR0RBIG1MIGygR1maW5hbmNlaXJvQG1hc3RlcnBvbnRvLmNvbS5icqA4BgVgTAEDBKAvBC0wNTA2MTk4NTA3NTY4NTk1NjUwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDCgIwYFYEwBAwKgGgQYTkFUQUxJQSBNQUdBTkhBIERBIENPU1RBoBkGBWBMAQMDoBAEDjEyMjg3MjAzMDAwMTkwoBcGBWBMAQMHoA4EDDAwMDAwMDAwMDAwMDANBgkqhkiG9w0BAQsFAAOCAgEAu3q0uC0WksHrcbk+jVnnmbveNO/Ttqk5JT91lJeA8OKzNWuFIowoVxsKTBHn1qRsimss5xObsDXtKd7zUZkEvqdE1mFI3HWkm45bmc7ljGCdnQ7C4NhDVr08nMCRlxr+r+k/7+mlhdgdgmVjbxZwzbFATO4PKO3qYij7HMw/lzwWOsnmgNG6EAhTZtapT+G5OnA80ENmRYVeg/a0uzWrPmOKzMPnTG6FM86gZZ53Ge84KCtLad4MmWzMtlHsGz5KgxMauWL/iGMZ8I5YRzTzRmGUuRxWYijKMn5nIZpjJ/FrDzryJAyvaErbMmayhKx6+1AwLsEe+K7L2TsFIfhPVUvXgeSs2yg8of5wUeDTn1KYVEcBp4XCukgqiicHkgxfcfnf4lPwSHM09576i4mEn4u4sAoeiBuTgfRkuhsYu8cLGfWGArr46pc4++FglRBzOAHDAKziW35cVfpi8ycm2F0JCa4QDfNbIlGK08U4O25VvJ5/W8hCLeTHCWtHYtYfixPh/LLT1PB5up8dhxpmgIUJQtW2OT3tRfEzxoJ64uALpSNVYZ5dY6OnlrO2qW0bZU+Wdc5uzcDH7YeCoviZ/SOCcRW/9kq5MAGVbpTsN3u9lzqCJjSWavGwP+it9YRo8OpLxtgoISCe08zd9ckSJxJtUyRaQkZ1o1INKh7dotQ=</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
编辑
使用建议的代码,它在行中返回了一个错误
Reference reference = new Reference($"#{list[0].Attributes["id"].Value}");
:
NullReferenceException: Object reference not set to an instance of an object.
我是这样使用函数的:
SignXmlFile("E:\nota.xml", "InfDeclaracaoPrestacaoServico", EscolherCertificado());
这里是 XML 文件的示例,我正在使用函数:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.issweb.fiorilli.com.br/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Header />
<soapenv:Body>
<ws:gerarNfse>
<GerarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Rps>
<InfDeclaracaoPrestacaoServico>
<Rps>
<IdentificacaoRps>
<Numero>1</Numero>
<Serie>999</Serie>
<Tipo>1</Tipo>
</IdentificacaoRps>
<DataEmissao>2018-11-27</DataEmissao>
<Status>1</Status>
</Rps>
<Competencia>2018-11-27</Competencia>
<Servico>
<Valores>
<ValorServicos>209000</ValorServicos>
</Valores>
<IssRetido>2</IssRetido>
<ItemListaServico>01.05</ItemListaServico>
<Discriminacao>Discriminacao teste blablabla</Discriminacao>
<CodigoMunicipio>3504800</CodigoMunicipio>
<ExigibilidadeISS>1</ExigibilidadeISS>
</Servico>
<Prestador>
<CpfCnpj>
<Cnpj>01001001000113</Cnpj>
</CpfCnpj>
<InscricaoMunicipal>15000</InscricaoMunicipal>
</Prestador>
<Tomador>
<IdentificacaoTomador>
<CpfCnpj>
<Cpf>35770121025</Cpf>
</CpfCnpj>
</IdentificacaoTomador>
<RazaoSocial>DADOS TOMADOR</RazaoSocial>
<Endereco>
<Endereco>RUA TOMADOR</Endereco>
<Numero>23</Numero>
<Complemento>COMPLEMENTO TOMADOR</Complemento>
<Bairro>BAIRRO TOMADOR</Bairro>
<Uf>MG</Uf>
<CodigoPais>1058</CodigoPais>
<Cep>37170000</Cep>
</Endereco>
<Contato>
<Telefone>(35) 38511836</Telefone>
<Email>mariana@live.com</Email>
</Contato>
</Tomador>
<OptanteSimplesNacional>2</OptanteSimplesNacional>
<IncentivoFiscal>2</IncentivoFiscal>
</InfDeclaracaoPrestacaoServico>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>s8BhRVqeQKRh4H6nlHJEQudBJ+w=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>IxrI+sqg6XEg7Dl0utAlJviTKT5fTu1NTErntiSjb61B5q/nP68r4wZ12vqXW5/G92pr+ZUZfLVwnG8vrFx8tsX/eObfpwOxZRfissuuOVQrLmFmHOvLs08VpbkffQpvLIhkpDzLV3pcIPsjgo7UQu+99mB4K+iEZYnfedgmJ8s/6EIcJLoWs9TvJHfpANgbEXSndi0nua1uDr9/FN4oO0jD2lRX+JHp7XJNjcjzS1N/kFG+JSyq0R017Ul0F/qR7dcOsBlFvbXtPcYfT6jiZxHjNf5n0xuK1vBHiwGgFHRFf2oF+2/LwqrCVZxiIMZK3ICdGWfdKkc3YCJ5A4px/g==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>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</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</Rps>
</GerarNfseEnvio>
<username>01001001000113</username>
<password>123456</password>
</ws:gerarNfse>
</soapenv:Body>
</soapenv:Envelope>
对于您指出的问题,原因是您将 SignatureMethod
通知为 SHA-1:
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
但是您没有通知 reference.DigestMethod
作为 SHA-1,您可以看到那只是作为 SHA- 输出的 XML 部分256,所以你必须添加这一行(实际上你添加了,但它被注释掉了):
reference.DigestMethod = SignedXml.XmlDsigSHA1Url;
看看这个答案(葡萄牙语的Stack Overflow,但代码部分都是英文),它使用SHA-256,但思路是一样的:
但是,您的代码有点混乱,您正在做一些似乎没有必要的事情,例如将 XML 文件作为流打开,然后使用字符串加载 XmlDocument
从流中读取(为什么不直接打开 XML 文件作为 XmlDocument
?),最后你再次打开另一个 XmlDocument
...
但我认为最重要的部分是您期望输入 XML 中已经存在 Signature
标记,但不应该那样,您应该签署一个非-signed XML 文件,如果文件中已经存在签名,您应该在再次签名之前删除旧签名,因为签名过程需要整个文档来生成签名。
这里有一个关于如何使用 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());
我正在尝试使用 SHA-1 算法对 XML 文档进行数字签名,但生成的签名 XML 中包含 SHA-256 部分。我看到了这个
这是我的实际代码:
private void AssinarXml(string arquivo, string tagAssinatura, string tagAtributoId, X509Certificate2 x509Cert)
{
StreamReader SR = null;
try
{
SR = System.IO.File.OpenText(arquivo);
string xmlString = SR.ReadToEnd();
SR.Close();
SR = null;
// Create a new XML document.
XmlDocument doc = new XmlDocument();
// Format the document to ignore white spaces.
doc.PreserveWhitespace = false;
// Load the passed XML file using it’s name.
doc.LoadXml(xmlString);
if (doc.GetElementsByTagName(tagAssinatura).Count == 0)
{
throw new Exception("A tag de assinatura " + tagAssinatura.Trim() + " não existe no XML. (Código do Erro: 5)");
}
else if (doc.GetElementsByTagName(tagAtributoId).Count == 0)
{
throw new Exception("A tag de assinatura " + tagAtributoId.Trim() + " não existe no XML. (Código do Erro: 4)");
}
else
{
XmlDocument XMLDoc;
XmlNodeList lists = doc.GetElementsByTagName(tagAssinatura);
foreach (XmlNode nodes in lists)
{
foreach (XmlNode childNodes in nodes.ChildNodes)
{
if (!childNodes.Name.Equals(tagAtributoId))
continue;
if (childNodes.NextSibling != null && childNodes.NextSibling.Name.Equals("Signature"))
continue;
// Create a reference to be signed
Reference reference = new Reference("");
reference.Uri = "";
XmlElement childElemen = (XmlElement)childNodes;
if (childElemen.GetAttributeNode("Id") != null)
{
reference.Uri = ""; // "#" + childElemen.GetAttributeNode("Id").Value;
}
else if (childElemen.GetAttributeNode("id") != null)
{
reference.Uri = "#" + childElemen.GetAttributeNode("id").Value;
}
//reference.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1";
// Create a SignedXml object.
SignedXml signedXml = new SignedXml(doc);
// Add the key to the SignedXml document
signedXml.SigningKey = x509Cert.PrivateKey;
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
// Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
XmlDsigC14NTransform c14 = new XmlDsigC14NTransform();
reference.AddTransform(c14);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
// Create a new KeyInfo object
KeyInfo keyInfo = new KeyInfo();
// Load the certificate into a KeyInfoX509Data object
// and add it to the KeyInfo object.
keyInfo.AddClause(new KeyInfoX509Data(x509Cert));
// Add the KeyInfo object to the SignedXml object.
signedXml.KeyInfo = keyInfo;
signedXml.ComputeSignature();
// Get the XML representation of the signature and save
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
nodes.AppendChild(doc.ImportNode(xmlDigitalSignature, true));
}
}
XMLDoc = new XmlDocument();
XMLDoc.PreserveWhitespace = false;
XMLDoc = doc;
string conteudoXMLAssinado = XMLDoc.OuterXml;
using (StreamWriter sw = System.IO.File.CreateText(arquivo))
{
sw.Write(conteudoXMLAssinado);
sw.Close();
}
}
}
finally
{
if (SR != null)
SR.Close();
}
}
如何让这个函数像SHA1一样签名?
这是输出签名的示例:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>pp8br9Yd9SdFWQhFdCOJmJlEsKGnlbpovZ6Ssp7VwC4=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>ZSWsXhFu6qw5NGy8+hVAA8oW7nUp1vX2Wv+YpnFiC9UWTdRdYlUDjAiah9symfOX2tOEUk69aJjaL/bSZoc5BFFYqQOm2kBVnlbEYQ0lQpvy4sEJodTWiVGaikVldFWUjPkhjwxy9SpreOKBHpEOPkdkyb8SS8k5bE1yA6IbTE3JfyCmeojDSha3lVZzbX8rBN6R2Mwkwg9Eh9dOPjk4+Wu/V5APDQfDa9viQlDAG+gtBTQacMb2aZrNR8fYqm8fSbwhfxgBaMbCqp3A/KqEm9M5Tj8ql/5flRRJ1zmlrwvByfff5+unhdhMzhKcPeoEAkBBJu4RlJVDgf1BNnexNw==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>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</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
编辑
使用建议的代码,它在行中返回了一个错误
Reference reference = new Reference($"#{list[0].Attributes["id"].Value}");
:
NullReferenceException: Object reference not set to an instance of an object.
我是这样使用函数的:
SignXmlFile("E:\nota.xml", "InfDeclaracaoPrestacaoServico", EscolherCertificado());
这里是 XML 文件的示例,我正在使用函数:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.issweb.fiorilli.com.br/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Header />
<soapenv:Body>
<ws:gerarNfse>
<GerarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Rps>
<InfDeclaracaoPrestacaoServico>
<Rps>
<IdentificacaoRps>
<Numero>1</Numero>
<Serie>999</Serie>
<Tipo>1</Tipo>
</IdentificacaoRps>
<DataEmissao>2018-11-27</DataEmissao>
<Status>1</Status>
</Rps>
<Competencia>2018-11-27</Competencia>
<Servico>
<Valores>
<ValorServicos>209000</ValorServicos>
</Valores>
<IssRetido>2</IssRetido>
<ItemListaServico>01.05</ItemListaServico>
<Discriminacao>Discriminacao teste blablabla</Discriminacao>
<CodigoMunicipio>3504800</CodigoMunicipio>
<ExigibilidadeISS>1</ExigibilidadeISS>
</Servico>
<Prestador>
<CpfCnpj>
<Cnpj>01001001000113</Cnpj>
</CpfCnpj>
<InscricaoMunicipal>15000</InscricaoMunicipal>
</Prestador>
<Tomador>
<IdentificacaoTomador>
<CpfCnpj>
<Cpf>35770121025</Cpf>
</CpfCnpj>
</IdentificacaoTomador>
<RazaoSocial>DADOS TOMADOR</RazaoSocial>
<Endereco>
<Endereco>RUA TOMADOR</Endereco>
<Numero>23</Numero>
<Complemento>COMPLEMENTO TOMADOR</Complemento>
<Bairro>BAIRRO TOMADOR</Bairro>
<Uf>MG</Uf>
<CodigoPais>1058</CodigoPais>
<Cep>37170000</Cep>
</Endereco>
<Contato>
<Telefone>(35) 38511836</Telefone>
<Email>mariana@live.com</Email>
</Contato>
</Tomador>
<OptanteSimplesNacional>2</OptanteSimplesNacional>
<IncentivoFiscal>2</IncentivoFiscal>
</InfDeclaracaoPrestacaoServico>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>s8BhRVqeQKRh4H6nlHJEQudBJ+w=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>IxrI+sqg6XEg7Dl0utAlJviTKT5fTu1NTErntiSjb61B5q/nP68r4wZ12vqXW5/G92pr+ZUZfLVwnG8vrFx8tsX/eObfpwOxZRfissuuOVQrLmFmHOvLs08VpbkffQpvLIhkpDzLV3pcIPsjgo7UQu+99mB4K+iEZYnfedgmJ8s/6EIcJLoWs9TvJHfpANgbEXSndi0nua1uDr9/FN4oO0jD2lRX+JHp7XJNjcjzS1N/kFG+JSyq0R017Ul0F/qR7dcOsBlFvbXtPcYfT6jiZxHjNf5n0xuK1vBHiwGgFHRFf2oF+2/LwqrCVZxiIMZK3ICdGWfdKkc3YCJ5A4px/g==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>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</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</Rps>
</GerarNfseEnvio>
<username>01001001000113</username>
<password>123456</password>
</ws:gerarNfse>
</soapenv:Body>
</soapenv:Envelope>
对于您指出的问题,原因是您将 SignatureMethod
通知为 SHA-1:
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
但是您没有通知 reference.DigestMethod
作为 SHA-1,您可以看到那只是作为 SHA- 输出的 XML 部分256,所以你必须添加这一行(实际上你添加了,但它被注释掉了):
reference.DigestMethod = SignedXml.XmlDsigSHA1Url;
看看这个答案(葡萄牙语的Stack Overflow,但代码部分都是英文),它使用SHA-256,但思路是一样的:
但是,您的代码有点混乱,您正在做一些似乎没有必要的事情,例如将 XML 文件作为流打开,然后使用字符串加载 XmlDocument
从流中读取(为什么不直接打开 XML 文件作为 XmlDocument
?),最后你再次打开另一个 XmlDocument
...
但我认为最重要的部分是您期望输入 XML 中已经存在 Signature
标记,但不应该那样,您应该签署一个非-signed XML 文件,如果文件中已经存在签名,您应该在再次签名之前删除旧签名,因为签名过程需要整个文档来生成签名。
这里有一个关于如何使用 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());