Laden...

XML Crypt

Letzter Beitrag vor 13 Jahren 15 Posts 17.153 Views
Hinweis von herbivore vor 13 Jahren

Der folgende Code ist nahezu 1:1 ein Beispiel aus der MSDN (siehe Gewusst wie: Verschlüsseln von XML-Elementen mit symmetrischen Schlüsseln, Dank an tom-essen für den Hinweis). Es ist natürlich nicht der Sinn des Bereichs ".NET-Komponenten und C#-Snippets" die MSDN "vorzulesen". Wenn der Thread nicht schon von mehreren Stellen verlinkt wäre, wäre er entfernt worden.

XML Crypt

Beschreibung: Eine kleine Helper Klasse zum verschlüsseln von XML Daten

Diese Klasse wird von mir hauptsächlich zum abspeichern von Passwörtern in XML Dateien verwendet.


using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;

namespace Thunderbird.XmlCrypted
{
   
    public class CryptXmlNode
    {
        /// <summary>
        /// Encrypt a specifik XML node. If you select the root node the whole XML document is crypted. 
        /// </summary>
        /// <param name="Doc">The XML document which contains the node to be crypted.</param>
        /// <param name="ElementName">The name of the XML node</param>
        /// <param name="Key">The secret crypto key.</param>
        public void Encrypt(XmlDocument Doc, string ElementName, SymmetricAlgorithm Key)
        {
            // Check the arguments.  
            if (Doc == null)
                throw new ArgumentNullException("Doc");
            if (ElementName == null)
                throw new ArgumentNullException("ElementToEncrypt");
            if (Key == null)
                throw new ArgumentNullException("Alg");

           
            // Find the specified element in the XmlDocument
            // object and create a new XmlElemnt object.
           
            XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementName)[0] as XmlElement;
            // Throw an XmlException if the element was not found.
            if (elementToEncrypt == null)
            {
                throw new XmlException("The specified element was not found");

            }

            // Create a new instance of the EncryptedXml class 
            // and use it to encrypt the XmlElement with the 
            // symmetric key.

            EncryptedXml eXml = new EncryptedXml();

            byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, Key, false);

            // Construct an EncryptedData object and populate
            // it with the desired encryption information.

            EncryptedData edElement = new EncryptedData();
            edElement.Type = EncryptedXml.XmlEncElementUrl;

            // Create an EncryptionMethod element so that the 
            // receiver knows which algorithm to use for decryption.
            // Determine what kind of algorithm is being used and
            // supply the appropriate URL to the EncryptionMethod element.

            string encryptionMethod = null;

            if (Key is TripleDES)
            {
                encryptionMethod = EncryptedXml.XmlEncTripleDESUrl;
            }
            else if (Key is DES)
            {
                encryptionMethod = EncryptedXml.XmlEncDESUrl;
            }
            else if (Key is Rijndael)
            {
                switch (Key.KeySize)
                {
                    case 128:
                        encryptionMethod = EncryptedXml.XmlEncAES128Url;
                        break;
                    case 192:
                        encryptionMethod = EncryptedXml.XmlEncAES192Url;
                        break;
                    case 256:
                        encryptionMethod = EncryptedXml.XmlEncAES256Url;
                        break;
                }
            }
            else
            {
                // Throw an exception if the transform is not in the previous categories
                throw new CryptographicException("The specified algorithm is not supported for XML Encryption.");
            }

            edElement.EncryptionMethod = new EncryptionMethod(encryptionMethod);

            // 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);
        }

        /// <summary>
        /// Decrypt a XML Document.
        /// </summary>
        /// <param name="Doc">The crypted XML Document.</param>
        /// <param name="Key">The secret key.</param>
        public void Decrypt(XmlDocument Doc, SymmetricAlgorithm Key)
        {
            // Check the arguments.  
            if (Doc == null)
                throw new ArgumentNullException("Doc");
            if (Key == null)
                throw new ArgumentNullException("Key");

            // Find the EncryptedData element in the XmlDocument.
            XmlElement encryptedElement = Doc.GetElementsByTagName("EncryptedData")[0] as XmlElement;

            // If the EncryptedData element was not found, throw an exception.
            if (encryptedElement == null)
            {
                throw new XmlException("The EncryptedData element was not found.");
            }


            // Create an EncryptedData object and populate it.
            EncryptedData edElement = new EncryptedData();
            edElement.LoadXml(encryptedElement);

            // Create a new EncryptedXml object.
            EncryptedXml exml = new EncryptedXml();


            // Decrypt the element using the symmetric key.
            byte[] rgbOutput = exml.DecryptData(edElement, Key);

            // Replace the encryptedData element with the plaintext XML element.
            exml.ReplaceData(encryptedElement, rgbOutput);

        }
    }

}


Schlagwörter: xml, crypt, verschlüsseln

Hi,

rein vom überfliegen des codes fällt mir auf, dass wenn der Key nicht 'Rijndael' ist, immer eine Exception geschmissen wird.
Statt:


if (Key is Rijndael)

müsste da wohl


else if (Key is Rijndael)

stehen.

Hallo!

Für die korrekte Verwendung von ArgumentNullException sollte auch der tatsächliche Name des Parameters verwendet werden.

Ansonsten ein bestimmt hilfreiches Snippet.

Nobody is perfect. I'm sad, i'm not nobody 🙁

Ja stimmt das sollte else if heisen. Danke.

Ah kann ich sehr gut gebrauchen, brauch ich die Daten nicht mehr ganz im Klartext speichern und kann eine gewisse Sicherheit bieten!

