Kapitel 4 · Lszqupmphjf?!

RSA-Verschlüsselung in Python

RSA steckt in fast jeder sicheren Internetverbindung. Das Programm baut das Verfahren von Grund auf nach: Es sucht zwei riesige Primzahlen, berechnet daraus ein Schlüsselpaar und verschlüsselt einen Satz – mit Zahlen, die über 300 Stellen haben.

Aus dem Buch · Kapitel 4 Profi VerschlüsselungMathe & Fraktale Python 3 · läuft im Browser
Bereit · Python startet beim ersten Klick
# RSA-Verschlüsselung – Kapitel 4 »Lszqupmphjf?!«
# aus »Coding for Fun mit Python«, portiert auf Python 3
import random
import time

bits = 512  # Länge jeder Primzahl in Bit – der Modul n hat doppelt so viele


def modpot(x, y, n):
    '''
    Schnelles Potenzieren x^y (mod n)
    nach der Methode "square and multiply".
    Zwischenergebnisse werden modulo n reduziert
    '''
    result = 1
    while y > 0:
        if y % 2 == 1:
            result *= x
            result %= n
            y -= 1
        else:
            x *= x
            x %= n
            y //= 2

    return result


def xggt(a, b):
    '''Erweiterter euklidischer Algorithmus: ggT(a, b) = x*a + y*b'''
    x1, x2, y1, y2 = 1, 0, 0, 1
    while b:
        q = a // b
        x1, x2, y1, y2 = x2, x1 - q * x2, y2, y1 - q * y2
        a, b = b, a % b

    return a, x1, y1


def inverse_mod(a, m):
    ggt, x, y = xggt(a, m)
    if ggt == 1:
        # x ist das Inverse – sicherstellen, dass es positiv ist
        return (x + m) % m
    # a und m haben einen gemeinsamen Teiler: es gibt kein Inverses
    return None


def toBinary(n):
    '''wandelt n in die Liste seiner Binärziffern um (niedrigste zuerst)'''
    r = []
    while n > 0:
        r.append(n % 2)
        n = n // 2

    return r


def test(a, n):
    '''True, wenn die Zahl a beweist, dass n zusammengesetzt ist'''
    b = toBinary(n - 1)
    d = 1
    for i in range(len(b) - 1, -1, -1):
        x = d
        d = (d * d) % n
        if d == 1 and x != 1 and x != n - 1:
            return True
        if b[i] == 1:
            d = (d * a) % n
    if d != 1:
        return True

    return False


def MillerRabin(n, s=50):
    '''n ist sehr wahrscheinlich prim, wenn keiner der s Tests anschlägt'''
    for j in range(1, s + 1):
        a = random.randint(1, n - 1)
        if test(a, n):
            return False  # n ist zusammengesetzt
    return True  # n ist mit sehr hoher Wahrscheinlichkeit prim


def randomPrime(bits):
    while True:
        # ungerade Zufallszahl, deren höchstes Bit gesetzt ist
        candidate = random.getrandbits(bits) | (1 << (bits - 1)) | 1
        if MillerRabin(candidate):
            return candidate


def findMultiplicativeInverse(p, q, e):
    phi = (p - 1) * (q - 1)
    while xggt(phi, e)[0] > 1:
        e += 2
    d = inverse_mod(e, phi)
    return e, d


def strToNumber(text):
    x = 1
    number = 0
    for zeichen in text.encode("utf-8"):
        number += zeichen * x
        x *= 256
    return number


def numberToStr(number):
    text = bytearray()
    while number > 0:
        text.append(number % 256)
        number = number // 256
    return text.decode("utf-8", errors="replace")


def short(number):
    digits = str(number)
    if len(digits) <= 44:
        return digits
    return f"{digits[:20]}…{digits[-20:]} ({len(digits)} Stellen)"


