1. Home
  2. Misc IT
  3. Python
  4. Simulation einer Passkey Authentifizierung

Simulation einer Passkey Authentifizierung

Lesedauer: 5 Minuten

Das Ziel des folgenden Programms ist eine exemplarische Veranschaulichung der Registrierung und Authentifikation des Passkey Verfahrens. Es stellt keine sichere Implementierung dar.

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

Loading

Updated on 22. Mai 2024
Was this article helpful?

Related Articles