Python Tutorial Teil 4 – Kryptographie

Teil 4: Kryptographie dieses kompakten Python-Tutorials gibt eine Übersicht über die wichtigsten Pakete für Kryptographie. Zunächst wird die Python-Bibliothek PyCryptodome vorgestellt, mit Beispielen für drei verschiedenen Betriebsmodi der AES-Verschlüsselung, und einem Beispiel, wie RSA und AES zusammen für die sichere Datenübertragung eingesetzt werden. Anschließend werden verschiedene Pakete für Hashing und Message Authentication Codes am Beispiel vorgestellt: hashlib und hmac für einfaches Hashing, sowie bcrypt für Passwort-Hashing.

  Motivation

Python-Anwendungen, die eine verteilte Architektur haben (z.B. Webanwendungen) müssen die Sicherheit der Daten (Vertraulichkeit, Integrität und Authentizität) durch passende kryptographische Verfahren absichern: Verschlüsselung, Hashing und digitale Signaturen.

Python verfügt über eine Reihe von Bibliotheken für Kryptographie, mit deren Hilfe man gängige Verschlüsselungs- und Hashing-Verfahren testen und in eigene Anwendungen einbinden kann. Zu den aktuell viel verwendeten Paketen zählen PyCrypto, hashlib, hmac, bcrypt und secrets.

In diesem Tutorial wird zunächst die Funktionsweise der AES-Verschlüsselung genauer beschrieben. In Abschnitt 2 wird ein Lern-Szenario durchgespielt: die Verschlüsselung einer Nachricht, die danach über einen unsicheren Übertragungsweg gesendet werden kann, mittels der Verschlüsselungsverfahren RSA und AES. Voraussetzung ist, dass beide Kommunikationspartner vor der Übertragung ein RSA-Schlüsselpaar erstellt und den öffentlichen Teil ihrer Schlüssel verfügbar gemacht haben. Zuletzt werden unterschiedliche Formen des Hashings vorgestellt.


PyCryptodome - Übersicht und Installation

Das Python-Paket PyCrypto bzw. die neuere Version PyCryptoDome implementiert eine Reihe kryptografischer Verfahren, die in eigenen Python-Programmen für Verschlüsselung und digitale Signaturen eingesetzt werden können:

Zunächst wird im Terminal der Entwicklungsumgebung PyCryptodome installiert. Dabei ist zu beachten, das PyCryptodome in zwei Varianten installiert werden kann, entweder mit pip install pycryptodome oder mit pip install pycryptodomex und man entweder die eine oder andere installieren sollte, jedoch nicht beide.

1 Symmetrische Verschlüsselung: AES

AES (Advanced Encryption Standard) ist eine standardisierte symmetrische Blockchiffre mit einer festen Datenblockgröße von 16 Byte bzw. 128 Bit. Die Schlüssel können 128, 192 oder 256 Bit lang sein und müssen vor der Datenübertragung sicher ausgetauscht werden.

Das generelle Vorgehen bei der AES-Verschlüsselung ist wie folgt:
Die Nachricht wird in mehrere Blöcke aufgeteilt und durch Padding auf eine passende Länge gebracht. Ein Initialisierungsvektor (IV) kann das Verfahren randomisieren, dadurch wird es sicherer. Die AES-Verschlüsselung kann zusätzlich mit einem Message Authentication Code abgesichert werden, der Integrität und Authentizität der Daten sicherstellt.

AES verfügt über mehrere Betriebsmodi, die beschreiben, wie genau die Nachrichten verschlüsselt werden. Häufig eingesetzte Betriebsmodi für AES sind ECB, CBC und EAX, OCB. Einige Betriebsmodi, wie EAX und OCB, verschlüsseln nicht nur, sondern authentifizieren die Nachricht auch.

Im ECB (Electronic Code Book) Modus wird jeder Block unabhängig von dem anderen verschlüsselt. Das bedeutet: Ein Fehler in einem Block beeinflusst nur die Entschlüsselung dieses Blocks. Es bedeutet auch: Gleiche Nachrichtenblöcke werden auch gleich verschlüsselt, und das ist nicht besonders sicher.