# --- 1. Mini-RSA zum Nachrechnen -------------------------------------------
p, q = 61, 53
n = p * q
e, d = findMultiplicativeInverse(p, q, 17)
print("1) Mini-RSA mit p = 61 und q = 53")
print(f"   n = {n}, φ(n) = {(p - 1) * (q - 1)}, e = {e}, d = {d}")
m = 65
c = modpot(m, e, n)
print(f"   verschlüsseln: {m}^{e} mod {n} = {c}")
print(f"   entschlüsseln: {c}^{d} mod {n} = {modpot(c, d, n)}")

# --- 2. Echte Schlüssel aus großen Primzahlen ------------------------------
print()
print(f"2) Zwei Primzahlen mit je {bits} Bit suchen …")
start = time.perf_counter()
p = randomPrime(bits)
q = randomPrime(bits)
print(f"   gefunden in {time.perf_counter() - start:.2f} s")
print("   p =", short(p))
print("   q =", short(q))
n = p * q
e, d = findMultiplicativeInverse(p, q, 65537)
print("   öffentlicher Schlüssel: n =", short(n))
print("                           e =", e)
print("   privater Schlüssel:     d =", short(d))

# --- 3. Eine Nachricht verschlüsseln ---------------------------------------
message = "Coding for Fun mit Python – geheime Grüße!"
number  = strToNumber(message)
cipher  = modpot(number, e, n)
plain   = numberToStr(modpot(cipher, d, n))
print()
print("3) Nachricht:    ", message)
print("   als Zahl:     ", short(number))
print("   verschlüsselt:", short(cipher))
print("   entschlüsselt:", plain)

Jeder Lauf erzeugt neue Primzahlen und damit neue Schlüssel.

KonsoleBeispielausgabe
1) Mini-RSA mit p = 61 und q = 53
   n = 3233, φ(n) = 3120, e = 17, d = 2753
   verschlüsseln: 65^17 mod 3233 = 2790
   entschlüsseln: 2790^2753 mod 3233 = 65

2) Zwei Primzahlen mit je 512 Bit suchen …
   gefunden in 0.97 s
   p = 11926820322923989382…18238178215722603781 (155 Stellen)
   q = 69347954487960286024…06525536341125627177 (154 Stellen)
   öffentlicher Schlüssel: n = 82710059294021261731…90923633049096556237 (308 Stellen)
                           e = 65537
   privater Schlüssel:     d = 71018556947258166553…68605781364943314593 (308 Stellen)

3) Nachricht:     Coding for Fun mit Python – geheime Grüße!
   als Zahl:      78434203983127886073…51824242721098592067 (110 Stellen)
   verschlüsselt: 27399396438365852770…12787296461397261875 (308 Stellen)
   entschlüsselt: Coding for Fun mit Python – geheime Grüße!

Was du hier lernst

  • Asymmetrische Verschlüsselung
  • Modulare Arithmetik
  • Square and Multiply
  • Erweiterter euklidischer Algorithmus
  • Miller-Rabin-Primzahltest
  • Große Ganzzahlen in Python
  • Text als Zahl (UTF-8)

So funktioniert RSA

Bei Caesar und Vigenère verschlüsselt und entschlüsselt man mit demselben Geheimnis. RSA trennt beides: Mit dem öffentlichen Schlüssel kann jeder eine Nachricht verschlüsseln, lesen kann sie nur, wer den privaten Schlüssel besitzt. Ron Rivest, Adi Shamir und Leonard Adleman haben das Verfahren 1977 vorgestellt. Seine Sicherheit beruht auf einer einfachen Asymmetrie: Zwei große Primzahlen zu multiplizieren ist leicht. Das Produkt wieder in seine Faktoren zu zerlegen, ist praktisch unmöglich.

1. Die Idee in kleinen Zahlen

