Pure and Secure XML Generation of Word Documents

Feb 11, 11:00 pm

Article Author: Mauricio Grimberg
.NET 3.5 Books

Introduction


This article will focus on building an application that will show how to use XML to build a pure Word document. Specifically I will show how to build a client – for the purposes of this article I’ll take an Outlook 2003 client as an example – that can request a Word document by means of an e-mail message whose body is automatically signed using an XML Digital Signature and RSA asymmetric keys for security. The server application will also be Outlook 2003; it will receive the e-mail and after the client is verified using the digital signature will:


  • Generate the requested Word document via XML tools

  • Attach it to a new e-mail in reply to the request

  • Send it through Outlook 2003

In a previous article I did something similar with Excel and ASP.NET and in this article I will do it with a few new tools – Outlook, Word, SQL Server, the .NET framework and a little XML. The documentation about Word XML format that I’ll use throughout this article is in the Schema specification and help files from the Microsoft Office Word 2003 XML SDK.


I will use a similar fictitious scenario that I used in my previous Excel article, so let’s quickly refresh the previous that idea that concerned international espionage.


Last time "James" saw an aspx page inviting him to reduce costs and, a link offering more information brought him to another page returning an Excel pivot table. But many ASP Today visitors requesting those pages produced a saturation on the server and M decided to verify that whoever asked for the information is really who they claim they are.


In this scenario let us assume James doesn’t use Excel, he prefers Word documents and does not have the time or ambition to learn.


With the scenario set we are ready to get onto creating the application.


System Requirements


In order to run the sample code you should have the following:


  • .NET Framework version 2.0

  • Visual Studio 2005

  • MSDE, SQL server Express or SQL Server (2000 or 2005) with the Northwind sample database installed

  • Word and Outlook 2003

This article assumes you have a basic understanding of .NET, XML, and ADO.NET.


Installing and Compiling the Sample Code


The sample download for this article contains four C# VS 2005 projects and a stored procedure for SQL Server:


  • KeyGenerator : A Windows application that generates an RSA key and saves it as XML (the user is required to enter a path to save the file by means of a dialog box).

  • OutlookAddinAspToday: An Outlook Addin that uses the generated key to digitally sign an e-mail and (oppositely) verify it and send the Word document.

  • Signer: A .NET class library designed to sign and verify an XML Digital Signature.

  • WordML: A .NET class library designed to generate an XML Word Document.

  • CreateSP.sql: A script file with the code to generate a stored procedure that retrieves the data to be included in the Word document.

To install the sample, follow these steps:


  • Replace the value of the following project settings in the WordML library (or, alternately, you can do it in the app.config file of the project):

  • WriteRawPath- the directory path where you put the files that come into the WriteRaw directory in the WordML project

  • ConnString: your Connection String to Northwind

  • Run the SQL script CreateSP.sql for the Northwind database in SQL Server so a the Store Procedure is created

  • Open the OutlookAddinAspToday project and build it.

  • Start the debugger in the project so the Addin is installed in Outlook 2003

Sample Application Overview


Let me start by going through an overview of the application I will be building throughout the article. Since I will be using encryption, I will need to generate an RSA Key to be used to sign the message. In our sample situation this will allow James to select the file containing the key when Outlook (the Addin actually) asks him for it. I’ll generate this key (see Figure 1) and save it (see Figure 2) to an XML file using the KeyGenerator Windows Application.



Figure 1. The KeyGenerator application in action.


After clicking on the Build the key button the user is prompted to save the key as seen in Figure 2.



Figure 2. Selecting the path and the name of the file or leaving the default name


After the key has been generated and saved, you can view it as shown in Figure 3



Figure 3. The RSA key viewed as XML in Internet Explorer


The Outlook addin application looks for the subject of the e-mails to be ToM, if it is James will be asked for an XML file containing the key, whereupon the body of the e-mail will be wrapped with an XML digital signature and sent. Now James can obtain this file, suitable for any message to be sent to M, using this little application and use it to sign his e-mail (as seen in Figure 4). The idea behind this in this article is that James can save this key on any device (such USB memory stick, wrist watch, a CD, key protection specific devices, etc.). For this reason he’ll be asked for the source path of the key when it is required. The next application is the Outlook Addin.



