Verschlüsselungskonzepte erklärt 14.10.2024, 00:00 Uhr

Grundlagen der Kryptografie

Die Kryptografie ist ein komplexes Thema. Das Verständnis einiger Begriffe macht das Entwicklerleben leichter.
(Quelle: dotnetpro)
Bei der Kryptografie geht es darum, Daten zu verschlüsseln, um zu verhindern, dass diese für nicht autorisierte Parteien zur Verfügung stehen. Hierzu werden die Ausgangsdaten – bezeichnet als Klartext – von einem Algorithmus unter Verwendung eines Schlüssels so umgewandelt, dass das Ergebnis – der sogenannte Geheimtext – nicht mehr lesbar ist. Nur wer im Besitz des passenden Schlüssels ist, kommt wieder an die Daten. Dieser Artikel stellt einige wichtige Konzepte, Begrifflichkeiten und Zusammenhänge vor.

Zufallszahlen

Den Schlüssel, der für die Ver- und Entschlüsselung benötigt wird, sollte es möglichst nur einmalig geben. Um dies sicherzustellen, werden Zufallszahlen generiert. Wer nun jedoch seine Gedanken in Richtung des .NET-Typs System.Random [1] lenkt, sollte vorsichtig sein, da dieser bei der Instanzierung einen Seed verwendet, das heißt einen Wert, der für die Initialisierung benötigt wird. In Bild 1 ist ein Beispiel zu sehen, wie zwei Instanzen mit dem identischen Seed generiert werden (rot markiert). Die zugehörigen rot markierten Ausgaben zeigen, dass hierdurch auch zweimal der identische „Zufallswert“ generiert wurde. Die grünen Markierungen dagegen zeigen, wie mit einem anderen Seed ein anderer Zufallswert berechnet wurde.
Der .NET-Typ System.Random (Bild 1)
Quelle: Autor
Der parameterlose Standard-Konstruktor ermittelt einen Seed anhand der Systemuhr, was bedeutet, dass es durchaus passieren kann, dass bei mehreren nacheinander erstellten System.Random-Instanzen diese den gleichen „Zufallswert“ produzieren. Da die Zufallszahlen für die Key-Generierung zwingend benötigt werden, ist somit System.Random für den Einsatz in der Kryptografie ungeeignet.
.NET stellt für die Generierung von Zufallszahlen im Kontext der Kryptografie den Typ RandomNumberGenerator zur Verfügung, der bei Generierung zwar langsamer ist, aber gegenüber dem Stellenwert der Absicherung von Daten fällt dieser Nachteil nicht ins Gewicht. Bild 2 zeigt die Verwendung dieses Typs. Die Ausgabe enthält die fünf generierten Zufallswerte, es gibt keinerlei Übereinstimmung.
Verwendung des RandomNumberGenerator (Bild 2)
Quelle: Autor
Mit dem Parameterwert 32 beim Aufruf von RandomNumberGenerator wird angegeben, dass 32 Bytes von Zufallswerten zu generieren sind.

RandomNumberGenerator.GetBytes(32)
Um die generierten Zufallswerte in einem lesbaren Format zu erhalten, werden diese in Base64 konvertiert. Obwohl auch für diesen Vorgang der Begriff Encodieren verwendet wird, handelt es sich hier nicht um eine Verschlüsselung; der Base64-String kann problemlos wieder in das ursprüngliche Byte-Array-Format zurückverwandelt (decodiert) werden.

Symmetrische Verschlüsselung – AES

Bei der symmetrischen Verschlüsselung kommt lediglich ein Schlüssel zum Einsatz. Dieser eine Schlüssel wird sowohl zum Verschlüsseln als auch zum Entschlüsseln verwendet.
Die symmetrische Verschlüsselung hat folgende Merkmale:
  • Sie ist sehr sicher. Der Advanced Encryption Standard (AES [3]) Standard wurde von Joan Daemen und Vincent Rijmen unter der Bezeichnung „Rijndael“ entwickelt und löste den Data Encryption Standard (DES [4]) ab, der nur eine geringe Schlüssellänge von 56 Bit unterstützte.
  • Die symmetrische Verschlüsselung ist im Vergleich zur asymmetrischen Verschlüsselung, die später erläutert wird, deutlich schneller.
  • Den Schlüssel sicher auszutauschen ist eine Herausforderung. Sollte dieser in die falschen Hände geraten, könnte zwischen den rechtmäßigen Sender und Empfänger ein „Man in the middle“ in­stalliert werden, der die versendeten Daten vor dem Empfänger entgegennimmt, entschlüsselt und sie bei Bedarf manipuliert, verschlüsselt und weiterleitet. Der Empfänger könnte somit mit falschen Informationen versorgt werden.