Der erste Teil des Programms rechnet mit Zahlen, die man noch im Kopf überblickt. Aus den Primzahlen p = 61 und q = 53 entsteht der Modul n = 3233. Dazu gehört φ(n) = (p − 1)(q − 1) = 3120. Als öffentlichen Exponenten wählt man eine Zahl e, die mit 3120 keinen gemeinsamen Teiler hat, hier 17. Der private Exponent d ist die Zahl, für die e · d beim Teilen durch φ(n) den Rest 1 lässt. Das ist 2753, denn 17 · 2753 = 46801 = 15 · 3120 + 1.

Verschlüsseln heißt: die Nachricht m hoch e, modulo n. Aus 65 wird 65¹⁷ mod 3233 = 2790. Entschlüsseln geht genauso, nur mit d statt e: 2790²⁷⁵³ mod 3233 ergibt wieder 65.

Warum kommt die Nachricht zurück?

Hinter RSA steckt der Satz von Euler: Für Zahlen m, die mit n keinen gemeinsamen Teiler haben, gilt m^φ(n) ≡ 1 (mod n). Weil e · d = k · φ(n) + 1 ist, wird aus (m^e)^d = m^(k·φ(n)+1) wieder m. Wer n in p und q zerlegen kann, kennt φ(n) und damit auch d. Deshalb hängt alles daran, dass niemand n faktorisieren kann.

2. Schnelles Potenzieren: »square and multiply«

2790²⁷⁵³ ist eine Zahl mit rund 9500 Stellen, und im echten RSA haben die Exponenten über 300 Stellen. Direkt ausrechnen geht nicht. modpot aus dem Buch nutzt zwei Tricks. Ist der Exponent gerade, wird die Basis quadriert und der Exponent halbiert, denn x^(2k) = (x²)^k. Ist er ungerade, wandert ein Faktor ins Ergebnis. Nach jedem Schritt wird modulo n reduziert, so bleiben alle Zwischenwerte klein:

while y > 0:
    if y % 2 == 1:
        result *= x
        result %= n
        y -= 1
    else:
        x *= x
        x %= n
        y //= 2

Statt 2753 Multiplikationen braucht das nur 16 Schleifendurchläufe. Bei einem Exponenten mit 1024 Bit sind es etwa 1500 – der naive Weg bräuchte eine Anzahl von Multiplikationen, die selbst über 300 Stellen hat.

3. Das Inverse mit dem erweiterten Euklid

Wie findet man d? Der erweiterte euklidische Algorithmus xggt(a, b) berechnet nicht nur den größten gemeinsamen Teiler, sondern auch zwei Zahlen x und y mit x · a + y · b = ggT(a, b). Ist der ggT von e und φ(n) gleich 1, dann ist x · e um genau 1 größer als ein Vielfaches von φ(n), und x ist das gesuchte d. inverse_mod macht es mit (x + m) % m noch positiv. Hat e einen gemeinsamen Teiler mit φ(n), erhöht findMultiplicativeInverse den Wert von e so lange um 2, bis es passt.

4. Riesige Primzahlen finden: Miller-Rabin

Für echte Schlüssel braucht das Programm zwei Primzahlen mit je 512 Bit, also mit rund 155 Stellen. Ausprobieren, ob eine solche Zahl durch 2, 3, 5, … teilbar ist, würde bis zum Ende des Universums dauern. Der Test von Miller und Rabin geht einen anderen Weg. Für eine Primzahl n gilt a^(n−1) mod n = 1, egal welches a man nimmt. test(a, n) rechnet genau das aus und achtet zusätzlich auf verdächtige Wurzeln aus 1. Schlägt der Test an, ist n sicher keine Primzahl.

Eine zusammengesetzte Zahl übersteht einen Durchgang höchstens mit Wahrscheinlichkeit 1/4. MillerRabin wiederholt ihn mit 50 zufälligen Werten für a, und die Irrtumswahrscheinlichkeit sinkt unter 10⁻³⁰. randomPrime würfelt so lange ungerade Zahlen, bis eine den Test besteht. Im Schnitt ist das etwa jede 180. ungerade Zahl dieser Größe.