Im CBC (Cipher Block Chaining) Modus wird ein Nachrichtenblock vor dem Verschlüsseln mit dem vorhergehenden Block verknüpft. Für den ersten Block wird ein Initialisierungsvektor verwendet. Da die Verschlüsselung nun vom Initialisierungsvektor (IV) abhängt, werden zwei gleiche Nachrichten mit unterschiedlichen IVs auch unterschiedlich verschlüsselt.

Im EAX (Encrypt-Authenticate-Translate) Modus wird die Nachricht gleichzeitig verschlüsselt und authentifiziert. Die Authentifizierung geschieht mittels eines Message Authentication Codes, der dem Empfänger zusammen mit der verschlüsselten Nachricht zur Verfügung gestellt wird. Weiterhin verwendet EAX einen Einmalcode "Nonce", der an die Nachricht angefügt wird, um die Verschlüsselung zu randomisieren. Anders als ECB und CBC erfordet EAX keine spezielle Blockgrößen.

1-1 AES mit ECB-Modus

ECB (Electronic Code Book)ist ein Betriebsmodus der AES-Blockchiffe, bei dem jeder Klartextblock unabhängig von den anderen verschlüsselt wird. Alle Blöcke müssen dieselbe Größe haben (16 Byte). Ein Klartext, dessen Länge kein Vielfaches von 16 Byte ist, wird durch Padding aufgefüllt. Beim Entschlüsseln muss das Padding wieder rückgängig gemacht werden. ECB ist nicht besonders sicher, da derselbe Klartext bei wiederholter Verschlüsselung stets mit demselben Chiffretext codiert wird; es fehlt ein Zufallsfaktor, der die Verschlüsselung randomisiert.

In diesem Beispiel wird der Klartext "Test1: AES mit EBC-Modus" mit Hilfe der AES-Verschlüsselung im ECB-Betriebsmodus verschlüsselt und entschlüsselt. Es wird ein 16 Byte langer fester Schlüssel gewählt, der zwischen Sender und Empfänger auf eine sichere Weise ausgetauscht werden muss.

AES-ECB: Nachricht verschlüsseln

Der AES-Schlüssel kann 16 Bytes bzw. 128 Bit oder 32 Bytes bzw. 256 Bit lang sein. Hier wählen wir einen Schlüssel, der genau 16 Zeichen enthält und damit 16 Byte lang ist. Alternativ kann mit key = get_random_bytes(16) ein zufälliger Schlüssel erzeugt werden.


Python-Code: AES-Verschlüsselung im ECB-Modus
  Verwendete Klassen: AES
  Verwendete Methoden: encrypt(), pad()
from Crypto.Cipher import AES 
from Crypto.Util.Padding import pad
from base64 import b64encode 
# (1) Klartext und Schlüssel festlegen
klartext = b"Test1: AES mit ECB-Modus"
klartext_padded = pad(klartext, AES.block_size)
key = b'my.topsecret.key' # 16 bytes lang
# (2) Verschlüsseln
chiffre = AES.new(key, AES.MODE_ECB) 
chiffretext_bytes = chiffre.encrypt(klartext_padded)
# (3) Ausgabe
print("Klartext mit Padding:\n", klartext_padded)
print("Schlüssel",  b64encode(key))
print("Verschlüsselte Nachricht:\n", 
      b64encode(chiffretext_bytes).decode('utf-8'))
Ausgabe
Klartext mit Padding:
 b'Test1: AES mit ECB-Modus\x08\x08\x08\x08\x08\x08\x08\x08'
Schlüssel b'bXkudG9wc2VjcmV0LmtleQ=='
Verschlüsselte Nachricht:
 eywU0QAOmRivUFjtrlYhVQdCiy8r+jvZ/OOSWdlc6FM=

Erläuterung
Beim AES-Padding werden Algorithmen wie PKCS#5 und PKCS#7 eingesetzt. Das Auffüllen eines Blocks erfolgt in ganzen Bytes. Der Wert jedes hinzugefügten Bytes ist die Anzahl der hinzugefügten Bytes. Unser Klartextbesteht z.B. aus 24 Bytes, zum aufgefüllten Text mit 32 Bytes fehlen noch 8 Bytes, daher wird mit "8" aufgefüllt.
Die Funktionen b64encode und decode werden verwendet, um Bytes in Strings umzuwandeln. Konkret wird der Ausdruck b64encode(chiffretext_bytes).decode('utf-8')) die Bytes des Chiffretextes als ASCII-String in utf-8 Codierung zurückliefern.