Sauber!

hallo,

ich habe den code kopiert und beim endschlüssel erhalte ich bei zeile:

byte[] rgbOutput = exml.DecryptData(edElement, Key);

eine exception: cryptographicexception (Zeichenabstände sind ungültig und können nicht entfernt werden.)

ich weiß absolut nicht wo der fehler ist.

kann mir villeicht sagen was der fehler ist.

eingebunden habe ich es so:

SymmetricAlgorithm symmetricAlgorithm = SymmetricAlgorithm.Create("Rijndael");
                symmetricAlgorithm.KeySize = 256;
CryptXmlNode c = new CryptXmlNode();

                c.Decrypt(XMLDocument, symmetricAlgorithm);
SymmetricAlgorithm symmetricAlgorithm = SymmetricAlgorithm.Create("Rijndael");
                symmetricAlgorithm.KeySize = 256;

                CryptXmlNode c = new CryptXmlNode();
                c.Encrypt(XMLDocument, "root", symmetricAlgorithm);

vielen dank und grüße

Hallo,

Habe schonmal eine ähnliche Routine geschriben, mit sporadisch auftretenden Exceptions.

Das Problem ist meines Erachtens, das durch die verschlüsselten Nodes unter Umständen ungültige Unicode Zeichen entstehen, die den Parser durcheinander bringen

Auch wenn der Thread schon etwas älter ist: Eine Lösung für das oben genannte Problem wurde noch nicht gepostet. Da ich mich derzeit auch daran versuche, Codes mit C# zu verschlüsseln, war ich auf der Suche nach Diensten, die dies erledigen. Leider bekomme ich dann auch die Meldung:

"Zeichenabstände sind ungültig und können nicht entfernt werden."

Die Ursache dafür liegt, so wie ich das verstanden habe, darin, dass ungültige Unicode-Zeichen entstehen und diese dann nicht decryptet werden können. Bedeutet das, dass es keinerlei Möglichkeit gibt, mithilfe der oben geposteten Dienste einzelne Nodes zu verschlüsseln oder gibt es dafür eine Lösung, die mir bisher noch verborgen blieb?

Danke im Vorraus für eine Antwort.

MfG Patros46

Kleiner Nachtrag:

Der Aufruf sieht bei mir folgendermaßen aus:

Encrypt:

 SymmetricAlgorithm symmetricAlgorithm = SymmetricAlgorithm.Create("Rijndael";);
symmetricAlgorithm.KeySize = 256;
Encrypt(doc, "Serial", symmetricAlgorithm);

Decrypt:

 SymmetricAlgorithm symmetricAlgorithm = SymmetricAlgorithm.Create("Rijndael";);
symmetricAlgorithm.KeySize = 256;
Decrypt(doc, symmetricAlgorithm);

Die Ursache dafür liegt, so wie ich das verstanden habe, darin, dass ungültige Unicode-Zeichen entstehen und diese dann nicht decryptet werden können.

Ich kenne mich nich so mit den einzelnen Algorithmen aus und weiß nich in welches Fall diese ungültigen Zeichen entstehen, aber man könnte mal versuchen den Plaintext (also noch vor der Verschlüsselung) mit Base64 zu kodieren. Das gäbe zwar etwas Overhead, aber es könnte funktionieren.

Erstmal danke für den Tipp, allerdings bleibt die Fehlermeldung. Hat jemand noch eine andere Idee?

Hallo,

Ich habe mir so geholfen, dass ich die ganze XML datei verschlüssele, also mir der Reihenfolge beim Speichern:

XML dokument -> Verschlüsselung -> Datei

Wichtig ist dabei dass nach der Verschlüsselung KEIN string objekt mehr vorliegt sondern ein Byte[] array.

Das lies sich von der Implementierung her ganz gut mit filestreams machen.

Um nur einzelnde Nodes zu verschlüsseln müsste man folgendermassen vorgehen:

string text der node -> verschlüsselung zu Byte[] !! -> konvertierung in gültigen string über base64 / mime encoding o. ä.

Man muss halt höllisch aufpassen, dass man keine "zufälligen" Binärdaten in strings ablegt, und genau so etwas passiert nun mal bei einem guten Verschlüsselungsalgorithmus.

@rastalt: klingt ja ganz gut deine Idee, aber die Konvertierung in base64 o. ä. muss NACH der Verschlüsselung erfolgen, sonst kommen wieder binärdaten heraus

Man kann das verschlüsselte Zeugl auch einfach in einen CDATA-Block packen.

Hmm ich glaube, dass das mit der CDATA Sektion auch keine gute Idee ist.
steht in den Binärdaten z.B. irgendwo "]]>" (der Terminator für die CDATA section)
ist das XML Dokument schon mal invalide.

Ausserdem ist das mit der CDATA Section schon irgendwie merkwürdig und lässt sich eigentlich auch nur mit einer validen DTD vernünftig von XML Parsern verarbeiten.

Hallo!

Zusätzliche Informationen dazu finden sich im Artikel Gewusst wie: Verschlüsseln von XML-Elementen mit symmetrischen Schlüsseln, aus dem auch exakt das Beispiel (inkl. if else-Fehler) übernommen wurde 😄.

Hinweis von herbivore vor 13 Jahren

Danke für den Hinweis. Daraufhin habe ich einen Moderationshinweis in XML Crypt geschrieben.

Nobody is perfect. I'm sad, i'm not nobody 🙁

Schon krass was für einen sowohl semantisch als auch logisch fehlerhaften Schrott man manchmal in der MSDN findet..