5. Text als Zahl

RSA verschlüsselt Zahlen, keine Buchstaben. strToNumber wandelt den Text deshalb zuerst mit UTF-8 in Bytes um. Diese Bytes liest es als Ziffern einer Zahl zur Basis 256, das erste Byte ist die Einerstelle, das zweite zählt 256-fach, und so weiter. numberToStr pflückt die Ziffern mit % 256 und // 256 wieder ab. Weil RSA modulo n rechnet, muss diese Zahl kleiner als n sein. Wie es sonst ausgeht, zeigt die Variante »Zu kleine Schlüssel«.

6. Große Zahlen sind in Python eingebaut

Für die Rechnungen braucht Python keine Zusatzbibliothek. Ganze Zahlen dürfen in Python beliebig groß sein, eine Zahl mit 309 Stellen ist ein ganz normales int. In Java bräuchte man dafür die Klasse BigInteger. Daran erinnert ein auskommentiertes Java-Fragment im Originalcode von rsa.py.

Nur zum Lernen

Dieses »Lehrbuch-RSA« zeigt das Prinzip, ist aber nicht für echte Geheimnisse gedacht: Es fehlt unter anderem ein Padding-Verfahren wie OAEP, das gleiche Nachrichten unterschiedlich aussehen lässt. Für echte Anwendungen nimmst du eine geprüfte Bibliothek.

Probier mal

Jede Variante ändert den Code oben. Ein Klick auf »Ausprobieren« übernimmt die Änderung in den Editor und startet das Programm. »Zurücksetzen« holt das Original zurück.

  1. 01Doppelt so lange Schlüssel

    Mit 1024 Bit pro Primzahl hat der Modul n über 600 Stellen. Das entspricht einem RSA-Schlüssel mit 2048 Bit, wie er heute üblich ist. Die Primzahlsuche dauert jetzt spürbar länger, denn jeder Test rechnet mit doppelt so langen Zahlen und braucht doppelt so viele Schritte.

    - bits = 512  # Länge
    + bits = 1024  # Länge
  2. 02Zu kleine Schlüssel

    Mit Primzahlen aus nur 24 Bit ist n kleiner als die Zahl, die für die Nachricht steht. RSA rechnet aber modulo n: Alles oberhalb von n geht verloren, und heraus kommt Zeichensalat. Die Nachricht muss kleiner als n sein. Deshalb zerlegt man lange Texte in Blöcke oder verschlüsselt mit RSA nur einen kurzen Schlüssel.

    - bits = 512  # Länge
    + bits = 24  # Länge
  3. 03Eine digitale Unterschrift

    RSA funktioniert auch rückwärts. Wer mit dem privaten Schlüssel d »verschlüsselt«, erzeugt eine Unterschrift. Mit dem öffentlichen Schlüssel e kann jeder prüfen, dass sie echt ist, aber niemand kann sie fälschen. Genau so werden Software-Updates und Zertifikate signiert.

    - print("   entschlüsselt:", plain)
    + print("   entschlüsselt:", plain)
    + 
    + signature = modpot(number, d, n)
    + print()
    + print("4) Unterschrift mit d:", short(signature))
    + print("   geprüft mit e:     ", numberToStr(modpot(signature, e, n)))
  4. 04Pythons eingebaute Abkürzungen

    Python kann das alles schon selbst. pow(x, y, n) rechnet schnelles Potenzieren modulo n, und seit Python 3.8 liefert pow(e, -1, phi) das modulare Inverse. Die Variante vergleicht beides mit den Funktionen aus dem Buch.

    - print("   entschlüsselt:", plain)
    + print("   entschlüsselt:", plain)
    + 
    + phi = (p - 1) * (q - 1)
    + print()
    + print("4) pow(number, e, n) == modpot(number, e, n):", pow(number, e, n) == cipher)
    + print("   pow(e, -1, phi) == d:", pow(e, -1, phi) == d)
  5. 05Deine eigene Nachricht

    Ersetze den Text in message. Umlaute und Emojis sind kein Problem, weil strToNumber den Text zuerst in UTF-8-Bytes umwandelt. Nur zu lang darf er nicht werden: Bei 512 Bit pro Primzahl passen gut 120 Bytes in eine Zahl unterhalb von n.

    - message = "Coding for Fun mit Python – geheime Grüße!"
    + message = "Treffen um 12 Uhr am Brunnen 🐍"

