Canonicalize and signing in C#

P

Pollux

Hi,

I'm having a problem canonicalizing an xml document and getting a hash
that matches that of an existing document so I was wondering if somebody
knew what I was doing wrong.

I generate an XML document and need to do the following:
- Canonicalize (14n) the XML Document
- Generate a 160-bit binary secure has from the canonicalized XML using
SHA-1 algorithm
- Encode the binary data using base-64 to produce a 28 characters string
- Encode the binary data using base-32 to produce an easily human
readable 32 characters string

I've included an example of a typical XML file below. The part that
needs to be canonicalized and hashed is the Body element. Within <Body>,
you'll notice an IRmark element. This element should not be there for
the process of canonicalization and hashing. It is in fact the hash of
the <body> element in base-64.

The code simply tries to do all the steps taking, a file called irmark-
canonical.xml which is identical to the one pasted below bar the IRmark
element not being there. I try to retrieve the <Body> element,
canonicalize it and hash it. I then retrieve the IRmark element in
irmark-example.xml (the file pasted below) and display the values on
screen. Well, they never match! I guess the biggest problem here is that
I'm just not very familiar with all these processes and I'm unsure which
functions to use.

I also attached a java code snippet which was provided by the
organization that is at the receiving end of the document. Maybe this
will help figuring out what I'm doing wrong? I haven't been
able to figure out how to get the
base-32 requirement either.

Any help will be greatly appreciated.

Pollux

XML File
++++++++
<?xml version="1.0"?>
<!-- Generic IRmark example instance - supplied credentials are not to
be used for any other purpose --> <GovTalkMessage
xmlns="http://www.govtalk.gov.uk/CM/envelope">
<EnvelopeVersion>2.0</EnvelopeVersion>
<Header>
<MessageDetails>
<Class>IR-SA-SA100</Class>
<Qualifier>request</Qualifier>
<Function>submit</Function>
<CorrelationID></CorrelationID>
<Transformation>XML</Transformation>
<GatewayTest>1</GatewayTest>
<GatewayTimestamp></GatewayTimestamp>
</MessageDetails>
<SenderDetails>
<IDAuthentication>
<SenderID>SA0154</SenderID>
<Authentication>
<Method>clear</Method>
<Role>principal</Role>
<Value>testing1</Value>
</Authentication>
</IDAuthentication>
</SenderDetails>
</Header>
<GovTalkDetails>
<Keys>
<Key Type="UTR">1000000154</Key>
</Keys>
<TargetDetails>
<Organisation>IR</Organisation>
</TargetDetails>
<ChannelRouting>
<Channel>
<URI>9999</URI>
<Product>Generic IRmark</Product>
<Version>1.0</Version>
</Channel>
</ChannelRouting>
</GovTalkDetails>
<Body>
<IRenvelope xmlns="http://www.govtalk.gov.uk/taxation/SA">
<IRheader>
<TestMessage>0</TestMessage>
<Keys>
<Key Type="UTR">1000000154</Key>
</Keys>
<PeriodEnd>2004-04-05</PeriodEnd>
<Manifest>
<Contains>
<Reference>
<Namespace>
http://www.inlandrevenue.gov.uk</Namespace>
<SchemaVersion>2004-v1.0
</SchemaVersion>
<TopElementName>SA100
</TopElementName>
</Reference>
</Contains>
</Manifest>
<IRmark Type="generic">
v0wMpG9kYq0AJzQG4/rXQu/wejE=</IRmark>
<Sender>Individual</Sender>
</IRheader>
<SA100><MainReturn><FullName>Case 1</FullName>
<SelfEmployment>yes</SelfEmployment>
<StudentLoanLiable>no
</StudentLoanLiable>
<TaxCalculation><CalculateOwnTax>yes
</CalculateOwnTax>
<Class4NICdue>9.36
</Class4NICdue>
<TotalTaxDue>21.06
</TotalTaxDue>

<ClaimToReduceYourPaymentsOnAccount>no
</ClaimToReduceYourPaymentsOnAccount>
</TaxCalculation>
<ClaimRepayment><Claim>no</Claim>
</ClaimRepayment>
<OtherPersonalDetails><Forename>John
</Forename>
<MaritalStatus>S
</MaritalStatus>
<NINO>YY672978C</NINO>
</OtherPersonalDetails>

<FurtherInformation><DoNotWantToPayThroughTaxCoding>no
</DoNotWantToPayThroug
hTaxCoding>


<ReliefClaimedNowForCertainLosses>no</ReliefClaimedNowForCertainLosses>
<PostCessationReceiptsEtc>no
</PostCessationReceiptsEtc>
</FurtherInformation>
</MainReturn>

