Question

i am struggling with the same issue like Markus Dreyer: C# Calculate SHA256 value for SEPA (XML) paymentfile

According to the DFÜ Agreement i have to calculate a sha256 hash value:

  • The hash value is created using the entire contained document, including the opening and closing tag.
  • The document is canonicalized according to Canonical XML, version 1.0. (http://www.w3.org/TR/2001/REC-xml-c14n-20010315).
  • In the case of included documents, the canonisation has also to be executed accord-ing to the main document.
  • SHA-256 is used as hash algorithm.

This is a sample valid xml File ( exported from an financial tool ) :

<?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>

According to the Solution from Markus Dreyer, here is my code:

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);

In my calculation i got the value: 55B2597B0688AB1A19760B542AA70AEF4F980D7BC9D6EBCF2B741F6299C661D3 but expected is the value from the file: 33E579FE7A9AF6C32C100E8578EBD63E54A2DF47C6849F7A4BC8BEA9E2794197

Have any of you an idea, what i am missing?

Was it helpful?

Solution

By looking here http://www.mobilefish.com/download/sepa_xml/pain.001.001.02.xml, it seems you were missing the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" namespace from the Document node (probably because it was stripped by an XML parser). I have modified a little your code so that it use the using syntax and I added the namespace if missing. Now it returns the right hash.

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);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top