Code
import os import json import base64 from Crypto.PublicKey import RSA from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA256 class Authenticator: def __init__(self): # CLIENT: Initialisiert das Authenticator-Objekt self.key_pair = None def generate_keys(self): # CLIENT: Generiert ein Schlüsselpaar und exportiert es self.key_pair = RSA.generate(2048) private_key = self.key_pair.export_key() public_key = self.key_pair.publickey().export_key() return private_key, public_key def sign_challenge(self, challenge): # CLIENT: Erstellt einen SHA256-Hash der Challenge h = SHA256.new(challenge.encode('utf-8')) # CLIENT: Signiert den Hash mit dem privaten Schlüssel signature = pkcs1_15.new(self.key_pair).sign(h) # CLIENT: Kodiert die Signatur in Base64 und gibt sie zurück return base64.b64encode(signature).decode('utf-8') def verify_signature(self, public_key, challenge, signature): # SERVER: Importiert den öffentlichen Schlüssel pub_key = RSA.import_key(public_key) # SERVER: Erstellt einen SHA256-Hash der Challenge h = SHA256.new(challenge.encode('utf-8')) try: # SERVER: Überprüft die Signatur mit dem öffentlichen Schlüssel pkcs1_15.new(pub_key).verify(h, base64.b64decode(signature.encode('utf-8'))) return True except (ValueError, TypeError): # SERVER: Gibt False zurück, wenn die Signatur ungültig ist return False class Server: def __init__(self): # SERVER: Initialisiert den Server mit einem leeren Dictionary für öffentliche Schlüssel self.public_keys = {} def register(self, user_id, public_key): # SERVER: Speichert den öffentlichen Schlüssel für den Benutzer self.public_keys[user_id] = public_key def generate_challenge(self): # SERVER: Generiert eine zufällige Base64-kodierte Herausforderung return base64.b64encode(os.urandom(32)).decode('utf-8') def authenticate(self, user_id, challenge, signature): # SERVER: Holt den öffentlichen Schlüssel des Benutzers public_key = self.public_keys.get(user_id) if not public_key: # SERVER: Gibt False zurück, wenn der Benutzer nicht registriert ist return False # SERVER: Erstellt ein Authenticator-Objekt authenticator = Authenticator() # SERVER: Überprüft die Signatur der Herausforderung return authenticator.verify_signature(public_key, challenge, signature) # Initialisierung der Komponenten # SERVER: Erstellt einen Server server = Server() # CLIENT: Erstellt einen Authenticator authenticator = Authenticator() # Registrierung user_id = 'prontosystems' # CLIENT: Generiert Schlüssel private_key, public_key = authenticator.generate_keys() # CLIENT: Ausgabe der Schlüssel print(f"Privater Schlüssel:\n{private_key.decode('utf-8')}") print(f"\nÖffentlicher Schlüssel:\n{public_key.decode('utf-8')}") # CLIENT: Übergibt den öffentlichen Schlüssel (public_key) und Benutzer (user_id) an den Server # SERVER: Registriert den Benutzer server.register(user_id, public_key.decode('utf-8')) print(f"\nUser {user_id} registriert mit öffentlichem Schlüssel.\n") # Authentifizierung # SERVER: Generiert eine Herausforderung challenge = server.generate_challenge() print(f"Server generiert Herausforderung: {challenge}\n") # CLIENT: Signiert die Herausforderung signature = authenticator.sign_challenge(challenge) print(f"Client signiert Herausforderung: {signature}\n") # SERVER: Überprüft die Signatur is_authenticated = server.authenticate(user_id, challenge, signature) print(f"Authentifizierung erfolgreich: {is_authenticated}")
Erklärung des Codes
Initialisierung der Komponenten
Server-Initialisierung:
Ein Server
-Objekt wird erstellt, das eine leere Datenbank zur Speicherung der öffentlichen Schlüssel der Benutzer enthält.
server = Server() # SERVER: Erstellt einen Server
Authenticator-Initialisierung:
Ein Authenticator
-Objekt wird erstellt, das zunächst kein Schlüsselpaar generiert.
authenticator = Authenticator() # CLIENT: Erstellt einen Authenticator
Registrierung
Generierung der Schlüssel durch den Client:
Der Client (Authenticator) generiert ein Schlüsselpaar (privater und öffentlicher Schlüssel) durch den Aufruf der Methode generate_keys
.
user_id = 'prontosystems' private_key, public_key = authenticator.generate_keys() # CLIENT: Generiert Schlüssel
Ausgabe der Schlüssel (Optional):
Der private und der öffentliche Schlüssel werden in der Konsole ausgegeben:
print(f"Privater Schlüssel:\n{private_key.decode('utf-8')}") print(f"\nÖffentlicher Schlüssel:\n{public_key.decode('utf-8')}")
Übergabe des öffentlichen Schlüssels an den Server:
- Der Client übergibt den öffentlichen Schlüssel und die Benutzer-ID an den Server durch den Aufruf der Methode
register
des Server-Objekts. - Der Server speichert den öffentlichen Schlüssel zusammen mit der Benutzer-ID in seiner Datenbank
public_keys
.
server.register(user_id, public_key.decode('utf-8')) # SERVER: Registriert den Benutzer beim Server print(f"\nUser {user_id} registriert mit öffentlichem Schlüssel.\n")
Authentifizierung
Generierung der Herausforderung durch den Server:
Der Server generiert eine zufällige, Base64-kodierte Herausforderung (Challenge) und gibt diese in der Konsole aus.
challenge = server.generate_challenge() # SERVER: Generiert eine Herausforderung print(f"Server generiert Herausforderung: {challenge}\n")
Signatur der Herausforderung durch den Client:
Der Client (Authenticator) signiert die erhaltene Herausforderung mit seinem privaten Schlüssel und gibt die Base64-kodierte Signatur in der Konsole aus.
signature = authenticator.sign_challenge(challenge) # CLIENT: Signiert die Herausforderung print(f"Client signiert Herausforderung: {signature}\n")
Überprüfung der Signatur durch den Server:
- Der Server überprüft die Signatur der Herausforderung mit dem gespeicherten öffentlichen Schlüssel des Benutzers durch den Aufruf der Methode
authenticate
. - Wenn die Überprüfung erfolgreich ist, gibt der Server an, dass die Authentifizierung erfolgreich war.
is_authenticated = server.authenticate(user_id, challenge, signature) # SERVER: Überprüft die Signatur print(f"Authentifizierung erfolgreich: {is_authenticated}")
Ausgabe des Programms:
Privater Schlüssel:
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA6bprb/8v1ho5f3nedCCjcXo4LfTD513SLSJgchOQmvRWkOQu
8hUOkEW2sR0M3yx95quw4aIP0W0WpUDWhqF0nJipRdloDpweNP8P/zljkVkgIgPr
gRPUJ0WOCkqgB2nM0+1Ru/1vONEAqjyjF2lXWX0X+OFJSfxjmqqtjHamFdMi9yyX
sszwRJgHlZ1G4HzG0/KfmKmdOxW4/oZcV0rtTp5qXWr3fm/s6TJhUN7MDi+FGGUr
/bwitVmgPnOn28401R1iFc70XJ+K24Egd5jK68kEzfrPMnCKHjL7SAhq67z+Nn1I
mZNf6eDhFWKmRZe4mvJ96veS98XN3bheY5eCvQIDAQABAoIBABHsv37A7/LSzeGP
n7FBa997oNGExxMYStKLeMuO4g/Bg4kMTZMNwoaV03ISWQbIPftB5BMYeho/gZWD
WzXLLesGOdx26lLNLh42MyHJotqbs/SVNItl5qbrX+kR+ji5/bYsFLu0Lu0zztdU
xqo4jzUi/EK/SP8GVD+L7ZA17OdZRXpJeoymRlrn50Y+aWJz6l5NgBbMT5sxfQ5X
A8HcHKfSGCWop2huuZBaXwzaeyAO/NNK9y5GKZ6MO/VTqi8YIUhSiTrQXKZMqy4u
yUUEICMz3liS74E5LyFfzLwzgvjSWAp4rQRze4nhk1BleYwsn+6dyi59KOKG3UMx
VIAYewkCgYEA7q95beTw7ZiBRJre/pbBosNkhVuS+Fo+otWowV6ChTt3uyA57y/B
/rxzIYIiwmevIkA+YElz2wA0p3sIGBONDAkF2ESgpYf8sug/inDwGhmcJ2faqAsl
04jAP2x6WoYbH3RvEkYdDp/8bIgEauwCvE6SMjwba3yPcYSisWfu69kCgYEA+q7i
721J2IPP63o7GDVtSdabZuATJa6x3cnRk188P1BXFiONUEGQyI02IFcGTQ0qo9BQ
ZuJzFC5bx+1PxJitu2n9L4kE8VHb3HyX/occsbiaCBJyiyv+X9kjoJYmDTjbkq4a
jCB6GZT7EH0uhrdzCExOMLdT0FTrFQQO0chY84UCgYEAyjBjELCLVvmFJ3R5yfgy
94nFMSKtkSwBOzb6yTMiJXKGrkFSUkeGch94972hbEUgmkcJj88pES9Pa0BRTvPg
230ZMmaQHyje6z7J9KBPBA0FtmvHUep/lH2XPSLLUrufZjnfjP9Pxf/IeLeP5nMe
rh1wwpUgNSFC8cqFdvqv7aECgYEAvSksqzjPqWbFhU4Fu53NKxOazkU1jZDGPLLm
xwrtHmWUYWtQXggrpXoRJtQkOA5AZ75wfUJRTiAxN6rWL2Z6alpvJ+h/500616TY
2MLBn0XKTV8GOghneZITdUD307Bc19EyzRxQpm8qCGY9roBNeCyEL/SWdTUu8vvN
5vUEUjUCgYEAtrRGVFnxA4gKJC/Dt52WRvmzuFlx8GM9ZX0wcKuwo+1qiO16Eslx
n2O9q4bB3/kpqxoQu5OlZiCMrZ8AeYdTUC2sETOPC9ETckKd/H9xD+cnthQcxpFz
V3uuBrk2yXjlk5DzTqE7AMZ8648onYGb+erh1ubERihA19HTBBiwG1c=
-----END RSA PRIVATE KEY-----
Öffentlicher Schlüssel:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6bprb/8v1ho5f3nedCCj
cXo4LfTD513SLSJgchOQmvRWkOQu8hUOkEW2sR0M3yx95quw4aIP0W0WpUDWhqF0
nJipRdloDpweNP8P/zljkVkgIgPrgRPUJ0WOCkqgB2nM0+1Ru/1vONEAqjyjF2lX
WX0X+OFJSfxjmqqtjHamFdMi9yyXsszwRJgHlZ1G4HzG0/KfmKmdOxW4/oZcV0rt
Tp5qXWr3fm/s6TJhUN7MDi+FGGUr/bwitVmgPnOn28401R1iFc70XJ+K24Egd5jK
68kEzfrPMnCKHjL7SAhq67z+Nn1ImZNf6eDhFWKmRZe4mvJ96veS98XN3bheY5eC
vQIDAQAB
-----END PUBLIC KEY-----
User prontosystems registriert mit öffentlichem Schlüssel.
Server generiert Herausforderung: ALHmC66w7iGh4r1b4MFRJOV1Z5rsMeKWYhmyLDMfjxQ=
Client signiert Herausforderung: z0RTJUylAIHqnJu7qSMnhGt5MzoPyy0bZQ4Tjr+0K9bEB7IYSDxSRWwFwwjli8vCeSau1yjH+OJIBUwqDG8uVe4sIZJ+/ohHtQsFgUBRdYHA/27b3Qe9UmLjQ+HoJonKp51MLZUYw4Hqr3hrjAci3ZoUMf/OTW6HBbkhfpv+w7L5k0qEAevckDlajvkncYMVmlRBJMA/jvcHSWPzZ0+8uI/9xnAOCfGkm1Inkum0KoPe6frhfx9v8mMzoiOCD6NWAOGHPqspyljNcmZXVsPLMW0GIqPxf/ac5V/YqIg6K4hcdvd514oZ8mbX3hoHwi/rvhtv6BI+wgs7CoxdP+fcyw==
Authentifizierung erfolgreich: True