C#计算并验证SEPA(XML)支付文件的SHA256值

时间:2013-08-27 07:52:54

标签: c# xml sha256 digest canonicalization

我正在努力解决像Markus Dreyer这样的问题: C# Calculate SHA256 value for SEPA (XML) paymentfile

根据DFÜ协议,我必须计算sha256哈希值:

  • 使用整个包含的文档创建哈希值,包括开始和结束标记。
  • 根据Canonical XML 1.0版对文档进行规范化。 (http://www.w3.org/TR/2001/REC-xml-c14n-20010315)。
  • 在包含文件的情况下,也可以根据主文件执行册封。
  • SHA-256用作哈希算法。

这是一个有效的xml文件示例(从金融工具中导出):

<?xml version="1.0" encoding="UTF-8"?>
<conxml xmlns="urn:conxml:xsd:container.nnn.002" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:conxml:xsd:container.nnn.002 container.nnn.002.xsd">
  <CreDtTm>2013-08-27T07:20:25Z</CreDtTm>
  <MsgPain001>
    <HashValue>33E579FE7A9AF6C32C100E8578EBD63E54A2DF47C6849F7A4BC8BEA9E2794197</HashValue>
    <HashAlgorithm>SHA256</HashAlgorithm>
    <Document xmlns="urn:swift:xsd:$pain.001.002.02">
      <pain.001.001.02>
        <GrpHdr>
          <MsgId>D005201308270920191</MsgId>
          <CreDtTm>2013-08-27T07:20:19Z</CreDtTm>
          <BtchBookg>true</BtchBookg>
          <NbOfTxs>1</NbOfTxs>
          <CtrlSum>0.50</CtrlSum>
          <Grpg>MIXD</Grpg>
          <InitgPty>
            <Nm>Test</Nm>
          </InitgPty>
        </GrpHdr>
        <PmtInf>
          <PmtInfId>D005201308270920191</PmtInfId>
          <PmtMtd>TRF</PmtMtd>
          <PmtTpInf>
            <SvcLvl>
              <Cd>SEPA</Cd>
            </SvcLvl>
          </PmtTpInf>
          <ReqdExctnDt>2013-08-27</ReqdExctnDt>
          <Dbtr>
            <Nm>Test</Nm>
          </Dbtr>
          <DbtrAcct>
            <Id>
              <IBAN>DE76200700000888888888</IBAN>
            </Id>
          </DbtrAcct>
          <DbtrAgt>
            <FinInstnId>
              <BIC>DEUTDEHHXXX</BIC>
            </FinInstnId>
          </DbtrAgt>
          <ChrgBr>SLEV</ChrgBr>
          <CdtTrfTxInf>
            <PmtId>
              <EndToEndId>NOTPROVIDED</EndToEndId>
            </PmtId>
            <Amt>
              <InstdAmt Ccy="EUR">0.50</InstdAmt>
            </Amt>
            <CdtrAgt>
              <FinInstnId>
                <BIC>DEUTDEHHXXX</BIC>
              </FinInstnId>
            </CdtrAgt>
            <Cdtr>
              <Nm>Erwin Mustermann</Nm>
            </Cdtr>
            <CdtrAcct>
              <Id>
                <IBAN>DE09200700000123456789</IBAN>
              </Id>
            </CdtrAcct>
            <RmtInf>
              <Ustrd>Sepa Test Gutschrift</Ustrd>
            </RmtInf>
          </CdtTrfTxInf>
        </PmtInf>
      </pain.001.001.02>
    </Document>
  </MsgPain001>
</conxml>

根据Markus Dreyer的解决方案,这是我的代码:

System.Text.UTF8Encoding enc = new UTF8Encoding(false);

XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load(@"path to file");
XmlNodeList list = doc.GetElementsByTagName("Document");
String s = list.Item(0).OuterXml;


MemoryStream msIn = new MemoryStream(enc.GetBytes(s));

XmlDsigC14NTransform t = new XmlDsigC14NTransform(true);
t.LoadInput(msIn);
MemoryStream ms = new MemoryStream();
ms = (MemoryStream)t.GetOutput(typeof(MemoryStream));


byte[] digest = t.GetDigestedOutput(new SHA256Managed());
String result = BitConverter.ToString(digest).Replace("-", String.Empty);

在我的计算中,我得到了价值: 55B2597B0688AB1A19760B542AA70AEF4F980D7BC9D6EBCF2B741F6299C661D3 但预计是文件中的值: 33E579FE7A9AF6C32C100E8578EBD63E54A2DF47C6849F7A4BC8BEA9E2794197

你们有没有想法,我缺少什么?

1 个答案:

答案 0 :(得分:3)

通过查看此处http://www.mobilefish.com/download/sepa_xml/pain.001.001.02.xml,您似乎错过了Document节点中的xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"命名空间(可能是因为它被XML解析器剥离)。我修改了一些代码,以便它使用using语法,如果缺少,我添加了命名空间。现在它返回正确的哈希。

XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.LoadXml(xml);

XmlNodeList list = doc.GetElementsByTagName("Document");

XmlElement node = (XmlElement)list[0];
node.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");

string s = node.OuterXml;

// The XmlDsigC14NTransform will strip the UTF8 BOM
using (MemoryStream msIn = new MemoryStream(Encoding.UTF8.GetBytes(s)))
{
    XmlDsigC14NTransform t = new XmlDsigC14NTransform(true);
    t.LoadInput(msIn);

    using (var hash = new SHA256Managed())
    {
        byte[] digest = t.GetDigestedOutput(hash);
        string result = BitConverter.ToString(digest).Replace("-", String.Empty);
    }
}