Mentre .NET supporta pienamente classi per le specifiche
XML in fatto di firme, per la Codifica non esiste nessuna classe specifica..
nemmeno una.
Attenzione, questo
non significa che operazioni di codifica risultino impossibili.. anzi.
Ricordiamoci delle classi di Cryptography viste nei precedenti
post.
Continuando a prendere come esempio il file xml (Sec22 e Sec23)
andiamo a vedere come possiamo trattare questo nodo al fine di codificarlo.
Dando per scontato la totale assenza di una chiave, la prima cosa che dobbiamo
fare è quella di andarla a creare. Per fare questo avremmo bisogno di creare una
chiave simmetrica, codificarla e rendere il risultato codificato in
Base64. Via al codice.
1 Rijndael rKey = new RijndaelManaged();
2 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
3 MemoryStream encryptedData = new MemoryStream();
4
5 int start = 0;
6 do
7 {
8 byte[] keyMaterial = new byte[16];
9 Array.Copy(rKey.Key, start, keyMaterial, 0, 16);
10 byte[] encryptedSessionKey = rsa.Encrypt(keyMaterial, false);
11 encryptedData.Write(encryptedSessionKey, 0,
12 (int)encryptedSessionKey.Length);
13 start += 16;
14 } while(start < rKey.Key.Length);
15 encryptedData.Position = 0;
16 String rToBase64 = Convert.ToBase64String(encryptedData.GetBuffer(),
17 0, (int)encryptedData.Length);
Una volta che abbiamo la chiave di sessione criptata, la creazione del giusto
XmlElement inizia ad essere la parte a cui dobbiamo prestare maggiore
attenzione. Ricordiamoci che dobbiamo generare il giusto Element al momento
giusto.. in questo modo potremmo creare gli elementi di codifica appropriati.
Vediamolo meglio.
1 XmlDocument keyExchDoc = new XmlDocument();
2 XmlElement encryptedKey = keyExchDoc.CreateElement("EncryptedKey");
3 keyExchDoc.AppendChild(encryptedKey);
4 XmlAttribute carriedKeyName = keyExchDoc.CreateAttribute("CarriedKeyName");
5 carriedKeyName.Value = "Ale's Session Key";
6 encryptedKey.Attributes.Append(carriedKeyName);
7
8 XmlElement encryptionMethod = keyExchDoc.CreateElement("EncryptionMethod");
9 encryptedKey.AppendChild(encryptionMethod);
10 XmlAttribute encryptionAlgorithm = keyExchDoc.CreateAttribute("Algorithm");
11 encryptionAlgorithm.Value = "http://www.w3.org/2001/04/xmlenc#rsa-1_5";
12 encryptionMethod.Attributes.Append(encryptionAlgorithm);
13
14 XmlElement keyInfo = keyExchDoc.CreateElement("ds", "KeyInfo",
15 "http://www.w3.org/2000/09/xmldsig#");
16 encryptedKey.AppendChild(keyInfo);
17
18 XmlElement keyName = keyExchDoc.CreateElement("ds", "KeyName", null);
19 keyName.InnerText = "Ale's Private Key";
20 keyInfo.AppendChild(keyName);
21
22 XmlElement cipherData = keyExchDoc.CreateElement("CipherData");
23 encryptedKey.AppendChild(cipherData);
24
25 XmlElement cipherValue = keyExchDoc.CreateElement("CipherValue");
26 cipherValue.InnerText = rToBase64;
27 cipherData.AppendChild(cipherValue);
28
A questo punto, chiamare OuterXml sul campo keyExchDoc
produce come output il seguente documento.
<EncryptedKey CarriedKeyName="Ale's Session Key">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<KeyName>Ale's Private Key</KeyName>
</ds:KeyInfo>
<CipherData>
<CipherValue>CQu3/R138mrMDuLuY74C1....</CipherValue>
</CipherData>
</EncryptedKey>
Mettiamo il caso che Alessio abbia bisogno di decodificare
il tutto con la sua chiave privata di nome "Ale's Private Key". Bene, ora
immaginiamo che Alessio ha ricevuto questo documento ed ha correttamente
trasformato e decodificato il il testo contenuto dei CipherValue .
A questo punto, è possibile, inviare l'ordine di Alessio con l'elemento
Pagamento correttamente codificato utilizzando questo codice.
String appPath = Application.StartupPath;
XmlDocument paymentDoc = new XmlDocument();
paymentDoc.Load(appPath + @"\Ordine.XML");
XmlElement paymentElem =
(XmlElement)paymentDoc.SelectSingleNode("Ordine/Pagamento");
byte[] paymentXmlInfo = Encoding.Unicode.GetBytes(paymentElem.OuterXml);
MemoryStream ms = new MemoryStream();
CryptoStream csBase64 = new CryptoStream(ms,
new ToBase64Transform(),
CryptoStreamMode.Write);
CryptoStream csRijndael = new CryptoStream(csBase64,
rKey.CreateEncryptor(),
CryptoStreamMode.Write);
csRijndael.Write(paymentXmlInfo, 0,
(int)paymentXmlInfo.Length);
csRijndael.FlushFinalBlock();
String base64enc = Encoding.ASCII.GetString(ms.GetBuffer(),
0, (int)ms.Length);
A questo punto, abbiamo le informazioni di pagamento codificare. Abbiamo ora
bisogno di creare l'elemento EncryptedData e aggiungere l'informazione sulla
chiave insieme al risultato del nostro lavoro.
XmlElement encryptedData = paymentDoc.CreateElement("EncryptedData");
XmlAttribute encryptedType = paymentDoc.CreateAttribute("Type");
encryptedType.Value = "http://www.w3.org/2001/04/xmlenc#Element";
encryptedData.Attributes.Append(encryptedType);
XmlElement keyInfo = paymentDoc.CreateElement("ds", "KeyInfo",
"http://www.w3.org/2000/09/xmldsig#");
encryptedData.AppendChild(keyInfo);
XmlElement keyName = paymentDoc.CreateElement("ds", "KeyName", null);
keyName.InnerText = "Ale's Session Key";
keyInfo.AppendChild(keyName);
XmlElement cipherData = paymentDoc.CreateElement("CipherData");
encryptedData.AppendChild(cipherData);
XmlElement cipherValue = paymentDoc.CreateElement("CipherValue");
cipherValue.InnerText = base64enc; cipherData.AppendChild(cipherValue);
XmlElement orderElem =
(XmlElement)paymentDoc.SelectSingleNode("Ordine");
orderElem.ReplaceChild(encryptedData, paymentElem);
Adesso non resta che sovrascrivere il valore di Pagamento del file originale
con quello risultate dalle nostre operazioni di codifica. Questo ci porta ad
avere come risultato il seguente documento XML.
<Ordine>
<Items>
<Item ID="123456789">
<Description>Il mio ordine</Description>
<Price>0.99</Price>
</Item>
</Items>
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<KeyName>Ale's Session Key</KeyName>
</ds:KeyInfo>
<CipherData>
<CipherValue>lupcw1DYZ9k0Tr1rX2TN...</CipherValue>
</CipherData>
</EncryptedData>
</Ordine>
Fatto