AES verwendet folgende Parameter:
  • Eine Schlüssellänge von 128, 192 oder 256 Bit.
  • Einen 16-Byte-Initialisierungsvektor. Dieser Wert wird sowohl für die Ver- als auch die Entschlüsselung eingesetzt, um eine gewissen Entropie, das heißt eine Unordnung, zu erreichen.
Beim AES-Verfahren handelt es sich um eine sogenannte „Blockchiffre“ oder auch „block cipher“. Damit wird ein deterministisches Verschlüsselungsverfahren bezeichnet, das einen Klartextabschnitt fester Länge (die zu verschlüsselnden Daten in lesbarer Form) in einen Geheimtext abbildet. Wie bereits beschrieben kann beim verwendeten Schlüssel zwischen einer Größe von 128, 192 oder 256 Bit gewählt werden.
Beim AES wird zunächst jeder Block in eine Tabelle mit vier Zeilen geschrieben. Die Anzahl der Spalten hängt von der Größe ab. Jede Zelle in der Tabelle enthält 8 Bit; bei 128 Bit hat die Tabelle also vier Spalten (Bild 3). Bei einer Länge von 256 Bit hätte die Tabelle acht Spalten.
AES-Tabelle mit 128 Bit (Bild 3)
Quelle: Autor
Der Vorgang der Verschlüsselung durchläuft mehrere Runden. Jede Runde vollzieht hierbei folgende Schritte:
  • Substitution: Jedes Byte wird unter Verwendung einer Substitutionsbox, auch S-Box genannt, verschlüsselt. Enthielt beispielsweise eine Zelle ursprünglich das Symbol A(0,0), enthält sie danach das Symbol G(0,0). Jedes Byte wird durch einen anderen Wert ersetzt.
  • Shift Row: Jede Zeile in der Tabelle wird um eine bestimmte Anzahl von Spalten nach links verschoben.
  • Mix Column: Die Spalten werden mithilfe von Matrixmanipulationen vermischt.
  • Key Addition: Die Matrix wird mit einem Rundenschlüssel, der aus dem Eingabeschlüssel generiert wird, mit der XOR-Operation verknüpft.
Diese Runden werden mehrfach durchlaufen. Das Verfahren ist vollständig umkehrbar, das heißt, die verschlüsselten Daten können tatsächlich auch wieder entschlüsselt werden.
So viel zur Theorie. In der Praxis kann dies, wie in Bild 4 zu sehen, in C# umgesetzt werden. Die Klasse EncryptionAes bietet die beiden Funktionen Encrypt und Decrypt an. Erstere wird mit den zu verschlüsselnden Daten, dem Schlüssel, der sowohl dem Sender als auch dem Empfänger bekannt sein muss, und dem Initialisierungsvektor versorgt. Die zweite Funktion erwartet dagegen die verschlüsselten Daten, den gemeinsamen Schlüssel und den Initialisierungsvektor.
Klasse zur AES-Verschlüsselung (Bild 4)
Quelle: Autor
Die Verwendung dokumentiert Bild 5. Zunächst werden der gemeinsame Verschlüsselungs-Key und der Initialisierungsvektor mit Aufrufen an
Daten mittels AES ver- und entschlüsseln (Bild 5)
Quelle: Autor

RandomNumberGenerator.GetBytes
erzeugt, welche für die Verschlüsselung (rot markiert) und Entschlüsselung (grün) angewendet werden.

Asymmetrische Verschlüsselung – RSA