Figure 4. The user writes an e-mail with the subject ToM
This figure has been reduced in size to fit in the text. To view the full image Click here


When the Outlook Addin sees that the e-mail’s subject is ToM it starts the process of signing and sending the e-mail:


  1. Outlook notices the e-mail subject being as ToM

  2. Requests the user for the key file (see Figure 5)

  3. Signs the message with the key provided

  4. Changes the subject to Message from James

  5. Finally, Outlook sends the email


  6. Figure 5. Outlook requesting the user for the path where his key (saved as XML) is.


Next, the body of the e-mail is put into an XML document and signed with the XML digital signature (using the key) and, finally, the e-mail is sent. When the message is sent it will look like Figure 6. Notice that it looks like a bunch of mixed up characters and the real message cannot be read!



Figure 6. Appearance of the message when sent.
This figure has been reduced in size to fit in the text. To view the full image Click here


And then the Addin will automatically send the e-mail with the Word document attached. Thus, M receives the e-mail and verifies James identity, then replies to James (see Figure 7) with another e-mail with the Word document



Figure 7. M replies to James
This figure has been reduced in size to fit in the text. To view the full image Click here


And, finally, James can read the Word document sent by M as seen in Figure 8.



Figure 8. The document as seen in Word
This figure has been reduced in size to fit in the text. To view the full image Click here


At the Database


The sample uses the Northwind database that ships with SQL Server (if you havent already got this database you can download it from Microsoft web site (see the links section of this article) to create the content for the Word document. A Store Procedure whose name is ToWordAspTodayArticle has the following code:



SELECT CategoryName, SUM AS Total 
FROM
(SELECT dbo.Categories.CategoryName, dbo.Products.ProductName, CONVERT * (1 – dbo.[Order Details].Discount) / 100) * 100 AS ProductSales, dbo.Employees.LastName + ‘, ‘ + dbo.Employees.FirstName AS Employee, dbo.Orders.OrderDate
FROM dbo.Categories
INNER JOIN dbo.Products
ON dbo.Categories.CategoryID = dbo.Products.CategoryID
INNER JOIN dbo.Orders
INNER JOIN dbo.[Order Details]
ON dbo.Orders.OrderID = dbo.[Order Details].OrderID
ON dbo.Products.ProductID = dbo.[Order Details].ProductID
INNER JOIN dbo.Employees
ON dbo.Orders.EmployeeID = dbo.Employees.EmployeeID
WHERE (dbo.Orders.ShippedDate BETWEEN ‘19970101’ AND ‘19971231’)
GROUP BY dbo.Categories.CategoryName, dbo.Products.ProductName, CONVERT * (1 – dbo.[Order Details].Discount) / 100) * 100, dbo.Employees.LastName + ‘, ‘ + dbo.Employees.FirstName, dbo.Orders.OrderDate)
DERIVEDTBL GROUP BY CategoryName


XML Digital Signature Basics


Sometimes it is necessary to know precisely and securely who really sent information and if the original information remains unchanged. One common solution is called PKI (public key infrastructure) which provides a signing solution. In short if somebody signs a document with their private key it can be verified with their public key and vice versa.


In this article I’ll use RSA keys (The RSAacronym is derived from the names of its authors, R.L. Rivest, A. Shamir, and L. Adleman). More information on RSA can be found in the links section for this article. XML signatures and XML encryption are security initiatives designed to work with XML data and thus work well with the sample application.


XML digital signatures provide the following:


  • Determine the resources to sign via a Uniform Resource Identifier (URI)

  • Create a digest for those resources using a predefined algorithm (I’m using in this example SHA1 – Secure Hash Algorithm 1 – because there is not a way yet to create a signature using RSA and SHA-256 in .NET managed code)

  • Canonicalize the XML: it implies bring the xml to a tidy and standardized form that takes into account information irrelevant as XML but necessary to fix the strings to sign (the order of the attributes, the whitespaces, etc).

  • Create a sign for the digest using the RSA algorithm with the key

  • Add some optional information like the public key and certificates

  • XML Digital Signature generate an XML element named signature containing all the signature information that can be attached to the document

