RSA: Der unknackbare Code?
In dieser Lektion beschäftigen wir uns mit dem RSA-Verschlüsselungsalgorithmus und klassischen Methoden, ihn zu brechen. Der RSA-Algorithmus wurde 1979 von Rivest, Shamir und Adleman entwickelt und ist bis heute eine der erfolgreichsten Formen der Verschlüsselung. Wenn du jemals eine Finanztransaktion im Internet durchgeführt hast, ist es sehr wahrscheinlich, dass die dabei verwendeten Sicherheitscodes mithilfe des RSA-Systems verschlüsselt und deine Identität darüber verifiziert wurde.
Diese Lektion untersucht die Methodik des RSA-Verfahrens und zeigt, warum es in der klassischen Informatik praktisch unknackbar ist.
Fermats kleiner Satz
Im Zentrum des RSA-Verfahrens steht ein schönes mathematisches Resultat, bekannt als Fermats kleiner Satz:
Das bedeutet: Wenn man eine natürliche Zahl mit einer um eins verminderten Primzahl (also mit ) potenziert, dann ergibt der Rest bei Division durch immer 1. Die mod-Funktion („modulo“) gibt den Rest nach der Division an.
Zum Beispiel nehmen wir und :
Aufgabe 1
Überprüfe Fermats kleinen Satz für folgende Werte von und :
Hinweis zur Implementierung
Das letzte Beispiel in Übung 1 zeigt ein potenzielles Problem bei der Implementierung von RSA: Die Potenzfunktion wächst extrem schnell. Selbst mit kleinen Primzahlen kann es schnell zu Überlauf-Fehlern kommen, wenn man die Potenz direkt berechnet. Das lässt sich vermeiden, indem man ausnutzt, dass eine Potenz denselben Rest besitzt, egal ob man als Basis die Zahl oder das Ergebnis verwendet. Man kann also Zwischenergebnisse bei jeder Multiplikation modulo p reduzieren.
Nehmen wir zum Beispiel wieder und , sehen wir:
Aber:
Statt mit der Modulo-Operation zu berechnen, können wir verwenden und finden wie gewünscht
.
Daher können wir zur Berechnung der modularen Potenz in Python eine Schleife schreiben, die x mehrfach mit sich selbst multipliziert und dabei jedes Mal den Rest modulo p berechnet.
Aufgabe 2
Implementiere den folgenden Python Code (% ist in Python die Notation für die Modulo-Operation):
def powerMod(a, b, c): # raises a to the power of b modulo c res = a % c for i in range(0, b - 1): res = a * res % c return res x = 5 p = 11 print( powerMod(x, p - 1, p) )
Nutze den Code, um herauszufinden, welche der folgenden Zahlen keine Primzahlen sind (weil Fermats kleiner Satz für sie nicht gilt):
- 1367
- 1369
- 7527
- 7531
- 7537
- 15723
- 15727
- 18791
Der RSA-Algorithmus
RSA beruht auf einer Variante von Fermats kleinem Satz:
Als Beispiel nehmen wir , und :
Multipliziert man beide Seiten der Gleichung mit , erhält man:
Dies bedeutet, dass man (mod pq) erhält, wenn man mit potenziert. Der RSA Algorithmus nutzt diese Tatsache für eine Ver- und Entschlüsselung. Wenn wir zwei Zahlen und finden mit:
, dann gilt
Ist die zu verschlüsselnde Nachricht, definieren wir als Verschlüsselungsschlüssel und als Entschlüsselungsschlüssel. Die beiden Schlüssel zum Ver- und Entschlüsseln sind also unterschiedlich (dies nennt man auch asymmetrische Verschlüsselung).
Schritt 1 – Verschlüsselung
Wir potenzieren die Nachricht mit , um die verschlüsselte Nachricht zu erhalten:
Die Sicherheit der RSA-Verfahrens beruht darauf, dass die Kenntnis von , und nicht ausreicht, um zu berechnen. Es gibt keinen eindeutigen Weg, um die -te Wurzel in modularer Arithmetik zu berechnen. Dies kann man zum Beispiel durch Fermats kleinen Satz selbst sehen:
Falls wir also die vierte Wurzel von 1 (mod 5) bestimmen wollen, können wir nicht wissen, ob die ursprüngliche Zahl 1, 2, 3 oder 4 ist.
Schritt 2 – Entschlüsselung
Um die verschlüsselte Nachricht wieder zu entschlüsseln, wird diese Nachricht mit (mod pq) potenziert. Mithilfe der Potenzgesetze erkennt man:
Der RSA-Algorithmus: Zusammenfassung des Prozesses
| Sender | Öffentlichkeit | Empfänger |
|---|---|---|
| Was sie wissen | ||
| x (zu verschlüsselnde Nachricht) e (Verschlüsselungsschlüssel) pq (zu verwendendes Modul) p oder q nicht einzeln bekannt | y (verschlüsselte Nachricht) e (Verschlüsselungsschlüssel) pq (zu verwendendes Modul) p oder q nicht einzeln bekannt | y (verschlüsselte Nachricht) d (Entschlüsselungsschlüssel) pq (zu verwendendes Modul) p und q sind einzeln bekannt, daher kann d errechnet werden |
| Was sie tun | ||
| Berechnen der verschlüsselten Nachricht y = xe (mod pq) | Das Wissen über e und pq reicht nicht aus, um y zu entschlüsseln | Berechnen der entschlüsselten Nachricht x = yd (mod pq) |
Beispiel
Wir verwenden p = 89, q = 151 und pq = 13439. Falls wir e = 7543 setzen, ist der zugehörige Entschlüsselungsschlüssel d = 7.
Wir verschlüsseln mit dem folgenden Python-Code die Beispielnachricht 8571:
Als verschlüsselte Nachricht sollte sich 1134 ergeben.
Im zweiten Schritt entschlüsseln wir diese Nachricht wieder mit dem Entschlüsselungsschlüssel d=7:
Es ergibt sich wieder die ursprüngliche Nachricht 8571.
Aufgabe 3a
Verwende pq=13439 und e = 5077, um die Nachricht QUANTUM zu verschlüsseln. Wandle jeden Buchstaben in eine Zahl um (A = 1, B = 2, …) und verschlüssele jeden Buchstaben einzeln.
Aufgabe 3b
Entschlüssele die Nachricht wieder mit pq=13439 und d = 13.
Der RSA-Algorithmus: Zusammenfassung
Das RSA-Verfahren besitzt zwei Schlüssel: einen öffentlichen Schlüssel und einen privaten (geheimen) Schlüssel. Der öffentliche Schlüssel besteht aus und ; der private Schlüssel besteht aus und den einzelnen Zahlen und .
Der öffentliche Schlüssel kann ohne Einschränkungen herausgegeben werden, da dieser nur zum Verschlüsseln, aber nicht zum Entschlüsseln verwendet werden kann. Möchte eine Bank zum Beispiel eine geheim zuhaltende Transaktion mit einem Kunden (z. B. eine PIN oder eine Kartenprüfnummer einer Kreditkarte) durchführen, kann die Bank den öffentlichen Schlüssel veröffentlichen. Der Kunde kann seine Information über die Operation
verschlüsseln und an die Bank übermitteln. Selbst wenn ein Hacker die Nachricht abfängt und ebenfalls im Besitz des öffentlichen Schlüssels der Bank ist, kann dieser nicht die ursprüngliche Nachricht berechnen. Nur die Bank selber kann mit dem privaten Schlüssel die Nachricht entschlüsseln, um die geheime Information zu lesen.
Das Brechen von RSA auf einem klassischen Computer
Um RSA zu brechen, muss man kennen. Dazu benötigt man jedoch
.
Obwohl öffentlich ist, ist das Produkt
nicht einfach zu bestimmen. Dazu müsste man in seine Primfaktoren zerlegen. Das ist für große Primzahlen und extrem aufwendig. Die folgende Aufgabe macht diese Herausforderung deutlich:
Aufgabe 4
Schreibe ein Programm, um die Zahl 900 239 055 271 631 zu faktorisieren. Stoppe die Zeit, die dein Programm benötigt, um die Faktoren und zu finden.
Zusammenfassung
Faktorisieren ist ein Beispiel für ein nur schwierig lösbares Problem: Es gibt eine Methode zum Finden der beiden Faktoren (Trial and Error Division), aber die benötigte Zeit wächst exponentiell mit der Größe der Zahl. Wählt man die beiden Primzahlen groß genug, könnten selbst Supercomputer das Produkt dieser Zahlen nicht in realistischer Zeit faktorisieren. In unserem Beispiel waren die beiden Primzahlen 8-stellig. In heutigen Implementationen von RSA werden typischerweise Primzahlen mit etwa je 300 Stellen verwendet. Damit ist derzeit RSA der Goldstandard der Internetsicherheit für abhörsichere Kommunikation.
Doch Quantencomputing könnte dieses Prinzip bedrohen: Mit Shors Algorithmus ließe sich die Komplexität der Faktorisierung reduzieren – so weit, dass RSA in Echtzeit gebrochen werden könnte. In der nächsten Lektion wirst du lernen, wie der Shor-Algorithmus die Sicherheit von RSA bedrohen kann und warum dies eine Revolution in der Kryptographie auslösen könnte.