Vom Buch in den Browser

Auf der Buch-CD verteilt sich RSA auf drei Python-2-Dateien. RSA.py enthält die Grundbausteine (modpot, xggt, Miller-Rabin), rsa/rsa.py Schlüsselberechnung und Umwandlung von Text in Zahlen, und rsa/rsaTest.py verschlüsselt mit zwei fest eingetragenen Primzahlen. Hier ist alles in einem Programm zusammengefasst. Neu sind randomPrime, die Hilfsfunktion short für lange Zahlen und das Mini-Beispiel am Anfang. Die Lehrfunktionen multi und pot sowie die unfertige isQualityPrime sind weggefallen.

Die wichtigste Änderung: / wird zu //. In Python 2 teilt / zwei ganze Zahlen ganzzahlig, in Python 3 entsteht immer eine Kommazahl. Bei Zahlen mit Hunderten Stellen ist das fatal: Eine Kommazahl hat nur etwa 16 gültige Stellen, und oberhalb von 10³⁰⁸ gibt es einen OverflowError. Deshalb steht jetzt überall die Ganzzahldivision // bzw. //=: in modpot (y //= 2), in toBinary und in numberToStr.

Außerdem:

  • print ist eine Funktion, xrange heißt range.
  • Ein Fehler aus RSA.py ist behoben. Dort steht in test() die Prüfung if d != 1: return True innerhalb der Schleife statt danach. Dadurch meldet der Test schon nach dem ersten Schritt fast immer »zusammengesetzt«, auch für echte Primzahlen. In rsa/rsa.py ist die Zeile richtig eingerückt. Die Portierung übernimmt diese Fassung.
  • findMultiplicativeInverse darf e erhöhen, falls es einen gemeinsamen Teiler mit φ(n) hat. Das Original gab aber nur d zurück, das veränderte e ging verloren. Jetzt kommen beide zurück: e, d = findMultiplicativeInverse(p, q, e).
  • strToNumber und numberToStr arbeiteten in Python 2 mit ord() und chr() auf Byte-Strings. In Python 3 sind Strings Unicode, deshalb geht es jetzt über text.encode("utf-8") und ein bytearray. So klappen auch Umlaute und Emojis. errors="replace" sorgt dafür, dass eine missglückte Entschlüsselung Zeichensalat zeigt, statt abzubrechen.
  • Statt der fest eingetragenen Primzahlen und des Exponenten e = 1210475170735953725411 aus rsaTest.py erzeugt das Programm bei jedem Lauf neue Primzahlen und startet mit dem heute üblichen e = 65537.
Original aus dem Buch ansehen RSA.py · Python 2
#coding: latin1

'''
Created on 05.12.2009

@author: Lars Heppert
'''


def multi(x, y):
    '''Multiplizieren durch Addieren und Verdoppeln'''
    result = 0
    while y > 0:
        if y % 2 == 1:
            # bei ungerade Werten fuer die 2. Zahl wird
            # die das Zwischenergebnis der 1. Zahl summiert
            result += x
            # die Reduzierung um 1 macht die 2. Zahl wieder gerade
            # und verhindert einen Rest bei der Division durch 2,
            # wobei es hier nur darum geht in den else-Zweig zu wechseln
            y -= 1       
        else:
            x *= 2
            y /= 2
            
    return result

print multi(31, 74)