Die symmetrische Verschlüsselung ist eine gute Sache. Die Herausforderung ist jedoch, sicherzustellen, dass der Key sicher zwischen den Kommunikationspartnern ausgetauscht wird; dies wurde bereits zuvor mit dem Hinweis auf den „Man in the middle“ erklärt. Hier kommt die asymmetrische Verschlüsselung ins Spiel, die zwei unterschiedliche Schlüssel nutzt. Sie arbeitet mit einem „Public Key“, der prinzipiell jedem zur Verfügung steht und zur Verschlüsselung zum Einsatz kommt (Bild 6). Die Entschlüsselung kann nur durch den „Private Key“ erfolgen, der mathematisch mit dem Public Key verknüpft ist. Der Private Key steht nur dem Empfänger zur Verfügung, um die verschlüsselte Nachricht zu entschlüsseln.
Asymmetrische Verschlüsselung (Bild 6)
Quelle: Autor
Dieses Verfahren wird als asymmetrisch bezeichnet, da im Gegensatz zur symmetrischen Verschlüsselung zwei Schlüssel mit unterschiedlichen Aufgaben zum Einsatz kommen: der Public Key zum Verschlüsseln und der Private Key zum Entschlüsseln. Bei der symmetrischen Verschlüsselung dagegen wird lediglich ein Schlüssel genutzt, der sowohl für die Verschlüsselung als auch für die Entschlüsselung Verwendung findet.
Einige Merkmale der asymmetrischen Verschlüsselung:
  • Im Vergleich zur symmetrischen Verschlüsselung ist der Vorgang, Nachrichten zu verschlüsseln und zu entschlüsseln, deutlich langsamer.
  • Auch die Menge der auf einmal zu verschlüsselnden Daten ist limitiert.
  • Daher wird sie gerne verwendet, um symmetrische Schlüssel zu verschlüsseln.
  • Die Schlüssellänge kann zwischen 1024, 2048 und 4096 Bit variieren, wobei 1024-Bit-Schlüssel heute als nicht mehr ­sicher gelten.
Bild 7 zeigt den ersten Abschnitt der C#-Klasse. Zunächst wird im Konstruktor eine Instanz des .NET-Typs RSA erstellt. Die Factory-Funktion wird mit der Information der Schlüssellänge von 2048 aufgerufen. Als Nächstes folgt die Funktion Encrypt, sie wandelt vor der Verschlüsselung die zu verschlüsselnde Zeichenkette zunächst in ein Byte-Array um. Das Gegenstück hierzu, die Funktion Decrypt, dient dazu, ein Byte-Array mit verschlüsselten Daten wieder zu entschlüsseln.
ctor und erste Funktionen der RSA-Klasse (Bild 7)
Quelle: Autor
In Bild 8 sind die Funktionen der RSA-Klasse zu sehen, die für den Export und den Import des Public und des Private Keys genutzt werden. Bild 9 veranschaulicht, wie die Klasse zur Ver- und Entschlüsselung verwendet wird.
Private und Public Key der RSA-Klasse (Bild 8)
Quelle: Autor
RSA-Klasse in Verwendung (Bild 9)
Quelle: Autor
Wie die Schlüsselinformationen exportiert und wieder importiert werden, zeigt Bild 10. Die erste Instanz der RSA-Klasse (grün markiert) exportiert diese und verschlüsselt anschließend die Daten. Die grünen Teile entsprechen somit dem Versender. Die zweite RSA-Klasse (rot) steht für den Empfänger. Sie importiert beide Schlüsselinformationen und entschlüsselt die verschlüsselte Information.
RSA-Klasse mit Import/Export der Schlüssel (Bild 10)
Quelle: Autor

Hybride Verschlüsselung mit AES und RSA

Der Inhalt der vorangegangenen Abschnitte kann damit wie folgt zusammengefasst werden:
  •   Die symmetrische Verschlüsselung ist recht flott im Vergleich zur asymmetrischen Verschlüsselung.
  •   Der sichere Austausch eines symmetrischen Schlüssels ist schwierig und birgt Sicherheitsrisiken.
  • Der Schlüsselaustausch der asymmetrischen Verschlüsselung ist deutlich einfacher. Der Zugriff auf den Public Key kann grundsätzlich jedem gewährt werden. Nur der Private Key muss sicher verwahrt werden.
