Datum: 15. Dezember 2025
Version: 1.0
Kontext: Technische Klärung zur Durchsuchbarkeit von verschlüsselten HNSW-Indizes
Frage: "Wäre ein symmetrisch verschlüsselter HNSW wie ein plain HNSW durchsuchbar?"
Frage: Ist ein symmetrisch verschlüsselter HNSW-Index direkt durchsuchbar?
Antwort: ❌ NEIN - Symmetrisch verschlüsselte Daten sind NICHT direkt durchsuchbar
Grund: Distanzberechnungen (Cosine Similarity, L2) benötigen Zugriff auf Plaintext-Vektoren
Lösung: Entschlüsselung in Memory vor der Suche (wie bereits empfohlen in SYMMETRIC_ENCRYPTION_APPROACHES.md)
HNSW-Suche benötigt Distanzberechnungen:
# Cosine Similarity (HNSW verwendet dies intern)
def cosine_similarity(vec_a, vec_b):
dot_product = sum(a * b for a, b in zip(vec_a, vec_b))
norm_a = sqrt(sum(a * a for a in vec_a))
norm_b = sqrt(sum(b * b for b in vec_b))
return dot_product / (norm_a * norm_b)
# Beispiel mit Plaintext-Vektoren
vec1 = [0.1, 0.2, 0.3]
vec2 = [0.15, 0.25, 0.35]
similarity = cosine_similarity(vec1, vec2) # Funktioniert!
# Mit AES-256-GCM verschlüsselten Vektoren
encrypted_vec1 = AES_encrypt(vec1, key) # [0x8f, 0xa3, 0x2d, ...]
encrypted_vec2 = AES_encrypt(vec2, key) # [0x1c, 0x7b, 0x99, ...]
similarity = cosine_similarity(encrypted_vec1, encrypted_vec2) # ❌ Unsinn!Problem: AES-Verschlüsselung zerstört die mathematischen Eigenschaften der Vektoren:
- Keine Distanz-Erhaltung
- Keine Ähnlichkeits-Erhaltung
- Ergebnis ist random noise
AES-256-GCM Eigenschaften:
Plaintext: [0.1, 0.2, 0.3]
↓ AES-256-GCM Encrypt
Ciphertext: [0x8f3a2d4b, 0x7c9e1f5a, ...] (pseudorandom bytes)
Eigenschaften von AES-Ciphertext:
- ✅ Konfusion: Jedes Bit des Plaintexts beeinflusst jeden Bit des Ciphertexts
- ✅ Diffusion: Kleine Änderungen im Plaintext → große Änderungen im Ciphertext
- ✅ Pseudorandom: Ciphertext sieht aus wie Zufallsdaten
- ❌ KEINE Distanz-Erhaltung:
distance(P1, P2) ≠ distance(E(P1), E(P2))
Resultat: Verschlüsselte Vektoren können NICHT für Distanzberechnungen verwendet werden!
Konzept: Berechnungen auf verschlüsselten Daten durchführen
# Homomorphic Encryption erlaubt Berechnungen auf Ciphertext
enc_vec1 = HE_encrypt(vec1, public_key)
enc_vec2 = HE_encrypt(vec2, public_key)
# Distanzberechnung auf verschlüsselten Vektoren
enc_distance = HE_cosine_similarity(enc_vec1, enc_vec2)
# Entschlüssele nur das Ergebnis
distance = HE_decrypt(enc_distance, private_key)Vorteile:
- ✅ Vektoren bleiben verschlüsselt während der Suche
- ✅ HNSW-Index kann auf verschlüsselten Daten operieren
- ✅ Zero-Knowledge Search (Server sieht keine Plaintext-Vektoren)
Nachteile:
- ❌ 100-1000x langsamer als Plaintext
- ❌ 10-100x größere Daten (Ciphertext-Expansion)
- ❌ Komplexe Implementierung (6-12 Monate)
- ❌ Begrenzte Operationen (nicht alle Distanzmetriken unterstützt)
Praktikabilität:
Konzept: Verschlüsselung erhält Ordnung
# OPE erhält die Ordnung von Werten
a = 10
b = 20
c = 30
enc_a = OPE_encrypt(a, key) # z.B. 1543
enc_b = OPE_encrypt(b, key) # z.B. 2871
enc_c = OPE_encrypt(c, key) # z.B. 4209
# Ordnung bleibt erhalten
assert enc_a < enc_b < enc_c # ✅ TrueFür Vektoren:
⚠️ Funktioniert NICHT direkt für Cosine Similarity⚠️ Nur für 1D-Ordnungen, nicht für Distanzen in hochdimensionalen Räumen- ❌ Sicherheitslücken: Ordnung verrät Information über Daten
Praktikabilität: ❌ NICHT geeignet für HNSW-Vektorsuche
Konzept: Spezielle Datenstrukturen für verschlüsselte Suche
# SSE für Keyword-Suche (z.B. verschlüsselte Inverted Indizes)
encrypted_index = SSE_build(documents, key)
# Suche mit verschlüsseltem Query
enc_query = SSE_query("diabetes", key)
results = SSE_search(encrypted_index, enc_query)Für Vektoren:
⚠️ Funktioniert NICHT für k-NN Suche⚠️ Nur für exakte Matches, nicht für Ähnlichkeitssuche- ❌ NICHT anwendbar auf HNSW
Praktikabilität: ❌ NICHT geeignet für Vektorsuche
Architektur:
┌─────────────────────────────────────────────────┐
│ Disk (At-Rest) │
│ - Vektoren: AES-256-GCM verschlüsselt │
│ - HNSW-Index: AES-256-GCM verschlüsselt │
│ - Nicht durchsuchbar ❌ │
└───────────────────┬─────────────────────────────┘
│
▼ Decrypt beim Laden
┌─────────────────────────────────────────────────┐
│ Memory/VRAM │
│ - Vektoren: Plaintext (entschlüsselt) │
│ - HNSW-Index: Plaintext Graph-Struktur │
│ - Durchsuchbar ✅ │
│ - Performance: O(log n) wie normal │
└───────────────────┬─────────────────────────────┘
│
▼ HNSW-Suche
┌─────────────────────────────────────────────────┐
│ Search Results │
│ - k nächste Nachbarn gefunden │
└─────────────────────────────────────────────────┘
class HybridVectorSearch {
public:
// Initialisierung: Lade verschlüsselten Index
void initialize() {
// 1. Lade verschlüsselte Vektoren von Disk
auto encrypted_vectors = loadEncryptedVectorsFromDisk();
// 2. Entschlüssele in Memory
std::vector<std::vector<float>> plaintext_vectors;
for (auto& enc_vec : encrypted_vectors) {
auto plaintext = decrypt(enc_vec); // AES-256-GCM Decrypt
plaintext_vectors.push_back(plaintext);
}
// 3. Baue/Lade HNSW-Index auf Plaintext-Vektoren
if (hasPersistedHNSWIndex()) {
// Option A: Lade verschlüsselten HNSW-Index
auto enc_index = loadEncryptedHNSWIndex();
hnsw_index_ = decryptHNSWIndex(enc_index); // Decrypt in Memory
} else {
// Option B: Rebuild HNSW von entschlüsselten Vektoren
hnsw_index_ = buildHNSWIndex(plaintext_vectors);
}
Logger::info("HNSW index ready for search (plaintext in memory)");
}
// Suche: Funktioniert nur auf entschlüsselten Daten
std::vector<SearchResult> search(const std::vector<float>& query, size_t k) {
// HNSW-Suche auf Plaintext-Vektoren (schnell!)
return hnsw_index_->searchKnn(query, k);
// Performance: O(log n) wie normal, keine Degradation
}
private:
std::unique_ptr<HNSWIndex> hnsw_index_; // Plaintext in Memory
};At-Rest (Disk):
- ✅ Vektoren verschlüsselt (BSI C5 CRY-03 konform)
- ✅ HNSW-Index verschlüsselt (optional, empfohlen)
- ❌ NICHT durchsuchbar (ist OK, da nicht benötigt)
In-Memory (VRAM):
- ✅ Vektoren im Plaintext (entschlüsselt)
- ✅ HNSW-Index im Plaintext (Graph-Struktur)
- ✅ DURCHSUCHBAR mit voller Performance
⚠️ Angreifer benötigt Memory-Zugriff (physisch/Kernel-Level)
Sicherheit:
- At-Rest geschützt: ✅ (Disk-Compromise → Ciphertext nur)
- In-Transit geschützt: ✅ (TLS 1.3)
- In-Memory:
⚠️ (akzeptiertes Risiko, unvermeidbar für Performance)
| Operation | Plaintext HNSW | Verschlüsselt (Disk) → Plaintext (Memory) | Homomorphic Encryption |
|---|---|---|---|
| Index-Laden | 2 sec | 5 sec (+3s Decrypt) | N/A |
| Suche (1 Query) | 1 ms | 1 ms (gleich!) | 100-1000 ms |
| Durchsatz | 1000 QPS | 1000 QPS | 1-10 QPS |
| At-Rest Sicherheit | ❌ Keine | ✅ AES-256-GCM | ✅ HE |
| In-Memory Sicherheit | ❌ Keine | ❌ Plaintext | ✅ Encrypted |
| Praktikabel | ✅ Ja | ✅ Ja | ❌ Nein (zu langsam) |
Fazit: Hybrid-Ansatz ist der einzige praktikable Ansatz für produktive Systeme.
Szenario 1: Plaintext HNSW (keine Verschlüsselung)
├─ Index-Laden: 2 sec
├─ Suche (k=10): 1 ms
└─ At-Rest: ❌ Unsicher
Szenario 2: Hybrid (empfohlen)
├─ Index-Laden: 5 sec (+3s Decrypt)
├─ Suche (k=10): 1 ms (gleich!)
└─ At-Rest: ✅ AES-256-GCM
Szenario 3: Homomorphic Encryption (theoretisch)
├─ Index-Laden: 2 sec
├─ Suche (k=10): 500 ms (500x langsamer!)
└─ At-Rest: ✅ HE-verschlüsselt
└─ Praktikabel: ❌ NEIN (zu langsam)
❌ NEIN - AES-Ciphertext hat keine Distanz-Eigenschaften
# Beispiel mit echten Werten
vec1 = [0.1, 0.2, 0.3]
vec2 = [0.11, 0.21, 0.31] # Sehr ähnlich zu vec1
# Plaintext Cosine Similarity
similarity_plain = cosine(vec1, vec2) # ~0.9999 (sehr ähnlich)
# Verschlüsselt
enc_vec1 = AES_encrypt(vec1, key) # [0x8f3a, 0x2d4b, ...]
enc_vec2 = AES_encrypt(vec2, key) # [0x1c7b, 0x99e5, ...]
# "Similarity" auf Ciphertext
similarity_enc = cosine(enc_vec1, enc_vec2) # ~0.03 (komplett anders!)
# ❌ Falsch!Grund: AES ist designed um Muster zu verbergen, nicht zu erhalten!
# Deterministisches Encryption (KEIN IV/Nonce)
vec = [0.1, 0.2, 0.3]
enc1 = DET_encrypt(vec, key) # Immer gleiches Ciphertext
enc2 = DET_encrypt(vec, key) # Gleiches Ciphertext
# Problem: Angreifer sieht gleiche Ciphertexte
# → Weiß dass Vektoren identisch sind
# → Pattern Leakage!BSI C5: ❌ NICHT konform (verletzt Uniqueness-Regel für GCM)
✅ Funktioniert, aber mit Nachteilen:
Filesystem-Encryption (dm-crypt, BitLocker):
├─ At-Rest: ✅ Verschlüsselt
├─ In-Memory: ❌ Plaintext (wie immer)
├─ Granularität: ❌ Alles-oder-nichts
├─ Key-Rotation: ❌ Schwierig (gesamte Partition)
└─ Cloud: ⚠️ S3-Backups benötigen separate Encryption
Empfehlung: Nutze Filesystem-Encryption zusätzlich zu Application-Level (Defense-in-Depth)
Frage 1: "Ist ein symmetrisch verschlüsselter HNSW durchsuchbar?"
Antwort: ❌ NEIN - AES-Ciphertext kann nicht für Distanzberechnungen verwendet werden.
Frage 2: "Wie mache ich HNSW sicher UND durchsuchbar?"
Antwort: ✅ Hybrid-Ansatz - At-Rest verschlüsselt, In-Memory Plaintext (wie dokumentiert).
Frage 3: "Gibt es Alternativen?"
Antwort:
┌──────────────────────────────────────────┐
│ EMPFOHLENE ARCHITEKTUR │
├──────────────────────────────────────────┤
│ 1. Disk: AES-256-GCM verschlüsselt │
│ - Vektoren: Encrypted │
│ - HNSW-Index: Encrypted │
│ - Nicht durchsuchbar (ist OK) │
│ │
│ 2. Memory: Plaintext (entschlüsselt) │
│ - HNSW-Index: Plaintext Graph │
│ - Durchsuchbar & performant │
│ - Angriff benötigt Memory-Zugriff │
│ │
│ 3. Search: O(log n) wie normal │
│ - Keine Performance-Degradation │
│ - BSI C5 konform (Memory-Risk OK) │
└──────────────────────────────────────────┘
- ✅ Akzeptiere: Verschlüsselte Vektoren sind NICHT direkt durchsuchbar
- ✅ Implementiere: Hybrid-Ansatz (wie in SYMMETRIC_ENCRYPTION_APPROACHES.md)
- ✅ Dokumentiere: Memory-Risiko als akzeptiert (BSI C5-konform)
⚠️ Optional: Untersuche HE für Ultra-High-Security Use-Cases (12+ Monate)
Forschung zu Encrypted Search:
- "Searchable Encryption Revisited" (Song et al., 2000)
- "Fully Homomorphic Encryption" (Gentry, 2009)
- "Order-Preserving Encryption" (Boldyreva et al., 2009)
- "Secure Nearest Neighbor Queries over Encrypted Data" (Yiu et al., 2010)
Praktische Limitationen:
- HE für Vektorsuche: 100-1000x Overhead (Stand 2025)
- OPE: Sicherheitslücken, nicht für k-NN geeignet
- SSE: Nur für exakte Matches, nicht Ähnlichkeit
Konsens: Hybrid-Ansatz (At-Rest Encrypted, In-Memory Plaintext) ist state-of-the-art für produktive HNSW-Indizes.
Erstellt: 15. Dezember 2025
Status: Technische Klärung abgeschlossen
Fazit: Symmetrisch verschlüsselter HNSW ist NICHT direkt durchsuchbar - Hybrid-Ansatz ist die Lösung