Rheinwerk Computing < openbook >

 
Inhaltsverzeichnis
1 Einleitung
2 Die Programmiersprache Python
Teil I Einstieg in Python
3 Erste Schritte im interaktiven Modus
4 Der Weg zum ersten Programm
5 Kontrollstrukturen
6 Dateien
7 Das Laufzeitmodell
8 Funktionen, Methoden und Attribute
9 Informationsquellen zu Python
Teil II Datentypen
10 Das Nichts – NoneType
11 Operatoren
12 Numerische Datentypen
13 Sequenzielle Datentypen
14 Zuordnungen
15 Mengen
16 Collections
17 Datum und Zeit
18 Aufzählungstypen – Enum
Teil III Fortgeschrittene Programmiertechniken
19 Funktionen
20 Modularisierung
21 Objektorientierung
22 Ausnahmebehandlung
23 Iteratoren
24 Kontextobjekte
25 Manipulation von Funktionen und Methoden
Teil IV Die Standardbibliothek
26 Mathematik
27 Kryptografie
28 Reguläre Ausdrücke
29 Schnittstelle zu Betriebssystem und Laufzeitumgebung
30 Kommandozeilenparameter
31 Dateisystem
32 Parallele Programmierung
33 Datenspeicherung
34 Netzwerkkommunikation
35 Debugging und Qualitätssicherung
36 Dokumentation
Teil V Weiterführende Themen
37 Anbindung an andere Programmiersprachen
38 Distribution von Python-Projekten
39 Grafische Benutzeroberflächen
40 Python als serverseitige Programmiersprache im WWW – ein Einstieg in Django
41 Wissenschaftliches Rechnen
42 Insiderwissen
43 Von Python 2 nach Python 3
A Anhang
Stichwortverzeichnis

Download:
- Beispielprogramme, ca. 464 KB

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Python 3 von Johannes Ernesti, Peter Kaiser
Das umfassende Handbuch
Buch: Python 3

Python 3
Pfeil 27 Kryptografie
Pfeil 27.1 Hash-Funktionen – hashlib
Pfeil 27.1.1 Verwendung des Moduls
Pfeil 27.1.2 Weitere Algorithmen
Pfeil 27.1.3 Vergleich großer Dateien
Pfeil 27.1.4 Passwörter
Pfeil 27.2 Verschlüsselung – PyCrypto
Pfeil 27.2.1 Symmetrische Verschlüsselungsverfahren
Pfeil 27.2.2 Asymmetrische Verschlüsselungsverfahren
 
Zum Seitenanfang

27.2    Verschlüsselung – PyCrypto Zur vorigen ÜberschriftZur nächsten Überschrift

