C# 如何使用特殊字符对XML文件进行签名?

C# 如何使用特殊字符对XML文件进行签名?,c#,.net,xml,C#,.net,Xml,我必须对XML进行签名,这将返回错误“无效CAF签名”。(CAF=Código Autorización de Folios) 我有一个XML文件: <?xml version="1.0"?> <AUTORIZACION> <CAF version="1.0"> <DA> <RE>76521854-3</RE> <RS>SOCIEDAD FARMACEUTICA O&quot;HIGGINS SPA<

我必须对XML进行签名,这将返回错误“无效CAF签名”。(CAF=Código Autorización de Folios)

我有一个XML文件:

<?xml version="1.0"?>
<AUTORIZACION>
<CAF version="1.0">
<DA>
<RE>76521854-3</RE>
<RS>SOCIEDAD FARMACEUTICA O&quot;HIGGINS SPA</RS>
<TD>33</TD>
<RNG><D>101</D><H>200</H></RNG>
<FA>2020-05-28</FA>
<RSAPK><M>t6ldOQd1Mz+1tiYhaMvVCKeAyT2vQK4rqYCHtbMDWIAHBGwI3mr1mmgLUpXKfvisRl1pTY2RXWdZVd6vE12PSw==</M><E>Aw==</E></RSAPK>
<IDK>100</IDK>
</DA>
<FRMA algoritmo="SHA1withRSA">UQ85YCoqC+pBw7kjzU0g+0uufqKKg759DapDJP4Bt4LMk1mK4330cgBPpVh/iUo5oC9TxINqo0icwFYiAabskw==</FRMA>
</CAF>
<RSASK>-----BEGIN RSA PRIVATE KEY-----
MIIBOQIBAAJBALepXTkHdTM/tbYmIWjL1QingMk9r0CuK6mAh7WzA1iABwRsCN5q
9ZpoC1KVyn74rEZdaU2NkV1nWVXerxNdj0sCAQMCQHpw6NCvo3d/znluwPCH41sa
Vdt+dNXJcnEAWnkiAjr+4v/O/o8lhCUGHFaf/0B+1jp2kTnb7b/A4qrd9fxFs7sC
IQDm1L63s29TnXKNkSrlDPGRuqBa0IsmFoXM82Xp0aVhfwIhAMuv9tNUQ1vFbFM/
euaRSNk0CzSmOIanQDhiK9RHT6A1AiEAmeMpz8z04mj3CQtx7gihC9HAPIsHbrmu
iKJD8TZuQP8CIQCHyqSM4teSg52M1PyZtjCQzVzNxCWvGirQQXKNhN/AIwIgXDO7
2/zf8L8fGm6nrDl56Oiybnq0PIg67W4FJ3NBXxI=
-----END RSA PRIVATE KEY-----
</RSASK>

<RSAPUBK>-----BEGIN PUBLIC KEY-----
MFowDQYJKoZIhvcNAQEBBQADSQAwRgJBALepXTkHdTM/tbYmIWjL1QingMk9r0Cu
K6mAh7WzA1iABwRsCN5q9ZpoC1KVyn74rEZdaU2NkV1nWVXerxNdj0sCAQM=
-----END PUBLIC KEY-----
</RSAPUBK>
</AUTORIZACION>
对于反序列化,我将此方法与C#结合使用:

通过以下方式序列化TED对象时,将生成此XML文件:

XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.GetEncoding("ISO-8859-1");
settings.Indent = true;
settings.IndentChars = "";
settings.OmitXmlDeclaration = false;
using (XmlWriter xmlWriter = XmlWriter.Create(tempFilePath, settings))
{
      XmlSerializer s = new XmlSerializer(obj.GetType());                                                  
      s.Serialize(xmlWriter, obj, ns);
}
但是,
标记是用
\“
而不是
编写的,我认为这种转换是错误的原因