def pot(x,y):
    '''Potenzieren durch Quadrieren und Multiplizieren'''
    result = 1
    while y > 0:
        if y % 2 == 1:
            result *= x
            y -= 1
        else:
            y /= 2
            x *= x

    return result

print pot(2, 4)

def modpot(x,y,n):
    '''
    Schnelles Potenzieren x^y (mod n)
    nach der Methode "square and multiply".
    Zwischenergebnisse werden modulo n reduziert
    '''
    result = 1
    while y > 0:
        if y % 2 == 1:
            result *= x
            result %= n
            y -= 1
        else:
            x *= x
            x %= n
            y /= 2
        
    return result

def xggt(a,b):
    x1, x2, y1, y2 = 1, 0, 0, 1
    while b:
        q = a // b
        x1, x2, y1, y2 = x2, x1 - q * x2, y2, y1 - q * y2
        a, b = b , a % b
        
    return a, x1, y1

print "xggt = ", xggt(23, 120)

import math
def isprime(n):
    if n % 2 == 0 and not n == 2:
        return (False)
    else:
        limit = int(math.sqrt(n)) + 1
        
    for l in range(3, limit, 2):
        if n % l == 0:
            return (False)

    return (True)

print isprime(23), "ist eine Primzahl"

import sys
import random

def toBinary(n):
    """
    toBinary(n)
    wandelt n in eine Liste, welche die Binärdarstellung
    von n repräsentiert - diese Darstellung vereinfacht
    die folgenden Schritte bzgl. der Primzahlprüfung
    """
    r = []
    while (n > 0):
        r.append(n % 2)
        n = n / 2
        
    return r

def test(a, n):
    """
    test(a, n)
    überprüft, ob n (einfach) zusammengestezt ist,
    also als Produkt anderer Zahlen entsteht
    """
    b = toBinary(n - 1)
    d = 1
    for i in xrange(len(b) - 1, -1, -1):
        x = d
        d = (d * d) % n
        if d == 1 and x != 1 and x != n - 1:
            return True
        if b[i] == 1:
            d = (d * a) % n
        if d != 1:
            return True

    return False

def MillerRabin(n, s = 50):
    """
      MillerRabin(n, s = 1000)
      überprüft, ob n prim ist
    """
    for j in xrange(1, s + 1):
        a = random.randint(1, n - 1)
        if (test(a, n)):
            return False # n is complex
        
    return True # n is prime
Original aus dem Buch ansehen rsa/rsa.py · Python 2
'''
Created on 07.12.2009

@author: GWV7FD3
'''

def gcd(a, b):
    while b > 0:
        a, b = b, a % b
    
    return a
    
print gcd(48, 16)

def extgcd(a, b):
    u = t = 1
    v = s = 0
    while b > 0:
        q = a // b
        a, b = b, a - q * b
        u, s = s, u - q * s
        v, t = t, v - q * t
        
    return a, u, v

print extgcd(48, 16)

def toBinary(n):
    r = []
    while (n > 0):
        r.append(n % 2)
        n = n / 2

    return r

def test(a, n):
    b = toBinary(n - 1)
    d = 1
    for i in xrange(len(b) - 1, -1, -1):
        x = d
        d = (d * d) % n
        if d == 1 and x != 1 and x != n - 1:
            return True
        if b[i] == 1:
            d = (d * a) % n
    if d != 1:
        return True
    
    return False

import random
def MillerRabin(n, s = 50):
    for j in xrange(1, s + 1):
        a = random.randint(1, n - 1)
        if (test(a, n)):
            return False
    return True

#bigNumbers = []
#for x in range(1000):
#    bigNumbers.append(random.getrandbits(random.randint(4200, 4600)))
#
#x = 0
#for number in bigNumbers:
#    x += 1
#    isPrime = MillerRabin(number)
#    print x
#    if isPrime:
#        print number, "is prime"
        
    
def extended_gcd(a, b):
    x, last_x = 0, 1
    y, last_y = 1, 0
 
    while b:
        quotient = a // b
        a, b = b, a % b
        x, last_x = last_x - quotient*x, x
        y, last_y = last_y - quotient*y, y
 
    return (last_x, last_y, a)
 
