© Martin Korneffel, Stuttgart 2006 +++ email: Martin.Korneffel@t-online.de +++ web: www.s-line.de/homepages/trac

Kryptografie

Inhalt

  1. Ziele beim Einsatz kryptographischer Verfahren

  2. Symetrische Verschlüsselung

    1. Vorteile

    2. Nachteile

    3. .NET Klassen für symetrische Kryptografie

    4. Beispiel

  3. Asymetrische Verschlüsselung

    1. Vorteile

    2. Nachteile

    3. Beispiel

  4. Hash- Codes

  5. Digitale Signatur

  6. X 509 Zertifikate

    1. Inhalt eines Zertifikates

  7. Schlüsseltausch

Ziele beim Einsatz kryptographischer Verfahren

  1. Vertraulichkeit: Beschränken des Zugriffs auf Informationen auf einen definierten Benutzerkreis

  2. Sicherstellen der Datenintegrität: Schützen von sensitiven Daten vor unberechtigten Änderungen

  3. Authentizität: Nachweise über den Verfasser von Informationen.

Symetrische Verschlüsselung


Vorteile

Nachteile

.NET Klassen für symetrische Kryptografie




RijndaelManaged ist die einzige Klasse der sym. Verschlüsselungsverfahren, die vollständig in Managed Code implementiert ist. Ihre Verwendung wird empfohlen.

Die Basisklasse aller symetrischen Kryptografieverfahren ist SysmetricAlgorithm


Die Ver- und Entschlüsselung erfolgt durch Objekte, deren Klasse die Schnittstelle ICryptoTransform implementieren.


Beispiel

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

namespace u2_SymetricAlgorithm
{
    class Program
    {
        const string password = "wa17er";
        const string txtSalt = "Das Salz in der Suppe";       

        // Aus einem Passwort wird ein Schlüssel generiert
        static byte[] MakeKey(string password, int KeySizeInBits)
        {
            // Einen Schlüssel aus einem Passwort generieren
            byte[] salt = Encoding.ASCII.GetBytes(txtSalt);
            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt);

            // Schlüssel und initialisierungsvektor aus dem Passwort generieren
            // Die Schlüsselgrößen werden in Bit angegeben, weshalb durch 8
            // geteilt werden muß
            return key.GetBytes(KeySizeInBits / 8);

        }

        // Datei "inputPath" wird mit einem aus "password" generierten Schlüssel
        // verschlüsselt. Verschlüsselte Daten werden in "outputPath" geschrieben
        static void encrypt(string inputPath, string password, string outputPath)
        {   
            // Ein Objekt einer Klasse für die sym. Verschlüsselung erstellen
            RijndaelManaged symAlgo = new RijndaelManaged();
            

            // Schlüssel aus Passwort generieren
            symAlgo.Key = MakeKey(password, symAlgo.KeySize);

            // Initialisierungsvektor aus Passwort bilden
            symAlgo.IV = MakeKey(password, symAlgo.BlockSize);

            // Datei mit Geheimtext einlesen in Bytearray
            FileStream infstream = new FileStream(inputPath, FileMode.Open);
            byte[] txt = new byte[infstream.Length];
            infstream.Read(txt, 0, (int)infstream.Length);

            infstream.Close();

            // Ausgabedatei für verschlüsselten Text öffnen
            FileStream outfstream = new FileStream(outputPath, FileMode.OpenOrCreate);

            ICryptoTransform trafo = symAlgo.CreateEncryptor();

            CryptoStream encryptStream = new CryptoStream(outfstream, trafo, CryptoStreamMode.Write);

            // In verschlüsselte Datei Schreiben
            encryptStream.Write(txt, 0, txt.Length);

            // Datenströme schliessen
            encryptStream.Close();
            outfstream.Close();
            
        }