Daher bietet es sich an, das Beste aus beiden Welten mitei­nander zu kombinieren, was als hybride Verschlüsselung bezeichnet wird. Symmetrische Schlüssel werden mit RSA verschlüsselt und können dadurch sicher ausgetauscht werden.
Als Beispiel soll der sichere Nachrichtenaustausch zwischen zwei Chat-Partnern, Frank und Martina, dienen. Frank möchte eine Nachricht an Martina senden und vollzieht dazu für den Versand folgende Schritte:
  • Generierung eines AES-Session-Keys (symmetrische Verschlüsselung).
  • Generierung eines Initialisierungsvektors (Zufallswert, dient der Entropie).
  • Verschlüsselung der Nachricht mit dem AES-Schlüssel und dem Initialisierungsvektor.
  • Verschlüsselung des AES-Session-Keys mit dem Public Key von Martina (RSA).
  • Versand (1.) der verschlüsselten Daten, (2.) des verschlüsselten Session Keys und (3.) des Initialisierungsvektors an Martina.
Auf der Empfangsseite muss Martina folgende Schritte durchlaufen:
  • Entschlüsselung des empfangenen, mit dem RSA-Public-Key verschlüsselten AES-Session-Keys mit dem zugehörigen RSA-Private-Key.
  • Entschlüsselung der Nachricht mit dem entschlüsselten AES-Session-Key und dem Initialisierungsvektor.
Nachdem Martina die Nachricht gelesen hat, möchte sie Frank antworten und vollzieht hierfür folgende Schritte:
  • Generierung eines neuen AES-Session-Keys (symmetrische Verschlüsselung). Der empfangene Session Key wird nicht wieder verwendet.
  • Generierung eines neuen Initialisierungsvektors.
  • Martina verschlüsselt die Nachricht für Frank mit dem neuen Session Key mittels RSA (asymmetrisch), aber diesmal mit Franks Public Key.
  • Martina versendet (1.) die verschlüsselten Daten, (2.) den verschlüsselten Session Key und (3.) den Initialisierungsvektor.
Um die von Martina empfangene Nachricht zu lesen, durchläuft Frank folgende Sequenz:
  • Entschlüsselung des mit dem RSA-Public-Key verschlüsselten AES-Session-Keys mit dem eigenen RSA-Private-Key.
  • Mit dem entschlüsselten AES-Session-Key kann die Nachricht entschlüsselt werden.
Die Implementierung beginnt mit dem „Datenpaket“, das in Bild 11 dargestellt ist und über die folgenden drei Member verfügt:
Das Datenpaket mit seinen Membern (Bild 11)
Quelle: Autor
  • einen AES-Key in verschlüsselter Form,
  • die Nachricht, die mit dem AES-Key verschlüsselt wurde,
  • den Initialisierungsvektor.
Das hybride Verschlüsselungsverfahren wird in einer Klasse gekapselt. In Bild 12 ist die Funktion zu sehen, mit der die Daten verschlüsselt werden. Die Bestandteile, die die symmetrische Verschlüsselung behandeln, sind rot markiert, während die asymmetrischen Verschlüsselungsbestandteile grün markiert sind.
Hybride Verschlüsselung (Bild 12)
Quelle: Autor
Zunächst wird der AES-Session-Key erstellt und in das Datenpaket gereicht. Die eigentlichen Daten werden im nächsten Schritt mit diesem AES-Session-Key verschlüsselt und ebenfalls dem Datenpaket übergeben. Final wird der symmetrische Schlüssel asymmetrisch verschlüsselt.
Bild 13 zeigt die Funktion, die der hybriden Entschlüsselung dient. Auch hier wurden die symmetrischen Anweisungen (rot markiert) und die asymmetrischen (grün) Anweisungen farblich gekennzeichnet. Der asymmetrisch verschlüsselte symmetrische Schlüssel wird zunächst entschlüsselt. Anschließend wird mit diesem die symmetrisch verschlüsselte Nachricht entschlüsselt.
Hybride Entschlüsselung (Bild 13)
Quelle: Autor
Bild 14 dokumentiertdie Anwendung. Im Konstruktor der EncryptionRSA-Klasse wird das für die asymmetrische Verschlüsselung benötige Objekt erstellt, siehe Listing 1. Als Nächstes wird dieses Objekt gemeinsam mit der zu verschlüsselnden Nachricht hybrid verschlüsselt und im Anschluss wieder entschlüsselt.
Verwendung der hybriden Verschlüsselung (Bild 14)
Quelle: Autor
Listing 1: Konstruktor der RSA-Kapselung
private readonly RSA _rsa;
public EncryptionRSA()
{
  const int keySize = 2048;
  rsa = RSA.Create(keySize);
}