def inverse_mod(a, m):
    x, q, gcd = extended_gcd(a, m)
 
    if gcd == 1:
        # x is the inverse, but we want to be sure a positive number is returned.
        return (x + m) % m
    else:
        # if gcd != 1 then a and m are not coprime and the inverse does not exist.
        return None

        
def findMultiplicativeInverse(p, q, e):
    phi = (p - 1) * (q - 1)
    while gcd(phi, e) > 1:
        e += 2
    
    d = inverse_mod(e, phi)
    
    return d

def modPow(a, b, n):
    z = 1
    while b != 0:
        while (b % 2) == 0:
            b = b / 2
            a = (a * a) % n

        b = b - 1
        z = (z * a) % n

    return z

#    private boolean isQualityPrime(BigInteger p) {
#        BigInteger two = new BigInteger("2");
#        
#        int            x    = p.bitLength();
#        BigInteger    b    = two.pow(x);
#        while (b.compareTo(p) < 0) {
#            x++;
#            b = two.pow(x);
#        }
#        BigInteger    s    = two.pow(--x);
#        
#        boolean isEasyBiggerPrime    = (b.subtract(BigInteger.ONE)).equals(p) ? true : false;
#        boolean isEasySmallerPrime    = (s.add(BigInteger.ONE).equals(p)) ? true : false;
#        
#        if (isEasyBiggerPrime || isEasySmallerPrime) {
#            System.out.println("WARNING: Prime is near to 2^x!");
#            System.out.println("p = " + p);
#        }
#        
#        return !(isEasyBiggerPrime || isEasySmallerPrime);
#    }

import math
def isQualityPrime(p):
    bitLength   = math.floor(math.log(p, 2))
    powNum      = 2**bitLength
    while powNum < p:
        bitLength  += 1
        powNum      = 2**bitLength
    
    
isQualityPrime(3000)

def strToNumber(text):
    x       = 1
    number  = 0
    for zeichen in text:
        number  += ord(zeichen)*x
        x       *= 256
        
    return number

def numberToStr(number):
    text = []
    while number > 0:
        zeichen = chr(number % 256)
        number  = number / 256
        text.append(zeichen)
    
    return "".join(text)
    
        
Original aus dem Buch ansehen rsa/rsaTest.py · Python 2
'''
Created on 09.12.2009

@author: GWV7FD3
'''
import rsa

q   = 864006630282221617546607165505132768833442927403087253437971070579738052430368997434168187774249241951614756886898778257056066247808371060434399495780120519992351353974141025134838110883240469955211816819125032764542995315946722704756735945014229730497747034468419619537240011450094095310929293646545904289036986543253037388962051682151266850800780321722541
p   = 203760457035785707274440765779841571954960905020216438093288697556051306412361010381948211478739481724728871392770550387381532382660420658266741318271699868487291176814463322229620222245833529237754749958472949097604722412462711929816226562448624147196460229785274621791738101798102616023157685119198323119793328819060209462062125952867409315980899161557
n   = p * q
phi = (p - 1) * (q - 1)
e   = 1210475170735953725411

d   = rsa.findMultiplicativeInverse(p, q, e)

print d

#plain   = 123456789
#cipher  = rsa.modPow(plain, e, n)
#
#print cipher
#
#back    = rsa.modPow(cipher, d, n)
#
#print back

text    =   "Dieser Text soll in eine Zahl umgewandelt werden"
number  =   rsa.strToNumber(text)

print number
print rsa.numberToStr(number)

cipher  =   rsa.modPow(number, e, n)
cipher  =   rsa.numberToStr(cipher)

print cipher

cipher  =   rsa.strToNumber(cipher)
cipher  =   rsa.modPow(cipher, d, n)
plain   =   rsa.numberToStr(cipher)

print plain