        // Verschlüsselte Daten aus der Datei "pathEncrypted" wird mit aus "password"
        // generierten Schlüssel entschlüsselt
        static string decrypt(string pathEncrypted, string password)
        {
            // Ein Objekt einer Klasse für die sym. Verschlüsselung erstellen
            RijndaelManaged symAlgo = new RijndaelManaged();

            // Schlüssel aus Passwort generieren
            symAlgo.Key = MakeKey(password, symAlgo.KeySize);

            // Initialisierungsvektor aus Passwort bilden
            symAlgo.IV = MakeKey(password, symAlgo.BlockSize);

            FileStream infstream = new FileStream(pathEncrypted, FileMode.Open);

            ICryptoTransform trafo = symAlgo.CreateDecryptor();

            // Entschlüsseln mittels CryptoStream
            CryptoStream decryptStream = new CryptoStream(infstream, trafo, CryptoStreamMode.Read);
            
            StreamReader reader = new StreamReader(decryptStream);
            string txt = reader.ReadToEnd();

            reader.Close();

            return txt;
            
        }


        const string pathGeheimtext = @"..\..\text.txt";
        const string pathVerschluesselterText = @"..\..\text.enc";

        static void Main(string[] args)
        {
            // Ausgabe des zu verschlüsselnden Textes

            StreamReader reader = new StreamReader(pathGeheimtext);
            string txt = reader.ReadToEnd();
            reader.Close();
            Console.WriteLine("Inhalt des Geheimtextes: ");
            Console.WriteLine(txt);
                        
            encrypt(pathGeheimtext, password, pathVerschluesselterText);
            reader = new StreamReader(pathVerschluesselterText);
            txt = reader.ReadToEnd();
            reader.Close();
            Console.WriteLine("Inhalt des Verschlüsselten Textes: ");
            Console.WriteLine(txt);
            
            txt = decrypt(pathVerschluesselterText, password);            
            Console.WriteLine("Inhalt des entschlüsselten Textes: ");
            Console.WriteLine(txt);            
        }
    }
}

Asymetrische Verschlüsselung


Vorteile

Nachteile

Beispiel

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