There are three types of signatures:


  1. Enveloped: This is where the signature is contained in an XML document which contains what is signed too. This is what I’ll use in the article.

  2. Enveloping: The Signed resource is put into the signature.

  3. Detached: This is where the signature is detached or separate from the message.

You can see here an example of the node that represents the fragment of the XML containing the digital signature:



<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
    <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-
      c14n-20010315"/>
      <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-
        sha1"/>
      <Reference URI="#Msg">
         <Transforms>
            <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-
             20010315"/>
         </Transforms>
         <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
         <DigestValue>FAY3+4QEHHGMvr3pulYolUrj2AY=</DigestValue>
      </Reference>
   </SignedInfo>
   <SignatureValue>sRDa90AHWgApfw4U8tdzRzfIxEsmZ5oBy4RkXaNGslqiJ2QJ444LE8XsMQJO
37YtVn14zyRrEF6jTlySTG3VvGFj3fb8yYbRICs8Lcxok5hZNFEYXuuyS3NiCqj8IWiRAjTF+2BS
VYY4wZIaUoPGlgKfsxd06CRok/U/VZBjC1A=
</SignatureValue> <KeyInfo> <KeyValue xmlns="http://www.w3.org/2000/09/xmldsig#"> <RSAKeyValue> <Modulus>sxSAJ28BUYYB6RtxAF6pMi8CwADvK0oSdIulTtZVOKfl8VC/+ KpJDOWKPfEi2p4EG52YtMt4/+D2xMzPUYN+NiRo2Y0gJ5V95gIGDoWFyG83VnB dsidP7h+ItyPf6vCs1WREvjWE/cWWLuAId7Zd3hWjBRIh1/nO9+rq/Rp5+ds= </Modulus> <Exponent>AQAB</Exponent> </RSAKeyValue> </KeyValue> </KeyInfo>
</Signature>



In this application I create an XML document to envelope the body of the e-mail (packed into a CDATA element of an XML element) and it’s XML digital signature.


The Code


I will show key portions of the code for the various projects that can be found in the download.


KeyGenerator Application


I will use a Windows application for the KeyGenerator. It will save an RSA key in an XML file as described previously. Here’s the code that is being executed when the user clicks the button btnStart.



using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Security;
//See the System.Security inclusion. . . windows form code here . . . . .
private void btnStart_Click(object sender, System.EventArgs e)
{ string FileToSave=null; if (saveFileDialog.ShowDialog()==DialogResult.OK) { FileToSave=saveFileDialog.FileName; } //Create a RSA object System.Security.Cryptography.RSA csp= System.Security.Cryptography.RSA.Create(); System.IO.StreamWriter sw=new System.IO.StreamWriter(FileToSave); //Save its key to a file sw.Write(csp.ToXmlString(true)); sw.Close();
}


Signer Application


The next application, Signer, is targeted to manage all of the aspects related to the XML digital signature management. From this application I’ll use the previously generated XML key. Here I must, with this application, sign and verify the signature. The .NET SignedXml class in the System.Security.Cryptography.Xml namespace (remember that the System.Security assembly must be added to the references of the project) is the tool that will do all the work related to signing and verifying the signatures. The methods I created are the Sign() and Verify(). Let’s start with the Sign() method.



public string Sign(string WhatToSign, string XMLSavedKey)


To sign an XML element the Sign()method has seven steps:


1. Put the element into a System.Xml.XmlDocument:



System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(WhatToSign);//We are getting the XML to sign here


2. Put the key XML string into an object suitable to work with the .NET xmlSigner who manages the signing process, such as RSACryptoServiceProvider:



RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider();
//Let’s import the key
rsaCsp.FromXmlString(XMLSavedKey);


3. Create the xmlSigner object:



//We are instancing the SignedXml object using the document to be signed
System.Security.Cryptography.Xml.SignedXml xmlSigner = new
System.Security.Cryptography.Xml.SignedXml(doc.DocumentElement);


