Homomorphe Verschlüsselung: Python-Tutorial zur Praxis
Erfahren Sie, wie Sie mit homomorpher Verschlüsselung auf verschlüsselten Gesundheitsdaten rechnen. Das Python-Tutorial nutzt TenSEAL – ohne Entschlüsselung.
Auf dieser Seite
Stellen Sie sich vor, Sie entwickeln eine revolutionäre Health-Tech-Anwendung. Sie möchten Nutzerinnen und Nutzern aufschlussreiche Analysen zu ihren biometrischen Daten bereitstellen, etwa die durchschnittliche Ruheherzfrequenz der vergangenen Woche. Es gibt nur eine große Hürde: Diese Daten sind äußerst sensibel. Ein Datenleck könnte persönliche Gesundheitsinformationen offenlegen und zu einem katastrophalen Vertrauensverlust sowie erheblichen rechtlichen Folgen führen.
Herkömmlicherweise müsste ein Server die Daten entschlüsseln, um eine Berechnung wie einen Durchschnitt durchzuführen. In diesem Moment der Berechnung sind die Klartextdaten angreifbar. Was wäre, wenn Sie Berechnungen direkt auf den verschlüsselten Daten ausführen könnten? Das ist das Versprechen der homomorphen Verschlüsselung (Homomorphic Encryption, HE), einer kryptografischen Technik, die wie Magie wirkt. Sie ermöglicht es einer dritten Partei (etwa einem Cloud-Server), Chiffretext zu verarbeiten und darauf zu rechnen und ein verschlüsseltes Ergebnis zu erzeugen, das nach der Entschlüsselung identisch mit dem Ergebnis der auf dem Klartext ausgeführten Operationen ist.
In diesem Tutorial entmystifizieren wir die homomorphe Verschlüsselung, indem wir ein praktisches Python-Beispiel erstellen. Wir werden:
- Eine Liste sensibler Gesundheitsdaten verwenden (z. B. tägliche Herzfrequenzmessungen).
- Diese Daten „clientseitig“ mit einer leistungsstarken Python-Bibliothek namens
TenSEALverschlüsseln. - Die verschlüsselten Daten an einen „Server“ senden, der die durchschnittliche Herzfrequenz ohne den Entschlüsselungsschlüssel berechnet.
- Den verschlüsselten Durchschnitt zur sicheren Entschlüsselung an den Client zurückgeben.
Dieser praxisnahe Ansatz zeigt Ihnen, wie Sie fortgeschrittene Kryptografie nutzen, um datenschutzfreundliche Funktionen zu entwickeln – eine entscheidende Fähigkeit im Zeitalter des Datenschutzes.
Voraussetzungen:
- Kenntnisse: Ein solides Verständnis von Python. Vorkenntnisse in Kryptografie sind nicht erforderlich.
- Werkzeuge: Python 3.7+ und die Bibliothek
tenseal.
Das Problem verstehen: Das Datenschutzparadox in der Health-Tech-Branche
Die Health-Tech-Branche steht vor einem Paradox: Je mehr Daten sie erhebt, desto personalisierter und wirksamer können ihre Dienste sein. Dieser Datenreichtum, der alles von Herzfrequenzen und Schlafmustern bis hin zu Genomsequenzen umfasst, ist jedoch ein bevorzugtes Ziel für Angreifer.
Aktuelle Lösungen und ihre Grenzen:
- Verschlüsselung im Ruhezustand und bei der Übertragung: Zur gängigen Praxis gehört es, Daten zu verschlüsseln, wenn sie in einer Datenbank gespeichert sind (im Ruhezustand) und wenn sie über ein Netzwerk übertragen werden (bei der Übertragung). Das ist unverzichtbar, lässt aber eine entscheidende Schwachstelle: Daten müssen für die Berechnung entschlüsselt werden.
- Anonymisierung: Dabei werden personenbezogene Daten (Personally Identifiable Information, PII) aus Datensätzen entfernt. Das ist nützlich, doch Re-Identifizierungsangriffe werden immer ausgefeilter, und für personalisierte Analysen müssen Daten häufig einer bestimmten Person zugeordnet werden können.
Unser Ansatz: Berechnung auf dem Chiffretext Die homomorphe Verschlüsselung löst die „Berechnungsschwachstelle“. Ein Server kann Analysen ausführen, Modelle des maschinellen Lernens trainieren und Erkenntnisse aus Nutzerdaten gewinnen, ohne jemals die rohen, sensiblen Informationen zu sehen. Das eröffnet neue Möglichkeiten für sicheres Cloud Computing, die Zusammenarbeit mehrerer Parteien in der medizinischen Forschung und wirklich private persönliche Analysen. Für unser Tutorial verwenden wir das Schema CKKS (Cheon-Kim-Kim-Song), das speziell für Berechnungen mit reellen (oder näherungsweisen) Zahlen entwickelt wurde und sich daher hervorragend für biometrische Daten eignet.
Voraussetzungen: Ihre Umgebung einrichten
Bevor wir beginnen, bereiten wir unsere Umgebung vor. Sie müssen die Bibliothek tenseal installieren.
Öffnen Sie Ihr Terminal und führen Sie den folgenden Befehl aus:
pip install tenseal
Um die Installation zu prüfen, starten Sie einen Python-Interpreter und importieren Sie die Bibliothek:
import tenseal as ts
print(ts.__version__)
Sie sollten die installierte Versionsnummer ohne Fehler sehen.
Schritt 1: Den Kontext für die homomorphe Verschlüsselung erstellen
Der erste Schritt in jeder TenSEAL-Anwendung besteht darin, einen TenSEALContext zu erstellen. Dieses Objekt enthält alle entscheidenden Parameter unseres Verschlüsselungsschemas, einschließlich des öffentlichen Schlüssels, des privaten (geheimen) Schlüssels und der Einstellungen, die das Sicherheitsniveau und die Rechenfähigkeiten festlegen.
Was wir tun
Wir konfigurieren einen Kontext für das Verschlüsselungsschema CKKS. Wir müssen drei zentrale Parameter festlegen:
poly_modulus_degree: Dieser Parameter beeinflusst das Sicherheitsniveau und die Anzahl der Werte, die wir in einem einzelnen Vektor verschlüsseln können. Er muss eine Zweierpotenz sein.coeff_mod_bit_sizes: Damit wird die Größe der Primzahlen im Koeffizientenmodul festgelegt. Er beeinflusst die „multiplikative Tiefe“ – wie viele Multiplikationen wir auf den verschlüsselten Daten ausführen können, bevor das Rauschen so stark anwächst, dass der Chiffretext nicht mehr entschlüsselt werden kann.global_scale: Damit wird die Genauigkeit unserer verschlüsselten reellen Zahlen bestimmt. Wir arbeiten im Wesentlichen mit Festkommazahlen, und dieser Skalierungsfaktor legt fest, wo das Dezimalkomma liegt.
Umsetzung
# src/create_context.py
import tenseal as ts
def create_context():
"""
Creates and configures a TenSEAL context for Homomorphic Encryption.
"""
context = ts.context(
ts.SCHEME_TYPE.CKKS,
poly_modulus_degree=8192,
coeff_mod_bit_sizes=
)
context.generate_galois_keys()
context.global_scale = 2**40
return context
if __name__ == '__main__':
ctx = create_context()
print("✅ TenSEAL context created successfully.")
print(f" Parameters: poly_modulus_degree={ctx.poly_modulus_degree()}, global_scale=2^{ctx.global_scale.bit_length()-1}")
# The context holds the private key
secret_key = ctx.secret_key()
# We can also create a public version of the context that doesn't contain the secret key
public_ctx = ctx.copy()
public_ctx.make_context_public() # Drops the secret key
print("🔑 Context contains private key:", ctx.is_private())
print("🔑 Public context contains private key:", public_ctx.is_private())
So funktioniert es
Wir initialisieren den Kontext mit dem Schema CKKS. Ein poly_modulus_degree von 8192 ist eine gängige und sichere Wahl. Die Liste coeff_mod_bit_sizes ermöglicht eine bestimmte Anzahl verketteter Multiplikationen. Wir erzeugen außerdem galois_keys, die für Vektorrotationsoperationen erforderlich sind – ein entscheidender Schritt, um alle Elemente unseres verschlüsselten Vektors aufzusummieren. Schließlich erstellt make_context_public() eine Version des Kontexts, die an den Server gesendet werden kann; sie enthält den öffentlichen Schlüssel und die Auswertungsschlüssel, aber entscheidend nicht den geheimen Schlüssel, der für die Entschlüsselung benötigt wird.
Schritt 2: Verschlüsselung auf der Clientseite
Nachdem wir einen Kontext haben, simulieren wir die Rolle des Clients. Eine Nutzerin oder ein Nutzer verfügt über Ruheherzfrequenzdaten einer Woche und möchte einen Durchschnitt erhalten, ohne dem Server die einzelnen Werte offenzulegen.
Was wir tun
Wir nehmen eine Liste von Gleitkommazahlen, die Herzfrequenzen darstellen, und verschlüsseln sie in einen einzelnen CKKSVector. Dieses Vektorobjekt bündelt alle Datenpunkte zu einer verschlüsselten Einheit.
Umsetzung
# src/client.py
import tenseal as ts
from create_context import create_context
def encrypt_health_data(context, data):
"""Encrypts a list of numbers into a CKKS vector."""
return ts.ckks_vector(context, data)
if __name__ == '__main__':
# (Client-side)
# 1. Create context with a secret key
context = create_context()
# 2. Sample sensitive health data
heart_rate_data = [72.5, 71.0, 73.2, 69.8, 70.5, 74.1, 71.7]
print(f"Plaintext data (client): {heart_rate_data}")
# 3. Encrypt the data
encrypted_heart_rates = encrypt_health_data(context, heart_rate_data)
print(f"🔒 Data encrypted successfully into a CKKS vector.")
# 4. Serialize the encrypted data and the public context for sending
serialized_encrypted_vector = encrypted_heart_rates.serialize()
# Create and serialize the public context
public_context = context.copy()
public_context.make_context_public()
serialized_public_context = public_context.serialize()
# This is what we would send to the server
# For this tutorial, we'll pass the objects directly
# In a real app, this would be an API call
#
# server_receives(serialized_public_context, serialized_encrypted_vector)
So funktioniert es
Die Funktion ts.ckks_vector() nimmt unseren Kontext und die Zahlenliste. Sie kodiert die Zahlen in ein Polynom und verschlüsselt es anschließend mit dem im Kontext gespeicherten öffentlichen Schlüssel. Das Ergebnis ist ein einzelnes CKKSVector-Objekt, das alle unsere Herzfrequenzdaten in verschlüsseltem Zustand enthält.
Schritt 3: Berechnung auf verschlüsselten Daten auf der Serverseite
Hier geschieht die Magie. Der „Server“ empfängt den verschlüsselten Vektor und den öffentlichen Kontext. Seine Aufgabe ist es, den Durchschnitt der Zahlen im Vektor ohne den geheimen Schlüssel zu berechnen.
Ein Durchschnitt wird als sum(values) / count(values) berechnet. Das können wir in zwei Schritten tun:
- Summe: Die Elemente des verschlüsselten Vektors homomorph aufsummieren.
- Division: Die verschlüsselte Summe homomorph durch die öffentliche Anzahl der Elemente teilen (was lediglich eine Multiplikation mit dem Kehrwert ist).
Was wir tun
Um die Elemente des Vektors zu summieren, verwenden wir eine Strategie des „Rotierens und Summierens“. Stellen Sie sich vor, unser Vektor ist [v1, v2, v3, v4]. Wir können ihn um eine Position rotieren und erhalten [v2, v3, v4, v1], und addieren das Ergebnis dann zum Original. Wir wiederholen diesen Vorgang und verdoppeln in jedem Schritt die Anzahl der summierten Elemente, bis alle Elemente in jedem Slot des Vektors akkumuliert wurden. Abschließend multiplizieren wir den resultierenden Vektor mit 1/n, um den Durchschnitt zu erhalten.
Umsetzung
# src/server.py
import math
def calculate_encrypted_average(public_context, encrypted_vector):
"""
Performs homomorphic operations to calculate the average of an encrypted vector.
"""
# The server can get the size of the vector without decrypting
n_values = len(encrypted_vector)
# 1. Homomorphically sum all elements in the vector
# This is the most complex step. We use rotations to achieve a horizontal sum.
encrypted_sum = encrypted_vector.sum()
print("🖥️ Server: Encrypted sum calculated.")
# 2. Multiply by the inverse of the number of values to get the average
# Division by a plaintext number is equivalent to multiplication by its inverse.
encrypted_average = encrypted_sum * (1 / n_values)
print(f"🖥️ Server: Encrypted average calculated by multiplying with {1/n_values:.4f}.")
return encrypted_average
if __name__ == '__main__':
# This block simulates the full pipeline
# ====== CLIENT SIDE ======
from create_context import create_context
import tenseal as ts
# 1. Setup
context = create_context()
heart_rate_data = [72.5, 71.0, 73.2, 69.8, 70.5, 74.1, 71.7]
print(f"Plaintext data (client): {heart_rate_data}")
print(f"Plaintext average: {sum(heart_rate_data) / len(heart_rate_data):.2f}")
# 2. Encrypt
encrypted_heart_rates = ts.ckks_vector(context, heart_rate_data)
print("🔒 Client: Data encrypted.")
# ====== DATA TRANSFER (Client -> Server) ======
# In a real app, you'd serialize and send over HTTP/RPC
serialized_vector = encrypted_heart_rates.serialize()
public_context = context.copy()
public_context.make_context_public()
serialized_context = public_context.serialize()
# ====== SERVER SIDE ======
# The server only has the public context and the encrypted data
server_context = ts.context_from(serialized_context)
server_encrypted_vector = ts.ckks_vector_from(server_context, serialized_vector)
print("☁️ Server: Received encrypted data and public context.")
# 3. Compute
encrypted_average = calculate_encrypted_average(server_context, server_encrypted_vector)
# ====== DATA TRANSFER (Server -> Client) ======
serialized_encrypted_average = encrypted_average.serialize()
# ====== CLIENT SIDE ======
# 4. Decrypt
print("🔙 Client: Received encrypted average.")
result_vector = ts.ckks_vector_from(context, serialized_encrypted_average) # Use original context with secret key
decrypted_average = result_vector.decrypt() # The result is in the first slot
print("\
======== RESULTS ========")
print(f"✅ Decrypted Average Heart Rate: {decrypted_average:.2f}")
print("=========================")
So funktioniert es
Die Methode encrypted_vector.sum() in TenSEAL abstrahiert die komplexe Logik des „Rotierens und Summierens“. Sie verwendet die in Schritt 1 erzeugten Galois-Schlüssel, um effiziente Rotationen und Additionen auszuführen, und erzeugt schließlich einen neuen verschlüsselten Vektor, in dem jedes Element die Summe aller ursprünglichen Elemente ist.
Als Nächstes führt encrypted_sum * (1 / n_values) eine elementweise Multiplikation zwischen der verschlüsselten Summe und einer unverschlüsselten Zahl aus. Das Schema CKKS unterstützt diese Operation nahtlos. Der Server verfügt nun über einen verschlüsselten Vektor, der den Durchschnitt darstellt, und kann ihn an den Client zurücksenden.
Nach Erhalt des Ergebnisses verwendet der Client seinen ursprünglichen context (der weiterhin den geheimen Schlüssel enthält), um die Nachricht zu entschlüsseln und den endgültigen, genauen Durchschnitt zu erhalten.
Leistungsaspekte
Die homomorphe Verschlüsselung ist leistungsfähig, aber nicht kostenlos. Die Berechnungen sind deutlich langsamer und speicherintensiver als ihre Gegenstücke im Klartext.
- Latenz: Das Verschlüsseln, Entschlüsseln und insbesondere das Rechnen auf verschlüsselten Daten braucht Zeit. Für unseren einfachen Durchschnitt sind es Millisekunden, bei komplexen Modellen des maschinellen Lernens können es jedoch Sekunden oder Minuten sein.
- Größe des Chiffretexts: Der serialisierte verschlüsselte Vektor ist viel größer als die ursprünglichen Klartextdaten. Eine Liste von 7 Gleitkommazahlen (56 Byte) kann zu einem Chiffretext von mehreren Hundert Kilobyte werden.
- Parametereinstellung: Sicherheit und Leistung des Schemas CKKS hängen stark von den Kontextparametern ab (
poly_modulus_degree,coeff_mod_bit_sizes). Größere Parameter bieten mehr Sicherheit und ermöglichen komplexere Berechnungen (mehr Multiplikationen), sind aber langsamer. Die richtigen Parameter für Ihren Anwendungsfall zu wählen, ist ein entscheidender Balanceakt.
Bewährte Sicherheitspraktiken
- Schlüsselverwaltung: Der geheime Schlüssel ist das kritischste Element dieses Systems. Er sollte das Gerät des Clients niemals verlassen. Standardmäßige sichere Verfahren der Schlüsselverwaltung sind unerlässlich.
- Parameterauswahl: Verwenden Sie etablierte, sichere Parameter. Die Standardwerte von
TenSEALsind ein guter Ausgangspunkt, doch für Produktionssysteme sollten Sie die kryptografische Fachliteratur zu empfohlenen Sicherheitsniveaus konsultieren (z. B. 128-Bit-Sicherheit). - Seitenkanalangriffe: Der Server kann die Daten zwar nicht sehen, aber er kann Berechnungszeiten und Speicherzugriffsmuster beobachten. In besonders sensiblen Szenarien könnten diese „Seitenkanäle“ Informationen preisgeben. Systeme so zu entwerfen, dass sie gegen solche Angriffe resistent sind, ist ein fortgeschrittenes Thema.
- Keine eigene Kryptografie entwickeln: Verwenden Sie stets gut geprüfte, von Fachleuten begutachtete Bibliotheken wie
TenSEAL(die auf Microsoft SEAL aufbaut).
Fazit
Wir haben erfolgreich ein vollständiges Beispiel von Anfang bis Ende durchgearbeitet, bei dem eine Berechnung auf verschlüsselten Daten ausgeführt wird. Wir haben als Client gehandelt und sensible Herzfrequenzdaten verschlüsselt und anschließend die Rolle eines Servers übernommen, der den Durchschnitt berechnet hat, ohne jemals die Rohzahlen zu sehen. Diese leistungsstarke datenschutzfreundliche Technik ist nicht länger nur theoretisch; sie ist für Python-Entwicklerinnen und -Entwickler über Bibliotheken wie TenSEAL zugänglich.
Obwohl die homomorphe Verschlüsselung Leistungseinbußen mit sich bringt, ermöglicht sie eine neue Klasse sicherer Anwendungen, insbesondere in sensiblen Bereichen wie dem Gesundheitswesen und dem Finanzwesen.
Nächste Schritte für die Leserschaft:
- Experimentieren Sie mit anderen Berechnungen, etwa der Varianz oder einer einfachen linearen Regression.
- Untersuchen Sie die Auswirkungen geänderter Kontextparameter auf die Leistung.
- Versuchen Sie, den Kontext und die verschlüsselten Vektoren in Dateien zu serialisieren, um eine realistischere Client-Server-Interaktion zu simulieren.
Ressourcen
- Offizielle Dokumentation: TenSEAL GitHub Repository
- Zugrunde liegende Bibliothek: Microsoft SEAL
- Weiterführende Lektüre: A Step-by-Step Fully Homomorphic Encryption Example with TenSEAL
Kurzreferenz
| Aspekt | Wesentliche Informationen |
|---|---|
| Thema | Entwicklung |
| Relevanz | Patientenaufklärung und Bewusstsein |
| Maßnahme | Besprechen Sie dies mit Ihrer medizinischen Fachperson |
| Häufigkeit | Wie von Ihrem Behandlungsteam empfohlen |
| Evidenz | Basierend auf aktuellen klinischen Leitlinien |
Häufig gestellte Fragen
F: Woran erkenne ich, ob das auf mich zutrifft? A: Besprechen Sie Ihre persönliche und familiäre Krankengeschichte mit Ihrer medizinischen Fachperson, um Ihre individuellen Risikofaktoren einzuschätzen und geeignete nächste Schritte festzulegen.
F: Was sollte ich meine Ärztin oder meinen Arzt fragen? A: Gute Fragen sind unter anderem: „Was bedeuten meine Ergebnisse?“, „Welche Möglichkeiten habe ich?“, „Welche Lebensstiländerungen würden helfen?“ und „Wann sollte ich zur Nachkontrolle kommen?“
F: Gibt es Lebensstiländerungen, die helfen können? A: Den meisten gesundheitlichen Beschwerden kommen grundlegende Maßnahmen zugute: ausgewogene Ernährung, regelmäßige körperliche Aktivität (150+ Minuten/Woche), erholsamer Schlaf (7–9 Stunden), Stressbewältigung und der Verzicht auf Tabak.
Medizinischer Haftungsausschluss
Dieser Artikel dient ausschließlich Bildungszwecken und stellt keine medizinische Beratung dar. Wenden Sie sich stets an eine qualifizierte medizinische Fachperson, bevor Sie Entscheidungen über Ihre Gesundheit, Behandlung oder Versorgung treffen. Individuelle Umstände unterscheiden sich, und was für eine Person angemessen ist, muss für eine andere nicht angemessen sein.
Wenn Sie einen medizinischen Notfall erleben, rufen Sie sofort 911 (oder Ihre örtliche Notrufnummer) an.