Thursday, March 23, 2006

X509Certificate Enveloped Signing XML

Couple of days back I was asked to research on Cryptography in .NET Framework v1.1 to digitally sign a document Here is the code which I developed using VB.NET to sign XML file

*******************************************************************




Dim store As WSE.X509CertificateStore

Dim MyCert As System.Security.Cryptography.X509Certificates.X509Certificate

store = WSE.X509CertificateStore.CurrentUserStore(WSE.X509CertificateStore.MyStore)

store.OpenRead()

For Each cert As X509Certificate In store.Certificates

MyCert = DirectCast(cert, System.Security.Cryptography.X509Certificates.X509Certificate)

Next

store.Close()

' This example signs a file specified by a URI

' using a detached signature. It then verifies

' the signed XML.

'

' The URI to sign.

Dim resourceToSign As String = "#MyObjectId"

' The name of the file to which to save the XML signature.

Dim XmlFileName As String = "C:\xmldsig.xml"

Try

Dim FILE As String = "c:\File.doc"

Dim Key As New RSACryptoServiceProvider

Dim prm As RSAParameters = Key.ExportParameters(True)

' Sign the detached resource and save the signature in an XML file.

SignResource(FILE, resourceToSign, XmlFileName, Key, MyCert)

Key.ImportParameters(prm)

MsgBox(VerifyXmlFile(FILE, XmlFileName, prm))

Catch ex As CryptographicException

Console.WriteLine(ex.Message)

End Try

*******************************************************************

' Sign an XML file and save the signature in a new file.

Public Sub SignResource(ByVal OriginalFile As String, ByVal URIString As String, ByVal XmlSigFileName As String, ByVal Key As RSA, ByVal Certificate As WSE.X509Certificate)

' Create the XmlDocument.

Dim doc As XmlDocument = New XmlDocument

doc.LoadXml("<FileInfo></FileInfo>")

' Add a price element.

Dim newElem As XmlElement = doc.CreateElement("Hash")

'Generate the Hash

newElem.InnerText = GetHash(OriginalFile)

doc.DocumentElement.AppendChild(newElem)

' Create a SignedXml object.

Dim signedXml As New SignedXml(doc)

' Create a data object to hold the data to sign.

Dim dataObject As New DataObject

dataObject.Data = doc.ChildNodes

dataObject.Id = "MyObjectId"

' Add the data object to the signature.

signedXml.AddObject(dataObject)

' Assign the key to the SignedXml object.

signedXml.SigningKey = Key

' Create a reference to be signed.

Dim reference As New Reference

'' Add the passed URI to the reference object.

reference.Uri = URIString

' Add the reference to the SignedXml object.

signedXml.AddReference(reference)

' Create a new KeyInfo object.

Dim keyInfo As New KeyInfo

' Load the certificate into a KeyInfoX509Data object

' and add it to the KeyInfo object.

keyInfo.AddClause(New KeyInfoX509Data(Certificate))

' Add the KeyInfo object to the SignedXml object.

signedXml.KeyInfo = keyInfo

' Compute the signature.

signedXml.ComputeSignature()

' Get the XML representation of the signature and save

' it to an XmlElement object.

Dim xmlDigitalSignature As XmlElement = signedXml.GetXml()

doc.DocumentElement.AppendChild(signedXml.GetXml())

' Save the document to a file and auto-indent the output.

Dim writer As XmlTextWriter = New XmlTextWriter("test.xml", Nothing)

writer.Formatting = Formatting.Indented

doc.Save(writer)

writer.Close()

' Save the signed XML document to a file specified

' using the passed string.

Dim xmltw As New XmlTextWriter(XmlSigFileName, New UTF8Encoding(False))

xmlDigitalSignature.WriteTo(xmltw)

xmltw.Close()

End Sub

*******************************************************************

' Verify the signature of an XML file against an asymetric

' algorithm and return the result.

Public Function VerifyXmlFile(ByVal OriginalFile As String, ByVal Name As [String], ByVal KeyParameter As RSAParameters) As [Boolean]

' Create a new XML document.

Dim xmlDocument As New XmlDocument

' Load the passed XML file into the document.

xmlDocument.Load(Name)

Dim HashElement As XmlElement = CType(xmlDocument.GetElementsByTagName("Hash")(0), XmlElement)

Dim CurrentHash As String = GetHash(OriginalFile)

If HashElement.InnerXml <> CurrentHash Then

Throw New ApplicationException("Signature Failed at Hash level check")

End If

Dim signedXml As New SignedXml(xmlDocument)

Dim nodeList As XmlNodeList = xmlDocument.GetElementsByTagName("Signature")

' Load the signature node.

signedXml.LoadXml(CType(nodeList(0), XmlElement))

Dim Key As New RSACryptoServiceProvider

Key.ImportParameters(KeyParameter)

' Check the signature and return the result.

Return signedXml.CheckSignature(Key)

End Function

*******************************************************************


Public Function GetHash(ByVal File As String) As String

Dim SHAHasher As New System.Security.Cryptography.SHA1Managed

Dim SHAHash() As Byte = SHAHasher.ComputeHash(GetByte(File))

Dim SHAHashString As String = System.Convert.ToBase64String(SHAHash)

Return SHAHashString

End Function



Happy Programming

– S

No comments:

Search