4. Establish exactly which is the node to be signed via the Reference object. Pay attention to the encoding here, UTF8 is enough for Spanish and English but this may not be good for you:



//We need to tell SignedXml the area we are exactly signing, I’ll use the
//Reference object for this
System.Security.Cryptography.Xml.Reference signref = new System.Security.Cryptography.Xml.Reference(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(WhatToSign)));
//Looking for the exact node
signref.Uri = String.Format("#{0}", "Msg");
xmlSigner.AddReference(signref);


5. Canonize (avoid XML inexactness in terms of cryptography) the text to be signed:



//It’s important add this transformation to "canonize" the XML
signref.AddTransform(new System.Security.Cryptography.Xml.XmlDsigC14NTransform());


6. Expose the public key (needed after to verify the signature) via the KeyInfo object:



//The KeyInfo object manages our RSA key information
System.Security.Cryptography.Xml.KeyInfo KI = new System.Security.Cryptography.Xml.KeyInfo();
KI.AddClause(new System.Security.Cryptography.Xml.RSAKeyValue(rsaCsp));
//exposing the public key in the Signature
xmlSigner.SigningKey = rsaCsp;
xmlSigner.KeyInfo = KI;


7. Compute the signature and properly join the text to be signed with the signature:



//let’s sign now!
xmlSigner.ComputeSignature();
System.Xml.XmlElement root = doc.CreateElement("SignedDoc");
root.AppendChild(doc.DocumentElement);
root.AppendChild(xmlSigner.GetXml());
return root.OuterXml;


To verify the signature the following must be done:


1. Load the signed text into an XMLDocument:



System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.PreserveWhitespace = true;
doc.LoadXml(WhatIsSigned);


2. Search for the node containing the signature and verify it:



System.Xml.XmlNodeList nodeList = doc.GetElementsByTagName("Signature", 
    System.Security.Cryptography.Xml.SignedXml.XmlDsigNamespaceUrl);  
//The Signature node
xmlSigner.LoadXml((System.Xml.XmlElement)nodeList0);
return xmlSigner.CheckSignature();


OutlookAddinAspToday Application


When an e-mail is sent through Outlook, it raises the event Application_ItemSend. To hook to this event, simply use an event assignment that is autogenerated through the Visual Studio Tools for Office – InternalStartup() method into the ThisApplication class:



private void InternalStartup()
{ //Added by Visual Studio Tools for Office this.Startup += new System.EventHandler(ThisApplication_Startup); this.Shutdown += new System.EventHandler(ThisApplication_Shutdown); //Added by Visual Studio Tools for Office this.ItemSend += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_ItemSendEventHandler (ThisApplication_ItemSend); this.NewMailEx += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_NewMailExEventHandler (ThisApplication_NewMailEx);
}


So when an e-mail is sent, the ThisApplication_ItemSend() function is executed automatically from within Outlook with the required parameters:



private void ThisApplication_ItemSend(object Item, ref bool Cancel)


This function works as follows:


1. Only react when the e-mail subject is ToM:



Outlook.MailItem m = (Outlook.MailItem)Item;
if (m.Subject "ToM")

Obtain the path of the key to be used for signing the e-mail message via the GetKeyPath() function (which uses a dialog to ask the user for the file with the key) and puts its contents into the XMLDocument:

doc.Load(GetKeyPath());

2. Structure the XML to carry the body of the e-mail and sign it:

SignedBody = sec.Sign(string.Concat("<Signed Id=", '"', "Msg", '"', 
  "><![CDATA[", body, "]]></Signed>"), doc.OuterXml);

3. Finally it verifies its own signature:

if (sec.Verify(SignedBody))
{
  m.Body = SignedBody;
  m.HTMLBody = SignedBody;
}
else
{
  LogError(SignedBody);
  m.Body = "This message isnt digitally signed";
}

The GetKeyPath() is the function that requests the user input and returns the path of the file:

private string GetKeyPath()
{
  OpenFileDialog dlg = new OpenFileDialog();
  dlg.Title = "Getting XML Key";
  dlg.Filter = "xml files (*.xml)|*.xml";
  dlg.AddExtension = true;
  //Show the dialog over the parent window: GetIWin32Window uses the 
  //FindWindow Win32 API function
  if (dlg.ShowDialog(WindowsManager.GetIWin32Window(""))  DialogResult.OK)
  {
    return dlg.FileName;
  }
  return null;
}


WordML Application


We need a way to generate a document to be sent to M. To do this I will open a database, retrieve some data from the Northwind to mimic some secret report, add some text to be read by James and then build the word document using XML. You can find a sample in the download as Dear James Test.xml and you can view it in Visual Studio to verify that the root node’s name is w:wordDocument and the child nodes are:


o:DocumentProperties


The general properties of the document (which are optional) can be seen in Figure 9.


  • w:fonts – The necessary fonts to be used

  • w:styles – The fonts and paragraph styles in the document

  • w:divs – Equivalent to HTML collection of div elements

  • w:shapeDefaults – Drawing defaults

  • w:docPr – Options of the document

  • w:body – The body of the document


  • Figure 9. The properties of the Word document.


Let’s talk a bit about the System.Xml.XmlTextWriter and the procedural way to write XML. The XmlTextWriter works, and works very well. The only bad thing is it can be the cause of some ugly code. Yes, it is a pretty clunky and hard to maintain implementation. It’s pointless showing you all of the approximately 400 lines of code responsible for opening element 1, opening element 2, opening element 3, adding attribute 1, adding attribute 2, closing element 3, closing element 2, closing element 1 and so on. You can, of course, refactor and polish the code and this will help. All the code is in the download and you can review it there. Here I’ll present the most significant parts:



using System;
using System.Xml;
using System.Xml.Xsl;
using System.Data.SqlClient;
namespace WordML
{ /// <summary> /// This class is intended to create an XML Word document via XML tools /// </summary> public class Builder { public Builder() {
}
public string CreateDoc()
{ #region File Paths string tmpDir=Environment.GetEnvironmentVariable("TEMP"); string fileName=string.Format("FromM_{0}{1}{2}{3}{4}", System.DateTime.Now.Month.ToString(), System.DateTime.Now.Day.ToString(), System.DateTime.Now.Year.ToString(), System.DateTime.Now.Minute.ToString(), System.DateTime.Now.Second.ToString()); string fullPath=string.Format(&quot;{0}{1}.xml&quot;,tmpDir,fileName); #endregion #region Declarations System.Xml.XmlTextWriter w; System.IO.FileStream oStream; #endregion oStream=new System.IO.FileStream(fullPath,System.IO.FileMode.Create); w=new System.Xml.XmlTextWriter(oStream,System.Text.Encoding.Default); w.Formatting=Formatting.Indented; w.Indentation = 3; // w.WriteWhitespace(Convert.ToString(Convert.ToChar(10))); w.WriteStartDocument(); // w.WriteProcessingInstruction(&quot;xml&quot;, &quot;version='1.0'&quot;); w.WriteProcessingInstruction(&quot;mso-application&quot;, &quot;progid='Word.Document'&quot;); w.WriteStartElement(&quot;w:wordDocument&quot;); #region Root attributes w.WriteAttributeString(&quot;xmlns&quot;, &quot;w&quot;, null, &quot;http://schemas.microsoft.com/office/word/2003/wordml&quot;); w.WriteAttributeString(&quot;xmlns&quot;, &quot;v&quot;, null, &quot;urn:schemas-microsoft- com:vml&quot;); w.WriteAttributeString(&quot;xmlns&quot;, &quot;w10&quot;, null, &quot;urn:schemas-microsoft- com:office:word&quot;); w.WriteAttributeString(&quot;xmlns&quot;, &quot;sl&quot;, null, &quot;http://schemas.microsoft.com/schemaLibrary/2003/core&quot;); w.WriteAttributeString(&quot;xmlns&quot;, &quot;aml&quot;, null, &quot;http://schemas.microsoft.com/aml/2001/core&quot;); w.WriteAttributeString(&quot;xmlns&quot;, &quot;wx&quot;, null, &quot;http://schemas.microsoft.com/office/word/2003/auxHint&quot;); w.WriteAttributeString(&quot;xmlns&quot;, &quot;o&quot;, null, &quot;urn:schemas-microsoft- com:office:office&quot;); w.WriteAttributeString(&quot;xmlns&quot;, &quot;dt&quot;, null, &quot;uuid:C2F41010-65B3-11d1-A29F- 00AA00C14882&quot;); w.WriteAttributeString(&quot;w&quot;, &quot;macrosPresent&quot;, null, &quot;no&quot;); w.WriteAttributeString(&quot;w&quot;, &quot;embeddedObjPresent&quot;, null, &quot;no&quot;); w.WriteAttributeString(&quot;w&quot;, &quot;ocxPresent&quot;, null, &quot;no&quot;); w.WriteAttributeString(&quot;xml&quot;, &quot;space&quot;, null, &quot;preserve&quot;); #endregion w.WriteStartElement(&quot;o:DocumentProperties&quot;); . . . <p></pre><!-- @END —>


Here I am writing the general properties of the document, like Title, Author, etc.:



<o:DocumentProperties>
  <o:Title>Dear James:</o:Title>
  <o:Author>Mauricio Grimberg</o:Author>
  <o:LastAuthor>Mauricio Grimberg</o:LastAuthor>
  <o:Revision>2</o:Revision>
  <o:TotalTime>0</o:TotalTime>
  <o:Created>2005-09-29T15:26:00Z</o:Created>
  <o:LastSaved>2005-09-29T15:26:00Z</o:LastSaved>
  <o:Company>Asp Today</o:Company>
</o:DocumentProperties>
. . . #region Font management
w.WriteStartElement("w:fonts");
w.WriteStartElement("w:defaultFonts");
w.WriteAttributeString("w", "ascii", null, "Times New Roman");
w.WriteAttributeString("w", "fareast", null, "Times New Roman");
w.WriteAttributeString("w", "h-ansi", null, "Times New Roman");
. . .


In the font management region I’m including the fonts and default fonts that the document needs:



<w:fonts>
  <w:defaultFonts w:ascii="Times New Roman" w:fareast="Times New Roman" 
    w:h-ansi="Times New Roman" w:cs="Times New Roman"/>
  <w:font w:name="Verdana">
    <w:panose-1 w:val="020B0604030504040204"/>
    <w:charset w:val="00"/>
    <w:family w:val="Swiss"/>
    <w:pitch w:val="variable"/>
    <w:sig w:usb-0="20000287" w:usb-1="00000000" w:usb-2="00000000" 
      w:usb-3="00000000" w:csb-0="0000019F" w:csb-1="00000000"/>
  </w:font>
</w:fonts>


I included certain XML nodes directly from files using the WriteRawFromFile() method as seen below:


  • Styles (w:styles element)

  • HTML DIV elements in the document (w:divs)

  • Default values for the shapes in the document (w: shapeDefaults)

  • Word specific document properties (w:docPr)


  • . . .
    #region Write raw
    WriteRawFromFile(w,Styles,false);
    WriteRawFromFile(w,Divs,false);
    WriteRawFromFile(w,shapeDefaults,false);
    WriteRawFromFile(w,docPr,true); #endregion
    . . .


For order and modularity, I created a class to write the body of the document – wordBody(). This class has the basic methods to write the metadata of the body, paragraphs and tables and you can see its interface in Figure 10.



Figure 10. Class view for the WordML project.


In the code below you can see I am invoking the Word body class.



body.WriteParagraph("I have a financial problem relative to your expenses in 
the matter of rescues of our mother country in individual and the world in
general and I wanted to ask you for aid in the inexorable reduction of costs
that is to happen.");


The getDataReader() method of the wordModel class is used here to get the data and to write each row while moving from record to record.



public void WriteTable()
{ wordModel data=new wordModel(); SqlDataReader rdr=data.getDataReader(); _w.WriteStartElement("w:tbl");//Table start WriteTableMetadata(); WriteTableHeader(); while (rdr.Read()) { WriteTableRow(rdr.GetString(0),string.Format("{0:C}",rdr.GetValue(1))); } _w.WriteEndElement();//w:tbl
}


The wordModel class provides the data, this class connect to the Northwind database on SQL Server and executes the aforesaid stored procedure to retrieve the report data.



using System;
using System.Data;
using System.Data.SqlClient;
namespace WordML
{ /// <summary> /// This class gets the DataReader from SQL Server using store procedures. /// </summary> public class wordModel { SqlConnection wrdSQLConn ; SqlCommand wrdCMD ; const string ConnString = "Data Source=(local); Initial Catalog=Northwind;Integrated Security=SSPI;"; public wordModel() { } public SqlConnection wrdConnection { get { if (wrdSQLConn ==null) { wrdSQLConn = new SqlConnection(); } if (wrdSQLConn.State!=ConnectionState.Open) { try { wrdSQLConn.ConnectionString= ConnString; wrdSQLConn.Open(); } catch (Exception ex) { //TODO manage your connection exceptions here } } return wrdSQLConn; } } internal SqlDataReader getDataReader() { wrdCMD=new SqlCommand(); wrdCMD.CommandType = CommandType.StoredProcedure; wrdCMD.CommandText = "ToWordAspTodayArticle"; wrdCMD.Connection = wrdConnection; return wrdCMD.ExecuteReader(); } }
}


The Outlook VBA application (Receiver)


Although this code runs in the Outlook receiver, the setup can be prepared to test it in a single machine in which the e-mail sender and the receiver coincides in the same application. Remember to change the e-mail addresses for you to send and receive.



Private Sub Application_NewMailEx(ByVal EntryIDCollection As String)
  Dim varEntryIDs
  Dim i As Integer
  Dim HowManyMails As Integer
  On Error GoTo StopAll
  varEntryIDs = Split(EntryIDCollection, ",")
  HowManyMails = UBound(varEntryIDs)
  If HowManyMails = 0 Then ‘Only 1 mail, there are not quotes, nothing split
    ProcessMail (EntryIDCollection) ‘Let’s do the work. See ProcessMail 
  Else
    For i = 0 To HowManyMails – 1
      ProcessMail (varEntryIDs(i))
    Next
  End If
  Exit Sub
  StopAll:
  Debug.Print Err.Description
 End Sub
Public Sub ProcessMail(ByVal EntryId As String) Dim objItem As MailItem Dim body As String Dim FileAttach As String Set objItem = Application.Session.GetItemFromID(EntryId) With objItem If InStr(.Subject, "Message from James") > -1 Then body = .HTMLBody Debug.Print "Message from James" Dim sec As Signer.Signer Dim vRet As Boolean Set sec = New Signer.Signer vRet = sec.verify(Trim(body)) If vRet Then ‘The signature is verified Dim wrd As WordML.Builder Set wrd = New WordML.Builder FileAttach = wrd.CreateDoc() ‘The builder has saved the XML Word Document in that path SendMailWithAttachment (FileAttach) Else Debug.Print CStr(vRet) & ": " & body End If End If End With
End Sub
Sub SendMailWithAttachment(ByVal FilePath As String) Dim m As MailItem Set m = Application.CreateItem(olMailItem) m.body = "This is the information for you requested" m.Subject = "ToJames" m.To = "mau@mug.org.ar" m.Attachments.Add (FilePath) m.Send
End Sub


Conclusion


I this article you saw the basics of how to create, use and verify a digital signature. I demonstrated how to create a Word document in XML and use Outlook to send it to a recipient encrypted. I also presented how to use Outlook 2003 as the client and server for sending and retrieving encrypted messages.


This article has used several different technologies in order to build the sample application. I used SQL Server to store the message content, Outlook as the transport for the e-mail, a Windows application to generate the keys and .NET as the glue to put it all together. Be sure to review the Related Links in order to get more detail on the technologies used in this article.

Founders at Work

Commenting is closed for this article.