<SelfEmployments><SelfEmployment><BusinessDetails><NameOfBusiness>B
</NameOfB
usiness>
<Description>Plumber
</Description>
<Address><Line>Address
</Line>
</Address>
<AccountingPeriodStart>
2003-01-01</AccountingPeriodStart>
<AccountingPeriodEnd>
2003-08-31</AccountingPeriodEnd>
<DetailsChanged>no
</DetailsChanged>
<DateOfCessation>2003-
08-31</DateOfCessation>
<SpecialArrangements>no
</SpecialArrangements>

<EnteredDetailsElsewhere>no</EnteredDetailsElsewhere>
<DoNotCover>no
</DoNotCover>
<DateHasChanged>no
</DateHasChanged>
<FurtherChange>no
</FurtherChange>
</BusinessDetails>
<CapitalAllowancesSummary>
<Cars>1161.00</Cars>
<TotalAllowances>1161.00
</TotalAllowances>

<EnhancedCapitalAllowances>no</EnhancedCapitalAllowances>
</CapitalAllowancesSummary>
<IncomeAndExpenses><IncludeVAT>
no</IncludeVAT>
<SalesBusinessIncome>
16788.00</SalesBusinessIncome>

<DisallowableSubContractorCosts>270.00</DisallowableSubContractorCosts>

<DisallowableEmployeeCosts>212.00</DisallowableEmployeeCosts>

<DisallowableMotorExpenses>143.00</DisallowableMotorExpenses>
<DisallowableTravel>
62.00</DisallowableTravel>
<GrossProfitLoss>
16788.00</GrossProfitLoss>
<EmployeeCosts>1500.00
</EmployeeCosts>
<PremisesCosts>1252.00
</PremisesCosts>

<GeneralAdministrativeExpenses>961.00
</GeneralAdministrativeExpenses>
<MotorExpenses>3133.00
</MotorExpenses>
<Travel>545.00</Travel>
<LegalCosts>2150.00
</LegalCosts>
<OtherExpenses>59.00
</OtherExpenses>
<TotalExpenses>9600.00
</TotalExpenses>
<NetProfitOrLoss>7188.00
</NetProfitOrLoss>
</IncomeAndExpenses>
<TaxAdjustments>
<DisallowableExpenses>687.00</DisallowableExpenses>

<TotalAdditionsToNetProfit>687.00</TotalAdditionsToNetProfit>
<CapitalAllowances>
1161.00</CapitalAllowances>

<DeductionsFromNetProfit>1161.00</DeductionsFromNetProfit>
<NetProfitLoss>6714.00
</NetProfitLoss>
</TaxAdjustments>

<AdjustmentsForTaxableProfitOrLoss><BasisPeriodBegins>2003-01-01
</BasisPerio
dBegins>
<BasisPeriodEnds>2003-
08-31</BasisPeriodEnds>
<ProfitFromOtherBoxes>
6714.00</ProfitFromOtherBoxes>

<OverlapProfitBroughtForward>1982.00</OverlapProfitBroughtForward>
<ReliefUsedThisYear>
1982.00</ReliefUsedThisYear>
<NetProfit>4732.00
</NetProfit>

<TaxableProfitAfterBroughtForward>4732.00
</TaxableProfitAfterBroughtForward>
<TotalTaxableProfits>
4732.00</TotalTaxableProfits>
<Provisional>no
</Provisional>

</AdjustmentsForTaxableProfitOrLoss>

<SummaryOfBalanceSheet><Assets><StockAndWorkInProgress>250.00
</StockAndWorkI
nProgress>
<BankEtcBalances>
2591.00</BankEtcBalances>
<TotalAssets>
2841.00</TotalAssets>
</Assets>
<NetBusinessAssets>
2841.00</NetBusinessAssets>

<CapitalAccount><BalanceAtStartOfPeriod>2403.00</BalanceAtStartOfPeriod>
<NetProfitLoss>
7188.00</NetProfitLoss>
<Drawings>6750.00
</Drawings>

<CapitalAccountBalanceAtEndOfPeriod>2841.00
</CapitalAccountBalanceAtEndOfPer
iod>
</CapitalAccount>
</SummaryOfBalanceSheet>
</SelfEmployment>
</SelfEmployments>
</SA100>
</IRenvelope>
</Body>
</GovTalkMessage>

C# Code
++++
using System;
using System.Xml;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Windows.Forms;
using System.IO;
using System.Text;

namespace irmark
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
XmlDocument docStripped = new XmlDocument();
docStripped.Load("irmark-canonical.xml");
XmlNamespaceManager nsmgr = new
XmlNamespaceManager(docStripped.NameTable);

// The default namespace has been changed. We need
to create a prefix for it
nsmgr.AddNamespace("tax",
"http://www.govtalk.gov.uk/taxation/SA" );
nsmgr.AddNamespace("env",
"http://www.govtalk.gov.uk/CM/envelope" );

XmlNode strippedNode = docStripped.SelectSingleNode
("//env:Body", nsmgr);
XmlDocument myDoc = new XmlDocument();
myDoc.LoadXml(strippedNode.OuterXml);