Das Drittanbieterpaket PyCrypto[ 113 ](https://pypi.python.org/pypi/pycrypto) implementiert eine Reihe von kryptografischen Algorithmen zur symmetrischen und asymmetrischen Verschlüsselung. Im letzten Abschnitt werden die asymmetrischen Verfahren auch zum Signieren von Dokumenten eingesetzt.

 
Zum Seitenanfang

27.2.1    Symmetrische Verschlüsselungsverfahren Zur vorigen ÜberschriftZur nächsten Überschrift

Bei einem symmetrischen Verschlüsselungsverfahren wird ein Klartext mithilfe eines Schlüssels zu einem Chiffrat verschlüsselt. Derselbe Schlüssel kann danach verwendet werden, um das Chiffrat wieder zu einem Klartext zu entschlüsseln. Eine wichtige Bedeutung hat dabei der Raum der möglichen Schlüssel: Ist dieser groß genug und ist das Verschlüsselungsverfahren an sich sicher, steigt der Rechenaufwand zum Brechen der Verschlüsselung enorm.

Symmetrische Verschlüsselungsverfahren lassen sich in zwei Klassen unterteilen:

  • Stromchiffren verschlüsseln einen Datenstrom Bit für Bit.
  • Blockchiffren verschlüsseln einen Datenstrom in Blöcken einer bestimmten Blockgröße.

Stromchiffren

Stromchiffren nehmen eine bitweise Verschlüsselung eines kontinuierlich eingehenden Datenstroms vor. Im Gegensatz zu Blockchiffren muss keine Mindestmenge an Daten vorliegen, damit die Verschlüsselung funktioniert. Sie eignen sich daher besonders für die Echtzeitübertragung von Daten.

Eine Stromchiffre ist ein symmetrisches Verschlüsselungsverfahren und basiert daher auf einem Schlüssel. In der Regel wird der Datenstrom mit einem aus dem Schlüssel berechneten Schlüsselstrom bitweise verrechnet, beispielsweise über ein exklusives ODER (XOR).

Im Modul PyCrypto.Cipher sind zwei Typen von Stromchiffren implementiert: XOR und ARC4. Beide verfügen über die gleiche Schnittstelle und werden hier anhand von XOR exemplarisch vorgestellt:

>>> from Crypto.Cipher import XOR
>>> sender = XOR.new("Passwort")
>>> chiffrat = sender.encrypt("Das ist mein geheimer Text")
>>> chiffrat
b'\x14\x00\x00S\x1e\x1c\x06T=\x04\x1a\x1dW\x08\x17\x1c5\x08\x1e\x16\x05O&\x11(\x15'

Über die Methode new wird eine neue XOR-Chiffre mit dem angegebenen Schlüssel erzeugt. Diese lässt sich jetzt mithilfe der Methoden encrypt und decrypt zum Verschlüsseln bzw. Entschlüsseln von Daten verwenden. Die Gegenseite verfährt analog und entschlüsselt den Datenstrom mittels decrypt:

>>> empfaenger = XOR.new("Passwort")
>>> klartext = empfaenger.decrypt(chiffrat)
>>> klartext
b'Das ist mein geheimer Text'

Beachten Sie, dass eine Stromchiffre aufgrund des Schlüsselstroms einen internen Zustand hat. Ein weiterer Aufruf von XOR.encrypt auf den gleichen Eingabedaten würde daher ein unterschiedliches Chiffrat ergeben. Das bedeutet insbesondere, dass ein eingehender verschlüsselter Datenstrom von Beginn an entschlüsselt werden muss, damit die Schlüsselströme auf beiden Seiten synchron sind.

Es genügt, im obigen Beispiel die Klasse XOR durch ARC4 auszutauschen, um eine ARC4-Chiffre zu verwenden. Die Schlüsselgrößen sind bei beiden Verfahren variabel.

Blockchiffren

Im Gegensatz zu einer Stromchiffre verschlüsselt eine Blockchiffre einen Datenblock fester Größe. Auch das entstehende Chiffrat hat eine feste Größe. Um beliebig große Datenmengen zu verschlüsseln, gibt es verschiedene Verfahren, sogenannte kryptografische Betriebsmodi, die durch eine kombinierte Chiffrierung der einzelnen Datenblöcke eine sichere Gesamtchiffrierung erreichen. Zwei Beispiele für standardisierte Betriebsmodi sind:

  • Electronic Code Book (ECB); die Datenblöcke werden unabhängig voneinander verschlüsselt.[ 114 ](Vorsicht, dieser Betriebsmodus führt dazu, dass gleiche Klartextblöcke auch gleiche Chiffratblöcke ergeben, was ein für einen Angreifer interessanter Ansatzpunkt ist. )
  • Cipher Block Chaining (CBC); ein Datenblock wird vor der Verschlüsselung mit dem Chiffrat des vorangegangenen Datenblocks verrechnet.

Es existiert eine Reihe weiterer Betriebsmodi mit jeweils eigenen Besonderheiten, die wir an dieser Stelle nicht erschöpfend behandeln können.

Im Modul PyCrypto.Cipher sind die in Tabelle 27.2 aufgeführten Typen von Blockchiffren implementiert.

Name Schlüsselgröße Blockgröße
AES 16, 24 oder 32 Byte 16 Byte
ARC2 variabel 8 Byte
Blowfish variabel 8 Byte
CAST variabel 8 Byte
DES 8 Byte 8 Byte
DES3 16 Byte 8 Byte
IDEA 16 Byte 8 Byte
RC5 variabel 8 Byte

Tabelle 27.2    Blockchiffren im Paket PyCrypto

Die in PyCrypto.Cipher enthaltenen Blockchiffren können alle gleich verwendet werden, weswegen wir sie Ihnen exemplarisch am Beispiel von AES vorstellen:

>>> from Crypto.Cipher import AES
>>> chiffre = AES.new("PasswortPasswort", AES.MODE_ECB)
>>> chiffrat = chiffre.encrypt("Python - das umfassende Handbuch")
>>> chiffrat
b"\xd1'\x86\xe3\xd0\xd0\x94V<\xfe\x14Z\x16\x85*\xc6\x16}\xe0\xbd\x04g\xbe\xb5 \xbc\xf2;\xf2\xe0\xcd\nn"
>>> chiffre.decrypt(chiffrat)
b'Python - das umfassende Handbuch'

Ähnlich wie bei den Stromchiffren wird eine Blockchiffre über die Methode new erzeugt. Dabei wird ein Schlüssel angegeben, der in diesem Fall eine Länge von 16 Zeichen haben muss, sowie der gewünschte kryptografische Betriebsmodus, in diesem Fall ECB. Die anschließende Ver- bzw. Entschlüsselung über die Methoden encrypt bzw. decrypt unterscheidet sich nicht von den Stromchiffren.

Beachten Sie, dass eine Blockchiffre im Gegensatz zu einer Stromchiffre keinen internen Zustand hat. Jede Eingabe wird als eigenständiger Datenblock neu verschlüsselt. Daher führen zwei aufeinanderfolgende Aufrufe von encrypt mit den gleichen Eingabedaten auch zum gleichen Chiffrat.

Für die kryptografischen Betriebsmodi CBC und CFB muss beim Erzeugen der Chiffre ein zusätzliches Argument für den Initialisierungsvektor übergeben werden. Diese Betriebsmodi beziehen bei der Verschlüsselung eines Datenblocks den vorangegangenen Datenblock mit ein und benötigen daher einen Initialisierungsvektor zur Verschlüsselung des ersten Datenblocks. Dabei handelt es sich um einen String von Blockgröße:

chiffre = AES.new("PasswortPasswort", AES.MODE_CBC, "ABCDEFGHabcdefgh")
 
Zum Seitenanfang

27.2.2    Asymmetrische Verschlüsselungsverfahren Zur vorigen ÜberschriftZur nächsten Überschrift

Ein asymmetrisches Verschlüsselungsverfahren, auch Public-Key-Verschlüsselungsverfahren, umgeht die größte Schwachstelle symmetrischer Verfahren: den Schlüsselaustausch. Bei verschlüsselter Kommunikation müssen beide Kommunikationspartner den gleichen Schlüssel besitzen. Sollte ein Angreifer den Schlüssel beim Schlüsselaustausch[ 115 ](Auch dafür gibt es kryptografische Verfahren, beispielsweise das Diffie-Hellman-Protokoll. ) in Erfahrung bringen können, ist das Entschlüsseln der nachfolgenden Kommunikation sehr einfach.

Bei den erst in den 1970er-Jahren entwickelten asymmetrischen Verschlüsselungsverfahren gibt es keinen gemeinsamen geheimen Schlüssel, sondern jeder Kommunikationsteilnehmer besitzt einen privaten Schlüssel, der geheim gehalten wird, und einen dazu passenden öffentlichen Schlüssel, der allen Kommunikationspartnern – und damit auch allen potenziellen Angreifern – bekannt ist. Der Sender verschlüsselt seine Nachricht mit dem öffentlichen Schlüssel des Empfängers in einer Weise, dass sie nur mithilfe des privaten Schlüssels wieder entschlüsselt werden kann. Wichtig ist dabei, dass sich der private Schlüssel nicht aus dem öffentlichen Schlüssel berechnen lässt.

Ein Beispiel für ein asymmetrisches Verschlüsselungsverfahren ist das 1977 entwickelte RSA-Verfahren (für Rivest, Shamir und Adleman). Vereinfacht gesagt basiert RSA auf der Annahme, dass die Zerlegung einer sehr großen Zahl in ihre Primfaktoren eine kaum zu berechnende Operation ist, wobei die Betonung hier auf sehr groß liegt. Die umgekehrte Operation, nämlich das Erzeugen dieser sehr großen Zahl aus ihren Primfaktoren, ist hingegen simpel. Jeder Kommunikationsteilnehmer erzeugt sich zwei Primzahlen und hält diese geheim. Das Produkt dieser Zahlen ist der öffentliche Schlüssel und wird zusammen mit einer weiteren benötigten Zusatzinformation veröffentlicht. Der öffentliche Schlüssel reicht aus, um eine Nachricht zu verschlüsseln, wer sie aber wieder entschlüsseln möchte, benötigt die Primfaktorzerlegung des öffentlichen Schlüssels.

Obwohl die Sicherheit von RSA bis heute nicht bewiesen ist, erfreut sich das Verfahren großer Beliebtheit und wird in modifizierter Form vielfach eingesetzt.

Asymmetrische Verschlüsselungsverfahren können häufig nicht nur zum Verschlüsseln, sondern auch zum Signieren von Nachrichten angewandt werden. Die in PyCrypto.PublicKey enthaltenen asymmetrischen Verfahren werden in Tabelle 27.3 vorgestellt. Daran anschließend werden beide Anwendungsfälle anhand von RSA vorgestellt.

Name Verschlüsseln Signieren
RSA ja ja
ElGamal ja ja
DSA nein ja
qNEW nein ja

Tabelle 27.3    Asymmetrische Verschlüsselungsverfahren in PyCrypto

Einen Schlüssel erzeugen

Bevor ein asymmetrisches Verfahren verwendet werden kann, muss ein Schlüsselpaar erzeugt werden. Das geschieht über die Methode generate des eingebundenen Verfahrens:

>>> from Crypto.PublicKey import RSA
>>> key = RSA.generate(1024)

Das erzeugte Schlüsselobjekt key enthält zunächst sowohl den öffentlichen als auch den privaten Schlüssel. Dieser Umstand ist über die Methode has_private erkennbar. Die Methode publickey erzeugt ein Schlüsselobjekt, das nur den öffentlichen Schlüssel enthält:

>>> key.has_private()
True
>>> public_key = key.publickey()
>>> public_key.has_private()
False

Die Methode exportKey erlaubt es, die Schlüssel in Form eines Strings zu exportieren. Über die Methode RSA.importKey kann ein exportierter Schlüssel wieder geladen werden:

>>> key_txt = key.exportKey()
>>> key_txt
b'-----BEGIN RSA PRIVATE KEY----- […] -----END RSA PRIVATE KEY-----'
>>> key = RSA.importKey(key_txt)

Beim Exportieren des Schlüsselpaars key werden sowohl der öffentliche als auch der private Schlüssel exportiert. Wird nur der öffentliche Schlüssel public_key exportiert, ist der private Schlüssel nicht enthalten. Die exportierten Daten können also veröffentlicht werden:

>>> public_key_txt = public_key.exportKey()
>>> public_key_txt
b'-----BEGIN PUBLIC KEY----- […] -----END PUBLIC KEY-----'
>>> public_key = RSA.importKey(public_key_txt)

Verschlüsseln

Die Schlüsselobjekte key und public_key besitzen die Methoden encrypt und decrypt. Es ist aber nicht ratsam, diese direkt zu verwenden, da sie das unmodifizierte RSA-Verfahren durchführen, das sogenannte Textbook-RSA. Diese Variante wird allgemein als unsicher angesehen und sollte nicht verwendet werden. Stattdessen gibt es sichere Varianten von RSA, die auch in PyCrypto implementiert sind, darunter PKCS1_OAEP für die Verschlüsselung und PKCS1_v1_5 für das Signieren.[ 116 ](Diese kryptischen Namen stehen für die standardisierten Protokolle PKCS#1 OAEP bzw. PKCS#1 v1.5. )

Im folgenden Beispiel wird eine sichere RSA-Verschlüsselung mit den im vorangegangenen Abschnitt erzeugten Schlüsseln durchgeführt:

>>> from Crypto.Cipher import PKCS1_OAEP
>>> chiffre = PKCS1_OAEP.new(public_key)
>>> chiffrat = chiffre.encrypt(b"Dies ist der geheime Text")

Der Empfänger kann das Chiffrat mithilfe seines privaten Schlüssels entschlüsseln:

>>> chiffre = PKCS1_OAEP.new(key)
>>> chiffre.decrypt(chiffrat)
b'Dies ist der geheime Text'

Signieren

Viele asymmetrische Verschlüsselungsverfahren lassen sich zum Signieren von Dokumenten einsetzen. Dabei geht es darum zu beweisen, dass ein Dokument in der Form vorliegt, wie es vom Urheber erstellt wurde.

Im Falle einer RSA-basierten Signatur wird eine Entschlüsselungsoperation mit dem privaten Schlüssel des Autors auf einem Hash-Wert des Dokuments durchgeführt. Der resultierende Wert wird als Signatur gemeinsam mit dem Dokument versendet. Jeder Empfänger des Dokuments kann die Signatur mit dem öffentlichen Schlüssel des Autors »verschlüsseln« und erhält dann den ursprünglichen Hash-Wert des Dokuments. Damit kann er prüfen, ob die vorliegende Version des Dokuments mit der ursprünglichen Version übereinstimmt.

Im folgenden Beispiel wird ein Dokument mithilfe der im Vorhinein erzeugten Schlüssel signiert und verifiziert. Dabei bedienen wir uns der angesprochenen RSA-Variante PKCS1_v1_5.

>>> from Crypto.Signature import PKCS1_v1_5
>>> from Crypto.Hash import SHA
>>> nachricht = b"Dies ist mein Dokument"
>>> hash = SHA.new(nachricht)
>>> signatur = PKCS1_v1_5.new(key).sign(hash)

Die erzeugte Signatur kann jetzt mithilfe des öffentlichen Schlüssels – und mit dem Hash-Wert des Dokuments, den auch der Empfänger erzeugen kann – verifiziert werden:

>>> PKCS1_v1_5.new(public_key).verify(hash, signatur)
True

Im folgenden Beispiel wurde die Signatur verändert, was die Verifikation fehlschlagen lässt:

>>> PKCS1_v1_5.new(public_key).verify(hash, signatur[:-1])
0

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Python 3 Python 3
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Einstieg in Python
Einstieg in Python


Zum Rheinwerk-Shop: Python. Der Grundkurs
Python. Der Grundkurs


Zum Rheinwerk-Shop: Algorithmen mit Python
Algorithmen mit Python


Zum Rheinwerk-Shop: Objektorientierte Programmierung
Objektorientierte Programmierung


Zum Rheinwerk-Shop: Raspberry Pi. Das umfassende Handbuch
Raspberry Pi. Das umfassende Handbuch


Zum Rheinwerk-Shop: Roboter-Autos mit dem Raspberry Pi
Roboter-Autos mit dem Raspberry Pi


Zum Rheinwerk-Shop: Neuronale Netze programmieren mit Python
Neuronale Netze programmieren mit Python


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2020
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern