Szyfrowanie pliku XML

0

Cześć,

piszę sobie program, który ma m.im. zapisywać dane do pliku XML i chciałbym zaszyfrować niektóre klucze w tym pliku. W tym celu użyłem klasy w System.Security.Cryptography.Xml, a konkretnie przykładu z tej strony:https://msdn.microsoft.com/pl-pl/library/ms229746(v=vs.110).aspx
Zmodyfikowałem funkcję Encrypt, tak by jako drugi argument przyjmowała zamiast nazwy klucza gotowy XmlElement:

public void Encrypt(XmlDocument Doc, XmlElement ElementToEncrypt, string EncryptionElementID, RSA Alg, string KeyName)
        {
            // Check the arguments.
            if (Doc == null)
                throw new ArgumentNullException("Doc");
            if (ElementToEncrypt == null)
                throw new ArgumentNullException("ElementToEncrypt");
            if (EncryptionElementID == null)
                throw new ArgumentNullException("EncryptionElementID");
            if (Alg == null)
                throw new ArgumentNullException("Alg");
            if (KeyName == null)
                throw new ArgumentNullException("KeyName");
 
            ////////////////////////////////////////////////
            // Find the specified element in the XmlDocument
            // object and create a new XmlElemnt object.
            ////////////////////////////////////////////////
           // XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
            XmlElement elementToEncrypt = ElementToEncrypt;
 
            // Throw an XmlException if the element was not found.
            if (elementToEncrypt == null)
            {
                throw new XmlException("The specified element was not found");
 
            }
            RijndaelManaged sessionKey = null;
            
           // MessageBox.Show(Doc.GetElementsByTagName(ElementToEncrypt).Count.ToString());
            
                try
                {
 
                    
                    //////////////////////////////////////////////////
                    // Create a new instance of the EncryptedXml class
                    // and use it to encrypt the XmlElement with the
                    // a new random symmetric key.
                    //////////////////////////////////////////////////
 
                    // Create a 256 bit Rijndael key.
                    sessionKey = new RijndaelManaged();
                    sessionKey.KeySize = 256;
 
                    EncryptedXml eXml = new EncryptedXml();
 
                    byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
                    ////////////////////////////////////////////////
                    // Construct an EncryptedData object and populate
                    // it with the desired encryption information.
                    ////////////////////////////////////////////////
 
                    EncryptedData edElement = new EncryptedData();
                    edElement.Type = EncryptedXml.XmlEncElementUrl;
                    edElement.Id = EncryptionElementID;
                    // Create an EncryptionMethod element so that the
                    // receiver knows which algorithm to use for decryption.
 
                    edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
                    // Encrypt the session key and add it to an EncryptedKey element.
                    EncryptedKey ek = new EncryptedKey();
 
                    byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false);
 
                    ek.CipherData = new CipherData(encryptedKey);
 
                    ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
 
                    // Create a new DataReference element
                    // for the KeyInfo element.  This optional
                    // element specifies which EncryptedData
                    // uses this key.  An XML document can have
                    // multiple EncryptedData elements that use
                    // different keys.
                    DataReference dRef = new DataReference();
 
                    // Specify the EncryptedData URI.
                    dRef.Uri = "#" + EncryptionElementID;
 
                    // Add the DataReference to the EncryptedKey.
                    ek.AddReference(dRef);
                    // Add the encrypted key to the
                    // EncryptedData object.
 
                    edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
                    // Set the KeyInfo element to specify the
                    // name of the RSA key.
 
 
                    // Create a new KeyInfoName element.
                    KeyInfoName kin = new KeyInfoName();
 
                    // Specify a name for the key.
                    kin.Value = KeyName;
 
                    // Add the KeyInfoName element to the
                    // EncryptedKey object.
                    ek.KeyInfo.AddClause(kin);
                    // Add the encrypted element data to the
                    // EncryptedData object.
                    edElement.CipherData.CipherValue = encryptedElement;
                    ////////////////////////////////////////////////////
                    // Replace the element from the original XmlDocument
                    // object with the EncryptedData element.
                    ////////////////////////////////////////////////////
                    EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);  
 
                }
                catch (Exception e)
                {
                    // re-throw the exception.
                    throw e;
                }
                finally
                {
                    if (sessionKey != null)
                    {
                        sessionKey.Clear();
                    }
 
                }
        }


i dalej mam pętlę foreach

XmlNodeList pass = XmlDoc.GetElementsByTagName("pass");
 
            foreach (XmlNode node in pass)
            {
                
                XmlElement elementToEncrypt = node as XmlElement;
                try
                {
                    // XmlElement pass = XmlDoc.GetElementsByTagName("pas")[listBox1.SelectedIndex] as XmlElement;
 
                    Encrypt(XmlDoc, elementToEncrypt, "EncryptedElement2", rsaKey, "rsaKey");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                finally
                {
                    // Clear the RSA key.
                    rsaKey.Clear();
                }
            }
            XmlDoc.Save("hosts.xml");


po uruchomieniu kodu pojawia się błąd: "Lista elementów zmieniła się. Nie można kontynuować operacji wyliczenia." Próbowałem to zrobić na pętli for i while, ale też nie działa, np:

 while(XmlDoc.GetElementsByTagName("pass").Count>0)
            {
               
                XmlElement elementToEncrypt = XmlDoc.GetElementsByTagName("pass")[0] as XmlElement;

                    Encrypt(XmlDoc, elementToEncrypt, "EncryptedElement2", rsaKey, "rsaKey");
                } 
1

Nie czytałem całego kodu, więc to taki strzał. Taki komunikat w przypadku pętli for lub foreach mówi, że zmieniła się ilość elementów w iterowanej liście. Oznacza to tyle. że ani for, ani foreach sobie z tym nie poradzą. For i foreach mają takie wymagania (chyba w każdym języku), że muszą mieć stałą ilość elementów w iterowanej liście. Ta ilość nie może się zmienić w trakcie działania pętli. Tutaj najwyraźniej się zmienia. Więc użyj while zamiast for, czy foreach. Tylko w sposób dynamiczny, tzn. nie sprawdzaj warunku przed wejściem do while, tylko przy każdej iteracji.

0

Ja bym stworzył nowe pole, np:

 //Tutaj to co masz, ignorowane dla serializatora
[XmlIgnore]
public string Key { get;set; }

//nowe, zwraca zaszyfrowany string, tytlko to zostanie dodane do xml
public string KeySecure { get { return this.Encrypt(this.Key); } }
//Encrypt to Twoja funkcja szyfrujaca

Coś mi nie działają przyciski na forum, jaki tag dodać, żeby było w 'code' ? :D

0

po uruchomieniu kodu pojawia się błąd: "Lista elementów zmieniła się. Nie można kontynuować operacji wyliczenia." Próbowałem to zrobić na pętli for i while, ale też nie działa, np:

Pętla foreach to tak naprawdę ładnie wyglądający while. Rozwiązanie jest proste - zrób sobie kopię XML i szyfruj elementy na kopii.

0

Usunąłem blok try-catch z pętli i szyfruje

 XmlNodeList pass = XmlDoc.GetElementsByTagName("pass");
            int count = XmlDoc.GetElementsByTagName("pass").Count;
           
           // foreach (XmlNode node in pass)
           for(int i=0; i<count;i++)
            {
               
                XmlElement elementToEncrypt = pass[0] as XmlElement;
                Encrypt(XmlDoc, elementToEncrypt, "EncryptedElement2", rsaKey, "rsaKey");
        
            }

1 użytkowników online, w tym zalogowanych: 0, gości: 1