未成功采取的行动:

  • 以多种不同的方式将
    \“
    替换为
    。直接使用
    string.Replace()
    SecurityElement.Escape()
    ,即使我仍然收到此错误。有时(根据所做的替换),我会得到
    SOCIEDAD FARMACEUTICA O&;引用;希金斯水疗中心
  • 序列化和反序列化已使用ISO-8859-1编码完成。我曾尝试通过UTF-8改变这一点,但没有成功
  • 负责这项工作的政府机构说,但如果我这样做,我会得到这个错误“无效CAF标志”

    编辑

    马丁·霍宁的答案似乎有效。但这个“最终”XML是另一个更大的XML的一部分。当我签署此文件时,
    字符被替换为
    \”

    要签署的代码:

    XmlDocument doc = new XmlDocument();
    doc.PreserveWhitespace = true;
    doc.Load(filePath); //path where is the XML file. This XML has &quot; instead of \"
    
    SignedXml signedXml = new SignedXml(doc);
    signedXml.SigningKey = certificado.PrivateKey;
    Signature XMLSignature = signedXml.Signature;
    Reference reference = new Reference();
    reference.Uri = "#" + referenceID;
    
    XmlDsigC14NTransform t = new XmlDsigC14NTransform();
    reference.AddTransform(t);            
    
    XMLSignature.SignedInfo.AddReference(reference);
    KeyInfo keyInfo = new KeyInfo();
    keyInfo.AddClause(new RSAKeyValue((RSA)certificado.PrivateKey));
    keyInfo.AddClause(new KeyInfoX509Data(certificado));
    XMLSignature.KeyInfo = keyInfo;
    signedXml.ComputeSignature();
    
    XmlElement xmlDigitalSignature = signedXml.GetXml();
    doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true));
    doc.Save(filePath); //filepath is overwritten with \" instead of &quot;
    
    如何在C中保留
    而不是
    \”
    对该文件进行签名

    而不是

    using (XmlWriter xmlWriter = XmlWriter.Create(tempFilePath, settings))
    {
          XmlSerializer s = new XmlSerializer(obj.GetType());                                                  
          s.Serialize(xmlWriter, obj, ns);
    }
    
    您需要将现有的XmlWriter封装到自己的XmlWriter中,以更改
    的序列化,从而使用实体引用
    &apos

    using (EscapeQuotesXmlWriter exw = new EscapeQuotesXmlWriter(XmlWriter.Create(tempFilePath, settings)))
    {
          XmlSerializer s = new XmlSerializer(obj.GetType());                                                  
          s.Serialize(exw , obj, ns);
    }
    
    该类可以实现为
    XmlWrappingWriter

    public class EscapeQuotesXmlWriter : XmlWrappingWriter
    {
        public EscapeQuotesXmlWriter(XmlWriter baseWriter) : base(baseWriter)
        {
        }
    
        public override void WriteString(string text)
        {
            foreach (char ch in text)
            {
                if (ch == '"')
                {
                    WriteEntityRef("quot");
                }
                else if (ch == '\'')
                {
                    WriteEntityRef("apos");
                }
                else
                {
                    base.WriteString(ch.ToString());
                }
            }
        }
        public override void WriteChars(char[] buffer, int index, int count)
        {
            WriteString(new String(buffer.Where((ch, pos) => pos >= index && pos < index + count).ToArray()));
        }
    
    }
    

    我想您应该需要格式。

    在.NET framework API的上下文中,如果您确实需要确保元素数据中的双引号字符
    由实体引用
    表示”
    我认为您需要使用自己的XmlWriter实现,以确保它不会写出
    按字面意思,但作为
    使用。序列化时为什么要使用编码?不需要。xml是UTF-8,不会更改任何字符(0x80除外)。使用ISO-8859-1将修改字符。要使代码正常工作,必须与创建文件时的操作相反。因此,请使用XmlReaderSettings=new XmlReaderSettings();settings.Encoding=Encoding.GetEncoding(“ISO-8859-1”);XmlReader reader=XmlReader.Create(文件名,设置)“我必须对XML进行签名,并且返回错误“无效CAF符号”的部分是否已使用.NET代码完成?能否显示该代码?@MartinHonnen我将尝试您的链接,谢谢。我收到错误“无效CAF符号”“当我将此XML发送给政府机构时,他们会通过电子邮件回复我。谢谢。太棒了,这适用于序列化!但是当我对XML签名时,字符被替换。我的问题已更新。@GonzaloBustamante,
    Save
    方法是另一种序列化,在这种序列化中,正常的.NET框架不使用实体引用来表示元素中的双引号或单引号,因为它们是不需要的,但您当然也可以在其中使用“EscapeQuotesXmlWriter”。
    using (XmlWriter xmlWriter = XmlWriter.Create(tempFilePath, settings))
    {
          XmlSerializer s = new XmlSerializer(obj.GetType());                                                  
          s.Serialize(xmlWriter, obj, ns);
    }
    
    using (EscapeQuotesXmlWriter exw = new EscapeQuotesXmlWriter(XmlWriter.Create(tempFilePath, settings)))
    {
          XmlSerializer s = new XmlSerializer(obj.GetType());                                                  
          s.Serialize(exw , obj, ns);
    }
    
    public class EscapeQuotesXmlWriter : XmlWrappingWriter
    {
        public EscapeQuotesXmlWriter(XmlWriter baseWriter) : base(baseWriter)
        {
        }
    
        public override void WriteString(string text)
        {
            foreach (char ch in text)
            {
                if (ch == '"')
                {
                    WriteEntityRef("quot");
                }
                else if (ch == '\'')
                {
                    WriteEntityRef("apos");
                }
                else
                {
                    base.WriteString(ch.ToString());
                }
            }
        }
        public override void WriteChars(char[] buffer, int index, int count)
        {
            WriteString(new String(buffer.Where((ch, pos) => pos >= index && pos < index + count).ToArray()));
        }
    
    }
    
    using (EscapeQuotesXmlWriter exw = new EscapeQuotesXmlWriter(XmlWriter.Create(filePath)))
    {
       doc.Save(exw);
    }