Fragen
Q. Was wird ausgegeben, wenn Sie den angegebenen Schlüssel ändern: key = b'my.topsecret'?
A. Es wird eine Fehlermeldung ausgegeben, da der Schlüssel so nicht mehr eine zulässige Länge hat.
Q. Was passiert, wenn Sie die AES+ECB Verschlüsselung (Zeilen 10-15) mehrfach nacheinander ausführen?
A. Wird die Verschlüsselung des Klartextes mit AES+ECB mehrfach ausgeführt, ist der Chiffretext jedesmal derselbe!

AES-ECB: Nachricht entschlüsseln

Für die Entschlüsselung benötigt der Empfänger lediglich den AES-Schlüssel key und die verschlüsselte Nachricht. Annahme: der Schlüssel key wurde vor dem Senden der Nachricht sicher ausgetauscht.


Python-Code: AES-Verschlüsselung im ECB-Modus
  Verwendete Klassen: AES
  Verwendete Methoden: decrypt(), unpad()
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
try:
    # (1) Nachricht entschlüsseln
    chiffre = AES.new(key, AES.MODE_ECB)
    plaintext_padded = chiffre.decrypt(chiffretext_bytes)
    # (2)  Padding rückgängig machen
    plaintext = unpad(plaintext_padded, AES.block_size)
    print("Entschlüsselter Chiffretext: ", plaintext)
except Exception as e:
     print(Exception, e)

Ausgabe

Entschlüsselter Chiffretext:  b'Test1: AES mit ECB-Modus'

1-2 AES mit CBC-Modus

CBC (Cipher Block Chaining) ist ein Betriebsmodus, bei dem jeder Klartextblock vor der Verschlüsselung mit dem vorherigen Chiffretextblock per XOR verknüpft wird. Für den ersten Block wird ein Initialisierungsvektor verwendet, der dieselbe Länge hat wie die AES-Blöcke.

In diesem Beispiel wird der Klartext "Test2: AES mit CBC-Modus" mit Hilfe der AES-Verschlüsselung im CBC-Betriebsmodus verschlüsselt und entschlüsselt. Es wird ein 16 Byte langer fester Schlüssel gewählt, der zwischen Sender und Empfänger auf eine sichere Weise ausgetauscht werden muss.

AES-CBC: Nachricht verschlüsseln

Der Sender legt einen Klartext als Nachricht fest und füllt den Klartext durch Padding auf. Danach wird auch ein Schlüssel (hier: 16 Byte lang) festgelegt, und der Klartext klartext_padded wird mit diesem Schlüssel verschlüsselt. Zuletzt erstellt der Sender eine Datei message.bin, in die alle Informationen geschrieben werden, die der Empfänger zum Entschlüsseln benötigt, nämlich den Initialisierungsvektor iv und die verschlüsselte Nachricht chiffretext_bytes.


Python-Code: AES-Verschlüsselung im CBC-Modus
  Verwendete Klassen: AES
  Verwendete Methoden: encrypt(), pad()
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from base64 import b64encode
# (1) Klartext und Schlüssel festlegen
klartext = b"Test2: AES mit CBC-Modus" # in Bytes
klartext_padded = pad(klartext, AES.block_size) # mit Padding
key = b'my.topsecret.key' # 16 bytes lang
# (2) Verschlüsseln
chiffre = AES.new(key, AES.MODE_CBC)
chiffretext_bytes = chiffre.encrypt(klartext_padded)
# (3) Chiffre-Datei message.bin für Datenübertragung erstellen
file_writer = open("message.bin", "wb")
[ file_writer.write(x) for x in (chiffre.iv, chiffretext_bytes) ]
file_writer.close()
# (4) Ausgabe
print("Klartext", klartext)
print("Klartext mit Padding", klartext_padded )
print("Initialisierungsvektor hat Länge:", len(chiffre.iv))
print("Chiffretext: ",  b64encode(chiffretext_bytes).decode('utf-8'))

Ausgabe

Klartext b'Test2: AES mit CBC-Modus'
Klartext mit Padding b'Test2: AES mit CBC-Modus\x08\x08\x08\x08\x08\x08\x08\x08'
Initialisierungsvektor hat Länge: 16
Chiffretext als String:  GGyld93nO0qIqsj53bw/Cuv9LibiWED+CTT0YJCwMa0=
Fragen
Q. Was passiert, wenn Sie die AES+CBC-Verschlüsselung (Zeilen 10-19) mehrfach nacheinander ausführen?
A. Wird die Verschlüsselung des Klartextes mit AES+CBC mehrfach ausgeführt, ist der Chiffretext jedesmal ein anderer!

AES-CBC: Nachricht entschlüsseln

Der Empfänger liest die Chiffre-Datei message.bin aus, die alle Informationen enthält, die für das Entschlüsseln benötigt werden: Initialisierungsvektor iv und Chiffretext (in Bytes). Er erstellt eine neue Instanz der AES-Verschlüsselung, mit Angabe des Betriebsmodus und des Initialisierungsvektors, und entschlüsselt damit den Chiffretext. Die Funktion decrypt liefert einen Klartext zurück, bei dem noch das Padding rückgängig gemacht werden muss, und der mit dem Ausgangstext übereinstimmen sollte.


Python-Code: AES-Entschlüsselung im CBC-Modus
  Verwendete Klassen: AES
  Verwendete Methoden: decrypt(), unpad()
from Crypto.Cipher import AES
key = b'my.topsecret.key' # Schlüssel, wurde zuvor sicher ausgetauscht
try:
    # (1) Lese die Chiffre-Datei aus: IV und Chiffretext
    file_in = open("message.bin", "rb")
    iv, chiffretext_bytes = [ file_in.read(x) for x in (16, -1) ]
    file_in.close()
    # (2) Entschlüssele chiffretext mit AES 
    chiffre = AES.new(key, AES.MODE_CBC, iv)
    plaintext_padded = chiffre.decrypt(chiffretext_bytes)
    # (3) Padding wird rückgängig gemacht
    plaintext = unpad(plaintext_padded, AES.block_size)
    print("Entschlüsselter Chiffretext: ", plaintext)
except Exception as e:
    print("Fehler bei der Entschlüsselung!", e)

1-3 AES mit EAX-Modus

Der Betriebsmodus EAX (Encrypt-Authenticate-Translate) hat die Besonderheit, dass er gleichzeitig verschlüsselt und authentifiziert, und wird in der Python-Bibliothek PyCryptodome durch die Funktion encrypt_and_digest umgesetzt. Beim Verschlüsseln werden ein Einmal-Code nonce und ein Message Authentication Tag mac erzeugt, diese werden zusammen mit der verschlüsselten Nachricht in eine Datei message.bin geschrieben, die dem Empfänger gesendet wird. Der Empfänger liest aus der empfangenen Datei message.bin die Einmalcodes MAC und Nonce sowie den verschlüsselten Text chiffretext und hat damit alle Informationen, die für Entschlüsselung die Überprüfung der Authentizität benötigt werdens.

In diesem Beispiel wird der Klartext "Hallo zusammen!" mit Hilfe der AES-Verschlüsselung im EAX-Betriebsmodus verschlüsselt und entschlüsselt. Es wird ein 16 Byte langer fester Schlüssel gewählt, der zwischen Sender und Empfänger auf eine sichere Weise ausgetauscht werden muss.

AES-EAX: Nachricht verschlüsseln

Der Sender legt einen Klartext als Nachricht fest. Danach wird auch ein AES-Schlüssel (hier: 16 Byte lang) festgelegt, und der Klartext klartext wird mit diesem Schlüssel verschlüsselt. Zuletzt erstellt der Sender eine Datei message.bin, in die alle Informationen geschrieben werden, die der Empfänger zum Entschlüsseln benötigt, nämlich den MAC-Code mac, den Einmalcode nonce und die verschlüsselte Nachricht chiffretext. Die Verschlüsselung passiert auf dem Rechner des Senders.


Python-Code: AES-Verschlüsselung im EAX-Modus
  Verwendete Klassen: AES
  Verwendete Methoden: encrypt_and_digest()
from Crypto.Cipher import AES
# (1) Klartext und Schlüssel
klartext = 'Hallo zusammen!'.encode()
key = b'my.topsecret.key' # Schlüssel, 16 Bytes lang
print("Schlüssel",  key, " hat Länge:", len(key))
try:
      # (2) Verschlüsseln
      chiffre = AES.new(key, AES.MODE_EAX)
      chiffretext, mac = chiffre.encrypt_and_digest(klartext)
      print("Verschlüsselte Nachricht: ", chiffretext, "\nMAC-Tag: ", mac)
      # (3) Chiffre-Datei message.bin für Datenübertragung erstellen
      file_writer = open("message.bin", "wb")
      [ file_writer.write(x) for x in (mac, chiffre.nonce, chiffretext) ]
      file_writer.close()
except Exception as e:
     print("Verschlüsselungs-Fehler: ", e)

Erläuterung des Codes

Fragen
Q. Was passiert, wenn Sie die AES+EAX-Verschlüsselung (Zeilen 9-16) mehrfach nacheinander ausführen?
A. Wird die Verschlüsselung des Klartextes mit AES+EAX mehrfach ausgeführt, ist der Chiffretext jedesmal ein anderer!

AES-EAX: Nachricht entschlüsseln

Die Entschlüsselung passiert auf dem Rechner des Empfängers.


Python-Code: AES-Entschlüsselung im EAX-Modus
  Verwendete Klassen: AES
  Verwendete Methoden: decrypt_and_verify()
from Crypto.Cipher import AES
from base64 import b64decode
key = b'my.topsecret.key' # Schlüssel, wurde zuvor sicher ausgetauscht
print("Schlüssel",  key)
try:
    # (1) Lese die Chiffre-Datei aus: MAC, Nonce, Chiffretext
    file_in = open("message.bin", "rb")
    mac, nonce, chiffretext = [ file_in.read(x) for x in (16, 16, -1) ]
    file_in.close()
    # (2) Entschlüssele chiffretext mit AES und überprüfe Authentizität 
    chiffre = AES.new(key, AES.MODE_EAX, nonce=nonce)
    klartext = chiffre.decrypt_and_verify(chiffretext, mac) 
    print("Die Nachricht ist authentisch!\n", klartext)
except Exception as e:
    print("Nachricht wurde verfälscht!", e)

2 RSA-Verschlüsselung

Das RSA-Verfahren ist ein asymmetrisches Kryptosystem, das für Verschlüsselung kurzer Nachrichten (z.B. Passwörter) und digitale Signaturen verwendet wird.
Verschlüsselung: Die Nachricht wird mit dem öffentlichen Schlüssel des Empfängers verschlüsselt. Der Empfänger entschlüsselt sie mit seinem privaten Schlüssel.
Digitale Signatur: Der Sender erzeugt eine digitale Signatur mit Hilfe seines privaten Schlüssels. Der Empfänger verifiziert diese mit dem öffentlichen Schlüssel des Empfängers. Hier wird RSA verwendet, um den Sitzungsschlüssel für AES zu verschlüsseln. Die eigentliche Nachricht wird mit einem symmetrischen Verfahren verschlüsselt, z.B. mit AES.

Ablauf der verschlüsselten Datenübertragung

Der Ablauf der verschlüsselten Datenübertragung zwischen zwei Kommunikationspartnern e und s ist wie folgt.

Schritt 1: Schlüsselpaar generieren

Hier wird ein Schlüsselpaar für den **Empfänger e** generiert und in zwei Dateien e_private.pem und e_public.pem gespeichert. Dieser Code sollte von jedem Kommunikationspartner nur einmal ausgeführt werden.

from Crypto.PublicKey import RSA

key = RSA.generate(2048)
private_key = key.export_key()
file_out = open("e_private.pem", "wb")
file_out.write(private_key)
file_out.close()

public_key = key.publickey().export_key()
file_out = open("e_public.pem", "wb")
file_out.write(public_key)
file_out.close()

Schritt 2: Nachricht verschlüsseln