XmlDocument docOriginal = new XmlDocument();
docOriginal.Load("irmark-example.xml");
XmlNode currentNode =
docOriginal.DocumentElement.SelectSingleNode("//tax:IRmark", nsmgr);
string correctIRmark = currentNode.InnerText;

XmlDsigC14NTransform t = new XmlDsigC14NTransform();
t.LoadInput (myDoc);
Stream s = (Stream) t.GetOutput(typeof(Stream));
SHA1 sha1 = SHA1.Create();

byte[] hash = sha1.ComputeHash(s);
Console.WriteLine("Original IRmark: " +
correctIRmark);
string base64String = Convert.ToBase64String(hash);
Console.WriteLine("My IRmark: " + base64String);
}
}
}

Java Code
+++++++++

import java.io.*;
import javax.xml.parsers.*;
import java.security.*;

import org.w3c.dom.*;

import org.apache.xml.security.signature.*;
import org.apache.xml.security.transforms.*;
import org.apache.xml.security.Init;

import org.bouncycastle.util.encoders.Base64;

/**
* This code generates an IRmark value for an input document.
* The value is a base64 encoded SHA1 digest of a signature
* transform over a certain style of document. The value has
* to be placed inside documents to be signed by the XPE when
* used in a EDS/IR deployment.
*
* The code has a number of jar dependencies:-
* xmlsec.jar - The Apache XML Security Library
* log4j-1.2.5.jar - The Apache Log utility
* xalan.jar - Apache XSLT/XPath processor
* xercesImpl.jar - Apache XML processor
* bc-jce-jdk13-114.jar - Bouncy Castle JCE library
*
* The Bouncy Castle JCE provider is automatically downloaded
* by the Apache XML sec library build so you may already have
* that.
*/
public class IRMark {

/**
* Generate and print the IRmark.
*
* @Param args - Pass the filename of the input document
* @throws Exception
*/
public static void main(String args[]) throws Exception {

// Init the Apache XML security library
Init.init();

// Check we are given a file to work with
if (args.length!=1) {
System.out.println("Use: IRmark <file> ");
return;
}

// Open the input file
FileInputStream fis=null;
try {
fis=new FileInputStream(args[0]);
} catch (FileNotFoundException e) {
System.out.println("The file " + args[0] + " could
not be opened.");
return;
}

// Load file into a byte array
byte[] data=null;
try {
int bytes=fis.available();
data=new byte[bytes];
fis.read(data);
} catch (IOException e) {
System.out.println("Error reading file.");
e.printStackTrace();
}

// First part is to run the a transform over the input to
extract the
// fragment to be digested. This is done by setting up a
Transforms
// object from a Template and then executing against the
input document

// The transforms to be performed are specified by using
the template XML below.
String transformStr =
"<?xml version='1.0'?>\n"
+ "<dsig:Transforms
xmlns:dsig='http://www.w3.org/2000/09/xmldsig#'
xmlns:gt='http://www.govtalk.gov.uk/CM/envelope'
xmlns:ir='http://www.govtalk.gov.uk/taxation/SA'>\n"
+ "<dsig:Transform
Algorithm='http://www.w3.org/TR/1999/REC-xpath-19991116'>\n"
+ "<dsig:XPath>\n"
+
"count(ancestor-or-self::node()|/gt:GovTalkMessage/gt:Body)=count
(ancestor-o
r-self::node())\n"
+ " and count(self::ir:IRmark)=0 \n"
+ " and count(../self::ir:IRmark)=0 \n"
+ "</dsig:XPath>\n"
+ "</dsig:Transform>\n"
+ "<dsig:Transform
Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315
#WithComments'/>\n
"
+ "</dsig:Transforms>\n"
;

// Parse the transform details to create a document
DocumentBuilderFactory
dbf=DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db=dbf.newDocumentBuilder();
Document doc=db.parse(new ByteArrayInputStream
(transformStr.getBytes()));

// Construct a Apache security Transforms object from that
document
Transforms transforms = new Transforms
(doc.getDocumentElement(), null);

// Now perform the transform on the input to get the
results.
XMLSignatureInput input = new XMLSignatureInput(data);
XMLSignatureInput result = transforms.performTransforms(input);

// Uncomment this line to see transform output
// System.out.println(new String(result.getBytes()));

// Second part is to run output via SHA1 digest
// This is done via the standard java.security API
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(result.getBytes());
byte[] digest=md.digest();

// And finally print a Base64 of the digest with
// The help of the BouncyCastle JCE library
System.out.println("IRmark: " + new String(Base64.encode
(digest)));
}
}
 
Joined
Apr 25, 2007
Messages
1
Reaction score
0
Did you ever get this working. I have the exact same requirement and I am having some issues. Please let me know if you ever got this working
Thanks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top