Per vedere come usare le classi Cryptography.XML per firmare files XML, procediamo a firmare l'elemento Pagamento con una chiave privata RSA. Si suppone che questo file contenga informazioni importanti che non vogliamo rendere leggibili in plain text (testo semplice).

Per prima cosa carichiamo l'elemento Pagamento dal file XML interessato. Come tutti sappiamo .NET mette a disposizione strumenti potenti per l'elaborazione dei files XML, questi sono inclusi nello spazio di nomi (namespace) System.XML.

Iniziamo con il codice

String appPath = Application.StartupPath;
XmlDocument xmlDoc = 
new XmlDocument();
xmlDoc.Load(appPath + @"\Ordine.XML");
XmlNodeList paymentElems = xmlDoc.SelectNodes("Ordine/Pagamento"));

Supponendo che la nodelist sia composta da un solo elemento, creiamo un l'oggetto signedXml che andrà a contenere le informazioni sul pagamento grazie ad un data object.

SignedXml signedXml = new SignedXml();
System.Security.Cryptography.Xml.DataObject paymentInfo =
   
new System.Security.Cryptography.Xml.DataObject();
paymentInfo.Data = paymentElems;
paymentInfo.Id = "OrdinePagamento";
signedXml.AddObject(paymentInfo);

A questo punto, aggiungiamo un elemento di Reference al data object interessato.

Reference reference = new Reference();
reference.Uri = "#OrdinePagamento";
signedXml.AddReference(reference);

E per terminare, aggiungiamo la chiave generata all'oggetto signedXml e creiamo la firma.

RSA rsaKey = RSA.Create();
signedXml.SigningKey = rsaKey;
KeyInfo keyInfo = 
new KeyInfo();
keyInfo.AddClause(
new RSAKeyValue(rsaKey));
signedXml.KeyInfo = keyInfo;
signedXml.ComputeSignature();

A questo punto, se vogliamo prendere l XML da signedXML riceveremo qualcosa di molto simile a quello che si vede nel codice seguente

<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="#OrdinePagamento">
         <DigestMethod 
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
         <DigestValue>
DoC7GhTuQk8H...</DigestValue>
      <
/Reference>
   <
/SignedInfo>
   <SignatureValue>
lzFitF4ebq0h...</SignatureValue>
   <KeyInfo>
      <KeyValue 
xmlns="http://www.w3.org/2000/09/xmldsig#">
         <RSAKeyValue>
            <Modulus>
sDmqsYcveGWG...</Modulus>
            <Exponent>
AQAB</Exponent>
         <
/RSAKeyValue>
      <
/KeyValue>
   <
/KeyInfo>
   <
Object Id="OrdinePagamento">
      <Pagamento 
Method="Credit" Type="HighInterest" xmlns="">
         <Number>
7890123456789012</Number>
         <ExpirationDate>
12/12/2003</ExpirationDate>
      <
/Pagamento>
   <
/Object>
<
/Signature>


Adesso dobbiamo inserire l'elemento Signature nel documento originale, possiamo fare in questo modo

xmlDoc.DocumentElement.InsertAfter(xmlDoc.ImportNode(signedXml.GetXml(), true),
    xmlDoc.DocumentElement.FirstChild);

Come potete notare, abbiamo bisogno d'importare completamente l'elemento signedXml visto la sua assenza totale nel file originale da cui siamo partiti.  Ricordiamoci d'inserirlo dopo l'elemento root del primo elemento figlio!

A lavoro quasi terminato, se volessimo verificare la firma.. potremmo usare.

XmlDocument signedDoc = new XmlDocument();
signedDoc.LoadXml(xmlDoc.OuterXml);
SignedXml sigs = 
new SignedXml(signedDoc);
XmlNodeList sigElems = signedDoc.GetElementsByTagName("Signature");
sigs.LoadXml((XmlElement)sigElems[0]);
MessageBox.Show(sigs.CheckSignature().ToString());

Se tutto è stato eseguito correttamente, dovremmo ricevere un "True". Ma nel caso che si voglia generare due tipologie di documento. Uno con i dati e uno con la firma cosa dovremmo fare? La risposta si può trovare in questa parte di codice che mostro di seguito.

SignedXml signedXml = new SignedXml();
Reference reference = 
new Reference();
reference.Uri = @"file://" + Application.StartupPath +
@"\Order.XML";
signedXml.AddReference(reference);
RSA rsaKey = RSA.Create();
signedXml.SigningKey = rsaKey;
KeyInfo keyInfo = 
new KeyInfo();
keyInfo.AddClause(
new RSAKeyValue(rsaKey));
signedXml.KeyInfo = keyInfo;
signedXml.ComputeSignature();