Der Sender s legt einen Klartext als Nachricht fest, erzeugt einen AES-Sitzungsschlüssel und verschlüsselt den Klartext mittels AES. Danach holt der Sender den öffentlichen RSA-Schlüssel des Empfängers e aus der öffentlichen Ablage und verschlüsselt damit den AES-Sitzungsschlüssel. Zuletzt erstellt der Sender eine Datei chiffretext_e.bin, in die alle Informationen geschrieben werden, die der Empfänger zum Entschlüsseln benötigt: die verschlüsselte Nachricht, der verschlüsselte AES-Sitzungsschlüssel, der Einmalcode nonce und der Message Authentication Code mac.

from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
from Crypto.Cipher import AES, PKCS1_OAEP
# (1) Klartext, als UTF-8 codiert
klartext = "Hallo zusammen!"
klartext = klartext.encode("utf-8")
# (2) Klartext mit AES im EAX-Modus verschlüsseln 
session_key = get_random_bytes(16)
chiffre_aes = AES.new(session_key, AES.MODE_EAX)
chiffretext, mac = chiffre_aes.encrypt_and_digest(klartext)
# (3) AES-Sitzungsschlüssel verschlüsseln
empfaenger_key = RSA.import_key(open("e_public.pem").read())
chiffre_rsa = PKCS1_OAEP.new(empfaenger_key)
enc_session_key = chiffre_rsa.encrypt(session_key)
# (4) Chiffre-Datei chiffretext_e.bin für Datenübertragung erstellen
file_writer = open("chiffretext_s_e.bin", "wb")
[ file_writer.write(x) 
 for x in (enc_session_key, chiffre_aes.nonce, mac, chiffretext) ]
file_writer.close()
print("Klartext: ", klartext )
print("Chiffretext: ", chiffretext)
Ausgabe
Klartext:  b'Hallo zusammen!'
Chiffretext:  b'\xd8":\xf1M\x93\xd5\xde\x9e\xf6kBKU\x14'

Erläuterung des Codes

Schritt 3: Nachricht entschlüsseln

Der Empfänger liest die Chiffre-Datei chiffretext_s_e.bin aus, die alle Informationen enthält, die für das Entschlüsseln benötigt werden: verschlüsselten Sitzungsschlüsselm enc_session_key, Einmalcode chiffre_aes.nonce, Message Authentication Code mac und verschlüsselte Nachricht chiffretext. Er entschlüsselt den AES-Sitzungsschlüssel mit Hilfe seines eigenen privaten RSA-Schlüssels private_key. und entschlüsselt die verschlüsselte Nachricht mit dem nunmehr verfügbaren AES-Sitzungsschlüssel session_key.

from Crypto.PublicKey import RSA
from Crypto.Cipher import AES, PKCS1_OAEP

# (1) Chiffredatei auslesen
# 
private_key = RSA.import_key(open("e_private.pem").read())
file_in = open("chiffretext_s_e.bin", "rb")
enc_session_key, nonce, mac, chiffretext = \
   [ file_in.read(x) for x in (private_key.size_in_bytes(), 16, 16, -1) ]

# (2) AES-Sitzungsschlüssel entschlüsseln
chiffre_rsa = PKCS1_OAEP.new(private_key)
session_key = chiffre_rsa.decrypt(enc_session_key)

# (3) Chiffretext mit AES entschlüsseln
chiffre_aes = AES.new(session_key, AES.MODE_EAX, nonce)
data = chiffre_aes.decrypt_and_verify(chiffretext, mac)
print("Entschlüsselter Chiffretext: ", data.decode("utf-8"))
print("Klartext == Entschlüsselter Chiffretext?:", klartext == data)

3 Hashing in Python

Die Verschlüsselung von Nachrichten sichert deren Vertraulichkeit, d.h. nur der berechtigte Sender und Empfänger können die Nachricht lesen. Für die Sicherung der Integrität einer Nachricht (d.h. der Inhalt wurde nicht verfäscht) und der Authentizität des Senders (d.h. der Sender ist derjenige, für den er sich ausgibt) werden weitere kryptographische Verfahren eingesetzt: Hashing und digitale Signaturen.

3-1 Hashing mit hashlib

Was ist Hashing?
Beim Hashing werden Daten beliebiger Größe (Nachricht oder Datei) mit Hilfe einer Hash-Funktion auf einen eindeutigen Hashwert (Digest, Prüfsumme) abgebildet. Hashing wird verwendet, um die Integrität einer Datei oder Nachricht während der Übertragung über das Netzwerk zu berechnen.

Wie wird Hashing verwendet? Der Sender S sendet eine Datei an Empfänger E und stellt den Hashwert zusammen mit der ursprünglichen Nachricht bereit. Empfänger E kann den Hashwert der empfangenen Datei berechnen. Eine Übereinstimmung beider Hashwerte versichert Empfänger E, dass die Nachricht nicht verfälscht wurde. Hashing ist also ein Verfahren, um die Integrität von Nachrichten zu gewährleisten.

Bekannte Hashverfahren Zu den bekannten Hashverfahren gehören MD5 - einer der ersten Hashing-Algorithmen, aktuell nur noch als Lehrbeispiel verwendet, die SHA-Hashverfahren (SHA1, SHA224, SHA256, SHA384, SHA512), die Verfahren der BLAKE-Familie (Hashwerte von 224, 256, 384 und 512 Bit für SHA3). SHA (Secure Hash Algorithm) ist eine Familie standardisierter Hashverfahren, mit drei Versionen: SHA-1, SHA-2 und SHA-3, wobei die jeweils letzte Version die neueste und sicherste ist.

In Python sind gängige Hashverfahren über das Paket hashlib verfügbar, das in der Python-Installation schon enthalten ist.

Python-Code: Hashwerte mit hashlib berechnen

import hashlib
# Codiere als Bytes mit UTF8-Codierung
msg = "Hallo zusammen!".encode()
# Berechne verschiedene Hashwerte
print("SHA-256:", hashlib.sha256(msg).hexdigest())
print("SHA-512:", hashlib.sha512(msg).hexdigest())
# BLAKE2 ist sicherer als die SHA-2 Verfahren SHA-256
print("BLAKE2c:", hashlib.blake2s(msg).hexdigest())
print("BLAKE2b:", hashlib.blake2b(msg).hexdigest())

Ausgabe

SHA-256:
 29e0b0d1f0903436da29b5c62ac0f6772acef17c907763c101846ed55271f0f6
SHA-512:
 03957d304c731f24ec66b962acc272646ffc6658d03009516bfc77d088790a1c86616ab1b662e0ee2b465ca2b5de55bec36e0a7ba8ec3ab778b522bfd5ab3a33
BLAKE2c:
 39cf0f20aff0179a4935ca47e9483c3d515158301de8ab7b7570ccffd1ccbfd3

3-2 Message Authentication Codes

Ein MAC (Message Authentication Code) ist ein erweiterter Hashcode, der sowohl die Integrität als auch die Authentizität einer Nachricht überprüfen kann.
Ein einfacher Hashwert wird ohne externen Input aus der Nachricht generiert. Was der Empfänger erhält, ist ein Wert, der nur verwendet werden kann, um zu überprüfen, ob die Nachricht während ihrer Übertragung verändert wurde.
Ein MAC verwendet zusätzlich einen Schlüssel als Seed für die Hash-Funktion. Als Schlüssel kann z.B. der private Teil des RSA-Schlüssels des Senders verwendet werden. Dies bestätigt dem Empfänger die Integrität der Nachricht und die Identität des Absenders.

Bekannte MAC-Verfahren sind:
HMAC: basiert auf kryptographischen Hash-Funktionen und wird in SSL und IPsec eingesetzt.
CMAC: basiert auf Blockchiffren und wird in Verbindung mit AES eingesetzt.

import hashlib
import hmac

msg = "Hallo zusammen!"
key = "Geheimer und langer Schluessel"
# Codiere Text und Schlüssel als Bytes
msg_bytes = msg.encode() 
key_bytes = key.encode()

# Erzeuge neuen HMAC-Code
my_hmac = hmac.new(key_bytes, msg_bytes, hashlib.sha256).hexdigest()
print(my_hmac)

3-3 Passwort-Hashing mit Bcrypt

Passwort-Hashing ist eine spezielle Form des Hashing, die verwendet wird, um Passwörter sicher zu speichern, so, dass auch die Integrität des Passworts gesichert ist. Insbesondere wird beim Passwort-Hashing ein sogenannter Salt verwendet: eine zufällige Zeichenfolge, die so lange ist wie der Hash selber, und für jeden Benutzer eindeutig ist.

Passwort-Hashing macht die Verwaltung von Passwörten erst sicher: selbst wenn der Angreifer die Passwort-Tabelle hat, kann er die gehashten Passwörter nicht so einfach knacken. Der Ablauf ist wie folgt: Das Passwort wird beim Anlegen eines neuen Benutzerkontos gehasht, und nur das gehashte Passwort wird in einer Datenbank-Tabelle gespeichert. Bei Anmeldung des Users wird sein eingegebenes Passwort wieder gehasht und mit dem in der Datenbank gespeicherten Passwort-Hash verglichen.

Aktuell verwendete Algorithmen für Passwort-Hashing sind: bcrypt, scrypt, PBKDF2, Argon2.

In Python werden diese Verfahren in dem Paket bcrypt abgebildet, dieses muss vor Verwendung mit pip installiert werden.

import bcrypt
# Lege ein Passwort fest
passwd = b'my.topsecret.key'
# Erzeuge einen Salt für das Passwort
salt = bcrypt.gensalt(rounds = 14)
# Erzeuge den Passwort-Hash
hashed_passwd = bcrypt.hashpw(passwd, salt)
print("Salt: ", salt)
print("Hashed Password: \n", hashed_passwd)
if (bcrypt.checkpw(passwd, hashed_passwd) == True):
    print("Die Passwörter stimmen überein!")

Nächste Schritte

Die Anleitung Installation Python und Anaconda beschreibt die Installation und Verwendung der Paketverwaltungsplattform Anaconda, als Hilfsmittel für Python-Programmierung im Rahmen des Maschinellen Lernens. Anaconda bietet eine grafische Benutzeroberfläche zum Installieren von Python-Tools und -Paketen, sowie zum Erstellen virtueller Environments.

In Python Tutorial Teil 2: Pakete installieren wird beschrieben, wie man mit Hilfe der Paketverwaltungssysteme pip und conda Python-Pakete installiert, aktualisiert und deinstalliert, wie man für verschiedene Projekte passende Anwendungsumgebungen ("environments") erstellt und wie man die installierten Pakete in Python-Skripten mit Hilfe der import-Anweisung korrekt importiert. Die Entwicklung selbstdefinierter Pakete, mit deren Hilfe man größere Projekte strukturieren kann, wird an einem Beispiel vorgestellt.

Demo-PY2: Datenverwaltung und -Visualisierung mit Pandas zeigt am Beispiel eines Zeitreihen-Datensatzes zum Stromverbrauch in Deutschland, wie die Datenverwaltung und - visualisierung mit Hilfe der Python-Bibliotheken Pandas und Matplotlib durchgeführt wird. Die Daten werden in der interaktiven, webbasierten Anwendungsumgebung Jupyter Notebook analysiert.


Autoren, Tools und Quellen

Autor:
 Prof. Dr. Eva Maria Kiss


Tools:

elab2go-Links

Quellen und weiterführende Links

  • [1] Offizielle Python Dokumentation bei python.org: docs.python.org/3/tutorial/
    sehr umfangreich, Nachschlagewerk, hier findet man Dokumentationen für verschiedene Python-Versionen
  • [2] Python Tutorial bei Google Developers: developers.google.com/edu/python/introduction
    umfangreich, für Fortgeschrittene, verweist auf die offizielle Dokumentation
  • [3] Python Tutorial bei W3Schools: w3schools.com/python/ – für Einsteiger geeignet, interaktive Ausführung im Browser
  • [4] Python Tutorial: evamariakiss.de/tutorial/python/ – zum Nachschlagen der wichtigsten Python-Befehle, mit Selbsttest / Quiz
  • [5] NumPy: numpy.org/ – Mehrdimensionale Arrays, Mathematische Funktionen, Zufallszahlen
  • [6] Matplotlib: matplotlib.org/ – Datenvisualisierung, Plotten
  • [7] Pandas: pandas.pydata.org/ – Datenverwaltung, Datenvorbereitung, DataFrames, Series
  • [8] Scikit-Learn: scikit-learn.org – Algorithmen für Maschinelles Lernen
  • [9] Keras: keras.io – Künstliche Neuronale Netzwerke, Deep Learning