Hashing

Bei dem Thema Kryptografie kommt man unweigerlich mit dem Begriff „Hashing“ in Berührung. Bei einem Hash handelt es sich um einen digitalen Fingerabdruck von Daten. Wird für eine Textnachricht der Hash berechnet, wird eine scheinbar zufällig zusammengewürfelte Zeichenfolge generiert. Das Hashing hat bestimmte Merkmale:
  • Die Berechnung eines Hash ist recht einfach.
  • Es ist nicht möglich, eine Nachricht mit einem bestimmten Hash-Wert zu berechnen.
  • Eine Änderung der Nachricht, ohne den Hash zu verändern, ist nicht möglich.
  • Es ist nicht möglich, unterschiedliche Nachrichten mit dem gleichen Hash zu erhalten.
  • Hashing ist somit eine „One way operation“. Hingegen ist die Verschlüsselung eine „Two way operation“.
Wird vor dem Versand einer Nachricht deren Hash berechnet und mit der Nachricht an den Empfänger geliefert, kann der Empfänger selbst den Hash der empfangenen Nachricht berechnen und mit dem übertragenen Hash vergleichen. Sind beide Hash-Werte identisch, kann davon ausgegangen werden, dass die Nachricht unverändert empfangen wurde.
Bild 15 zeigt, wie von zwei nahezu identischen Nachrichten der Hash berechnet wird. Der Unterschied ist das letzte Zeichen, auf welches der rote Pfeil hinweist. Zu sehen ist, dass die berechneten Hash-Werte absolut unterschiedlich sind.
Hash-Berechnung für zwei sehr ähnliche Nachrichten (Bild 15)
Quelle: Autor

HMAC – Hashed Message
Authentication Code

Die Kombination aus einem „One way“-Hash und einem kryptografischen Schlüssel wird als HMAC bezeichnet. Der HMAC lässt sich ebenfalls wie ein Hashcode für die Prüfung der Nachrichtenintegrität verwenden. Der HMAC kann zudem zur Authentifizierung der Nachricht verwendet werden – nur wer im Besitz des kryptografischen Schlüssels ist, kann den HMAC berechnen.
Listing 2 zeigt, wie die Berechnung eines HMAC in einer Funktion gekapselt wird. Übergeben werden die Daten, für die der Hash berechnet wird, und der kryptografische Schlüssel. Die Verwendung der zugehörigen .NET-Klasse ist trivial.
Listing 2: HMAC berechnen
public static byte[] HmacSha512(byte[] toGetHash, byte[] key)
{
  using var hmac = new HMACSHA512(key);
  return hmac.ComputeHash(toGetHash);
}
Auf das Beispiel von Frank und Martina bezogen wäre noch ein zusätzlicher Schritt beim Versand von Frank zu Martina nötig: Der HMAC der verschlüsselten Daten unter Verwendung des AES-Session-Keys müsste berechnet werden.
Zunächst wird hierzu das Datenpaket, wie es in Bild 16 zu sehen, ist erweitert. Die hybride Verschlüsselung ist in der Klasse EncryptionHybrid gekapselt. Sie ähnelt dem bisher gesehenen Code, jedoch ergänzt um die Erweiterung zur Berechnung des HMAC (Bild 17). Der HMAC berechnet den Wert aus den symmetrisch verschlüsselten Daten und dem Initialisierungsvektor. Beide werden in der Funktion Combine zusammengeführt.
Für den HMAC erweitertes Datenpaket (Bild 16)
Quelle: Autor
Berechnung des HMAC beim Verschlüsseln (Bild 17)
Quelle: Autor
Bei der Entschlüsselung kann nun der HMAC wie bereits zuvor aus den symmetrisch verschlüsselten Daten und dem Ini­tialisierungsvektor berechnet werden und mit dem HMAC der empfangenen Daten verglichen werden (Bild 18).
Berechnung des HMAC beim Entschlüsseln (Bild 18)
Quelle: Autor

Fazit

Die Kryptografie ist ein wichtiges Thema. Dieser Beitrag hat hoffentlich zum Verständnis einiger Begriffe aus dieser Domäne beigetragen.
Dokumente
Artikel als PDF herunterladen


Das könnte Sie auch interessieren