namespace u3_RSA_Keys
{
    class Program
    {
        // Erzeugen eines neuen Schlüssel, oder Lesen eines zuvor generierten
        // aus dem CryptoServiceProvider
        static void RsaKeyAndCspParameter(string NameCspContainer)
        {
            // Zugriff auf den CryptoServiceProvider zum speichern und abrufen der Schlüssel
            CspParameters csp = new CspParameters();
            csp.KeyContainerName = NameCspContainer;

            RSACryptoServiceProvider myRsa = new RSACryptoServiceProvider(csp);

            myRsa.PersistKeyInCsp = true;

            string xmlKeys = myRsa.ToXmlString(false);

            // Öffentlichen Schlüssel veröffentlichen in einer Xml- Datei
            StreamWriter writer = new StreamWriter(@"..\..\" + NameCspContainer + ".xml");
            writer.Write(xmlKeys);
            writer.Close();            

            Console.WriteLine("Privater und öffentlicher Schlüssel: \n" + xmlKeys);
        }


        // Verschlüsseln eines Textes mit dem öffentlichen Schlüssel aus dem CryptoServiceProvider.        
        static byte[] Encrypt(string NameCspContainer, string txt)
        {
            CspParameters csp = new CspParameters();
            csp.KeyContainerName = NameCspContainer;

            RSACryptoServiceProvider myRsa = new RSACryptoServiceProvider(csp);

            myRsa.PersistKeyInCsp = true;


            byte[] txtBytes = Encoding.Unicode.GetBytes(txt);
            return myRsa.Encrypt(txtBytes, false);
        }

        // Verschlüsseln eines Textes mit dem öffentlichen Schlüssel aus einer Xml-Datei
        static byte[] ClientEncrypt(string NameCspContainer, string txt)
        {           

            RSACryptoServiceProvider myRsa = new RSACryptoServiceProvider();

            StreamReader reader = new StreamReader(@"..\..\" + NameCspContainer + ".xml");
            string xmlKey = reader.ReadToEnd();
            myRsa.FromXmlString(xmlKey);


            byte[] txtBytes = Encoding.Unicode.GetBytes(txt);
            return myRsa.Encrypt(txtBytes, false);
        }

        // Entschlüsseln eines verschlüsselten Textes mit dem Privaten Schlüssel 
        // aus dem CryptoServiceProvider
        static string Decrypt(string NameCspContainer, byte[] encryptedBytes)
        {
            CspParameters csp = new CspParameters();
            csp.KeyContainerName = NameCspContainer;

            RSACryptoServiceProvider myRsa = new RSACryptoServiceProvider(csp);

            myRsa.PersistKeyInCsp = true;

            byte[] txtBytes =  myRsa.Decrypt(encryptedBytes, false);

            string txt = Encoding.Unicode.GetString(txtBytes);

            return txt;
        }


        static void Main(string[] args)
        {
            
            // Demo der Funktionsweise von CspParameter a la CryptoServiceProvider
            for (int i = 0; i < 2; i++)
            {
                RsaKeyAndCspParameter("C1");
                Console.WriteLine();
                Console.WriteLine();
            }

            for (int i = 0; i < 2; i++)
            {
                RsaKeyAndCspParameter("C2");
                Console.WriteLine();
                Console.WriteLine();
            }

            // Ver- und Entschlüsseln lokal. Schlüssel werden in CryptoServiceProvider - 
            // Schlüsselcontainer "X1" gespeichert

            byte[] encryptedBytes = Encrypt("X1", "Das Pferd frisst keinen Gurkensalat");

            string txt = Decrypt("X1", encryptedBytes);

            // Verschlüsseln auf Client und Entschlüsseln auf Server. Der Client lädt den  
            // öffentlichen Schlüssel aus einer Xml- Datei

            // Schlüsselpaar erzeugen 
            RsaKeyAndCspParameter("Y1");

            encryptedBytes = ClientEncrypt("Y1", "Der Hund trinkt keine Milch");

            txt = Decrypt("Y1", encryptedBytes);



        }
    }
}

Hash- Codes

Hash- Codes bilden eine Menge von Informationen eindeutig auf einen binärcode fester Länge ab. Dabei ist es mathematisch nahezu unmöglich, aus einem gegebenen Hash auf die Menge der Texte zu schließen, aus denen er errechnet wurde. Kleine Änderungen im Text führen zu großen Änderungen des Hashwertes.




Verfahren

Codelänge

SHA1

160 bit

MD5

128 bit

Digitale Signatur

Die digitalen Signaturen kombinieren Public Key- Verschlüsselungsverfahren mit Hashwerten, um die Authenzität eines Dokumentes nachzuweisen. Dabei wird serverseitig der Hash des Dokumentes mit dem privaten Schlüssel verschlüsselt. Das Dokument wird mit dem verschlüsselten Hash erweitert und an den Client gesendet. Die Kombination aus Test und verschlüsselten Hash wird signiertes Dokument genannt. Der Client trennt den verschlüsselten Hash vom Dokument wieder ab. Danach entschlüsselt der Client den Hash mit seinem öffentlichen Schlüssel und vergleicht diesen mit dem aktuellen Hash des Dokumentes. Stimmen beide überein, dann folgt daraus. daß das Dokument während der Übertragung nicht durch einen Dritten geändert wurde.


X 509 Zertifikate

X 509 ist ein Standard zur Verwaltung von Schlüsseln asymetrischer Verschlüsselungsverfahren im Netz. Entwickelt wurde dieser im Rahmen des X 500 Standards für Netzwerkverzeichnisse (Datenbank zur Verwaltung von Netzwerkresourcen). Die Datensätze mit den Schlüsseln werden Zertifikate genannt. Sie sind Knoten untergeordnet, die als Certificate Authority (CA) bezeichnet werden. Die CA- s sind Dienste, welche neue Zertifikate auf Antrag hin ausstellen, und eine Liste aller bereits ausgestellten Zertifikate verwalten. Jeder Client eines Zertifikatsdienstes kann diesen prüfen lassen, ob ein gegebenes Zertifikat vom CA ausgestellt wurde. Ist der CA vertrauenswürdig, dann kann ein Client so sicherstellen, daß ein Server, der seines Daten mit dem privaten Schlüssel aus dem Zertifikat signiert, ebenfalls vertrauenswürdig ist.


Inhalt eines Zertifikates


Schlüsseltausch