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