-
Notifications
You must be signed in to change notification settings - Fork 1
security_multi_party
Stand: 5. Dezember 2025
Version: v1.3.0
Kategorie: 🔒 Security
- Problem Statement
- Lösung 1: Gruppenbasierte Schlüssel (Group-KEK)
- Lösung 2: Envelope-Encryption (Multi-Recipient)
Anforderung: Mehrere Personen/Rollen/Gruppen/Abteilungen/Behörden müssen dieselben verschlüsselten Daten lesen und schreiben können, ohne dass:
- Jeder Nutzer einen eigenen verschlüsselten Datensatz erhält (Storage-Explosion)
- Daten bei Gruppen-Änderung re-encrypted werden müssen (Performance)
- Ein zentraler Admin alle Daten entschlüsseln kann (Zero-Trust verletzt)
Beispiel-Szenarien:
-
HR-Abteilung: Alle Mitarbeiter von
hr_teamkönnen Gehalts-Daten lesen/schreiben - Projekt-Team: Alle Mitglieder von Projekt "Apollo" können Projektdokumente bearbeiten
- Behörden-übergreifend: Polizei, Staatsanwaltschaft, Gericht können Ermittlungsakte teilen
-
Rollenbasiert: Alle mit Rolle
doctorkönnen Patientenakten lesen
┌────────────────────────────────────────────────┐
│ VCC-PKI Root CA │
│ └── Service Cert (themis-db.vcc.local) │
└─────────────────┬──────────────────────────────┘
│ verschlüsselt
▼
┌────────────────────────────────────────────────┐
│ Master KEK (Key Encryption Key) │
│ - Pro ThemisDB-Instanz │
│ - Verschlüsselt mit PKI-Zertifikat │
└─────────────────┬──────────────────────────────┘
│ verschlüsselt
▼
┌────────────────────────────────────────────────┐
│ Gruppen-DEKs (Data Encryption Keys) │
│ - Pro Gruppe/Rolle/Abteilung (z.B. "hr_team") │
│ - Gespeichert als: "key:group:hr_team" │
│ - Verschlüsselt mit Master KEK │
└─────────────────┬──────────────────────────────┘
│ verschlüsselt
▼
[Shared Encrypted Data]
// include/security/group_key_manager.h
class GroupKeyManager {
public:
// Erstelle oder lade DEK für eine Gruppe
std::vector<uint8_t> getGroupDEK(const std::string& group_name);
// Rotiere Gruppen-Key (bei Mitglieder-Austritt)
void rotateGroupKey(const std::string& group_name);
// Prüfe ob User Zugriff auf Gruppe hat (via JWT)
bool hasGroupAccess(const JWTClaims& claims, const std::string& group_name);
private:
std::vector<uint8_t> master_kek_; // Von PKI abgeleitet
std::unordered_map<std::string, std::vector<uint8_t>> group_deks_; // Cache
};// Bei jedem Schreibvorgang
std::string jwt_token = request.get_header("Authorization");
auto claims = jwt_validator_->parseAndValidate(jwt_token);
// Bestimme zuständige Gruppe aus JWT oder Schema
std::string group = determineDataOwnerGroup(claims, field_schema);
// z.B. "hr_team" aus claims.groups[0] oder Schema-Annotation
// Hole Gruppen-DEK (gecacht, verschlüsselt in DB)
auto group_dek = group_key_mgr_->getGroupDEK(group);
// Leite Field-Key ab
auto field_key = HKDF_SHA256(
group_dek,
salt = field_name,
info = "field-encryption:" + group
);
// Verschlüsseln
auto ciphertext = AES_GCM_encrypt(plaintext, field_key, nonce);
// Metadaten speichern (für Entschlüsselung)
entity.setField("salary_encrypted", base64(ciphertext));
entity.setField("salary_group", group); // "hr_team"// Bei jedem Lesevorgang
auto encrypted_salary = entity.getField("salary_encrypted");
auto data_group = entity.getField("salary_group").as<std::string>();
// Prüfe ob aktueller User Zugriff hat
if (!group_key_mgr_->hasGroupAccess(claims, data_group)) {
throw UnauthorizedException("User not member of group: " + data_group);
}
// Hole Gruppen-DEK
auto group_dek = group_key_mgr_->getGroupDEK(data_group);
// Leite Field-Key ab (gleich wie beim Verschlüsseln)
auto field_key = HKDF_SHA256(group_dek, salt = "salary", info = "field-encryption:" + data_group);
// Entschlüsseln
auto plaintext = AES_GCM_decrypt(base64_decode(encrypted_salary), field_key, nonce);✅ Shared Access: Alle Gruppenmitglieder nutzen denselben DEK
✅ Keine Daten-Duplizierung: Ein verschlüsselter Datensatz für alle
✅ Skalierbar: Gruppenmitgliedschaft über JWT-Claims (Keycloak)
✅ Zero-Trust: Admin ohne Gruppenmitgliedschaft kann nicht entschlüsseln
[Plaintext Data]
│
│ verschlüsselt mit
▼
┌─────────────────────┐
│ Data Encryption │ ← Zufälliger DEK pro Datensatz
│ Key (DEK) │ (AES-256, 32 Bytes)
└─────────────────────┘
│
│ wird verschlüsselt für jeden Empfänger
▼
┌──────────────────────────────────────────┐
│ Wrapped Keys (einer pro Empfänger): │
│ - DEK_wrapped_alice (RSA/AES für Alice)│
│ - DEK_wrapped_bob (RSA/AES für Bob) │
│ - DEK_wrapped_hr (für Gruppe hr) │
└──────────────────────────────────────────┘
// Pro verschlüsseltem Feld: Speichere multiple wrapped DEKs
struct EncryptedField {
std::string ciphertext; // Mit DEK verschlüsselte Daten
std::string nonce; // IV/Nonce für AES-GCM
// Pro authorisierter Gruppe/User: wrapped DEK
std::map<std::string, std::string> wrapped_keys;
// z.B. {"hr_team": "base64(RSA_encrypt(DEK, hr_pubkey))",
// "admin_group": "base64(RSA_encrypt(DEK, admin_pubkey))"}
};
// Beim Verschlüsseln
std::vector<uint8_t> dek = random_bytes(32); // Zufälliger DEK
auto ciphertext = AES_GCM_encrypt(plaintext, dek, nonce);
// Wrap DEK für jede autorisierte Gruppe
for (const auto& group : authorized_groups) {
auto group_pubkey = getGroupPublicKey(group);
auto wrapped_dek = RSA_encrypt(dek, group_pubkey);
field.wrapped_keys[group] = base64(wrapped_dek);
}
// Beim Entschlüsseln
auto user_group = claims.groups[0]; // Erste Gruppe des Users
if (!field.wrapped_keys.contains(user_group)) {
throw UnauthorizedException("No key for your group");
}
auto group_privkey = getGroupPrivateKey(user_group); // Aus KMS/HSM
auto dek = RSA_decrypt(base64_decode(field.wrapped_keys[user_group]), group_privkey);
auto plaintext = AES_GCM_decrypt(field.ciphertext, dek, field.nonce);✅ Feingranular: Zugriff pro Feld konfigurierbar
✅ Einfache Zugriffsänderung: Neuen Empfänger hinzufügen = neuen wrapped key hinzufügen (kein Re-Encrypt der Daten)
✅ User-Austritt sicher: Wrapped key löschen → kein Zugriff mehr
Kombination aus Gruppen-DEKs (Lösung 1) für Standard-Zugriff und Envelope-Encryption (Lösung 2) für feingranulare Freigaben.
{
"salary": {
"ciphertext": "...",
"encryption_group": "hr_team",
"encryption_type": "group-dek"
}
}Alle hr_team-Mitglieder können lesen/schreiben.
{
"classified_document": {
"ciphertext": "...",
"encryption_type": "envelope",
"wrapped_keys": {
"police_dept": "...",
"prosecutors_office": "...",
"court_judges": "..."
}
}
}Nur diese drei Behörden können lesen.
// BaseEntity erweitern für Encryption-Metadaten
class EncryptedFieldMetadata {
public:
enum class Type {
NONE, // Unverschlüsselt
GROUP_DEK, // Gruppen-basiert (Lösung 1)
ENVELOPE // Multi-Recipient (Lösung 2)
};
Type type;
std::string encryption_group; // Für GROUP_DEK
std::map<std::string, std::string> wrapped_keys; // Für ENVELOPE
std::string algorithm = "AES-256-GCM";
std::string nonce; // Base64
};Aktuell (BaseEntity):
key: users:alice
value: {
"pk": "users:alice",
"name": "Alice",
"email": "alice@vcc.local"
}
Mit Group-Encryption:
key: users:alice
value: {
"pk": "users:alice",
"name": "Alice",
"salary_encrypted": "base64_ciphertext",
"salary_group": "hr_team",
"salary_nonce": "base64_nonce"
}
Mit Envelope-Encryption:
key: users:alice
value: {
"pk": "users:alice",
"name": "Alice",
"ssn_encrypted": "base64_ciphertext",
"ssn_encryption_type": "envelope",
"ssn_nonce": "base64_nonce",
"ssn_wrapped_keys": {
"hr_team": "base64_wrapped_dek",
"audit_team": "base64_wrapped_dek"
}
}
# Gruppen-DEKs (verschlüsselt mit Master KEK)
key:group:hr_team → encrypted_dek (32 bytes AES key, encrypted)
key:group:finance_dept → encrypted_dek
key:group:admin → encrypted_dek
# Gruppen-Membership-Cache (optional, für Performance)
key:group:hr_team:members → ["alice", "bob", "charlie"]
# Audit-Log für Key-Rotation
key:group:hr_team:history → [
{"version": 1, "created": 1730000000, "rotated": 1730100000},
{"version": 2, "created": 1730100000, "active": true}
]
-
✅ PKIKeyProvider erweitern
-
getGroupDEK(group_name)→ lädt/erstellt verschlüsselte DEKs -
rotateGroupKey(group_name)→ erstellt neuen DEK, markiert alten als deprecated
-
-
JWT-Claims-Mapping
-
JWTValidatorextrahiertgroups/rolesaus Token -
AuthMiddlewareprüft Gruppenmitgliedschaft
-
-
Schema-Annotation
{ "fields": { "salary": { "type": "int64", "encrypted": true, "encryption_group": "hr_team" } } } -
QueryEngine-Integration
- Bei INSERT/UPDATE: Verschlüssele mit Gruppen-DEK
- Bei SELECT: Prüfe Gruppenmitgliedschaft, entschlüssele mit Gruppen-DEK
-
KMS-Integration (für Gruppen-Keypairs)
- Generiere RSA-Keypair pro Gruppe
- Speichere Private Keys in HSM/KMS oder verschlüsselt in DB
-
Envelope-Wrapping
- Implementiere
EnvelopeEncryptionKlasse - Wrap/Unwrap DEKs mit RSA/ECIES
- Implementiere
-
API-Erweiterung
POST /api/v1/data/share { "document_id": "doc123", "grant_access_to": ["police_dept", "prosecutors_office"] }
Für VCC-Kontext:
-
Start mit Gruppen-DEK (Lösung 1)
- Nutze bestehende Keycloak-Gruppen (
hr_team,finance_dept, etc.) - Mappt gut auf Behörden-Struktur (Abteilungen, Ämter)
- Wenig Storage-Overhead
- Nutze bestehende Keycloak-Gruppen (
-
Später Envelope für Sonderfälle (Lösung 2)
- Wenn behördenübergreifende Ad-hoc-Freigaben nötig
- Wenn feingranulare Zugriffskontrolle auf Feld-Ebene gefordert
-
DB-Änderungen minimal
- Nur Metadaten-Felder hinzufügen (
*_encrypted,*_group,*_nonce) - Keine Breaking Changes für unverschlüsselte Felder
- Rückwärtskompatibel:
encrypted=false→ wie bisher
- Nur Metadaten-Felder hinzufügen (
Nächster Schritt:
Soll ich die Gruppen-DEK-Implementierung prototypisch in PKIKeyProvider ergänzen?
- Architecture-ACCESS-MODEL-IMPLEMENTATION-SUMMARY
- Architecture-ADR-003-pg-dump-sql-parser
- Architecture-BASEENTITY-PRINCIPLE
- Architecture-CACHE-STORAGE-INTEGRATION
- Architecture-CMAKE-ARCHITECTURE
- Architecture-CMAKE-FLAGS-REFERENCE
- Architecture-CMAKE-MODULAR-ARCHITECTURE
- Architecture-CONCERNS-ARCHITECTURE-DIAGRAM
- Architecture-CONCERNS-IMPLEMENTATION-SUMMARY
- Architecture-CONTENT-MODEL
- Architecture-COPILOT-THEMISDB-GRAPH-RAG-BACKEND-ARCHITECTURE
- Architecture-CRYPTO-AND-KEYS
- Architecture-FEATURE-FLAGS-REFERENCE
- Architecture-GPU-ARCHITECTURE-REVIEW-TEMPLATE
- Architecture-HTTP-SHUTDOWN-HARDENING
- Architecture-MIGRATION-GUIDE-CONCERNS
- Architecture-MIGRATION-GUIDE-v13-v14
- Architecture-MODULARIZATION-GUIDE
- Architecture-MODULAR-ARCHITECTURE-ROADMAP
- Architecture-MODULE-ARCHITECTURE-INDEX
- Architecture-P1D01-ISSMPLUGIN-DESIGN-REVIEW
- Architecture-P1-D01-ISSMPLUGIN-DESIGN-REVIEW
- Architecture-P1-D08-MAMBA-GOVERNANCE-CONTRACT
- Architecture-P1-P2-IMPLEMENTATION-COMPLETION-INDEX
- Architecture-PHASE0-COMPLETION-ASSESSMENT
- Architecture-PHASE3-QUERYENGINE-DI-ARCHITECTURE
- Architecture-PHASE4-INDEX-MANAGER-DI
- Architecture-POSTGRESQL-WIRE-PROTOCOL
- Architecture-QUERYENGINE-IMPLEMENTATION-GUIDE
- Architecture-QUERY-SCHEDULING
- Architecture-RAFT-CONSENSUS-DESIGN
- Architecture-README
- Architecture-README-SSM-HYBRID-IMPLEMENTATION
- Architecture-REFACTORING-SUMMARY
- Architecture-RESOURCE-POOLING
- Architecture-SOURCE-DIRECTORY-GUIDE
- Architecture-THEMIS-CORE-GUIDE
- Architecture-UNIFIED-ACCESS-MODEL
- Architecture-WAL-GRPC-MTLS-CONFIGURATION
- Architecture-WIRE-PROTOCOL-RETRY
- Architecture-boltzmann-observability-draft
- Architecture-experimental-logarithmic-vector-storage
- Architecture-llm-wiki-mvp-adr
- Architecture-rewrite-engine-architecture
- Architecture-rope-api-architecture
- Architecture-ssm-gguf-mamba-status
- Architecture-ssm-hybrid-analysis
- Architecture-ssm-hybrid-rollout-plan
- Architecture-ssm-plugin-interface-design-review
- Architecture-transaction-coordinators
- Architecture-wiki-secondary-index
- Architecture-wire-protocol
- Governance-DISABLED-STUB-POLICY
- Governance-DOCS-PR-POLICY
- Governance-GA-PROMOTION-SIGN-OFF
- Governance-GITHUB-MILESTONES-SETUP
- Governance-MATURITY-CLAIM-VERIFICATION-CHECKLIST
- Governance-MATURITY-EVIDENCE-REGISTRY
- Governance-MERGE-GATE-BOT-CONFIG
- Governance-MERGE-GATE-STATUS-LIVE
- Governance-PHASE3-ENFORCEMENT-RUNBOOK
- Governance-PHASE-1-CLOSURE-REPORT
- Governance-PHASE-CLOSURE-POLICY
- Governance-PHASE-DEPENDENCY-GRAPH
- Governance-PLUGIN-SUBMODULE-ROLLBACK
- Governance-PRODUCTION-READY-2026-DELIVERY-PLAN
- Governance-PR-VERSION-TARGETING
- Governance-PR-VERSION-TARGETING-BACKFILL
- Governance-QUERY-MODULE-STATUS
- Governance-README
- Governance-RELEASE-PROMOTION-GATE-POLICY
- Governance-RELEASE-VALIDATION-CHECKLIST
- Governance-SECURITY-MODULE-5671-EVIDENCE-SUMMARY
- Governance-SHARDING-P6-RESIDUAL-RISK-ACCEPTANCE
- Governance-SOURCECODE-COMPLIANCE-GOVERNANCE
- Governance-UPDATES-DEVELOPMENT-STATUS-SIGN-OFF
- Governance-WAVE-C-IMPLEMENTATION-COMPLETE
- Module-acceleration-Roadmap
- Module-access-model-Roadmap
- Module-ai-Roadmap
- Module-analytics-Roadmap
- Module-api-Roadmap
- Module-aql-Roadmap
- Module-auth-Roadmap
- Module-base-Roadmap
- Module-cache-Roadmap
- Module-cdc-Roadmap
- Module-chaos-Roadmap
- Module-chimera-Roadmap
- Module-config-Roadmap
- Module-content-Roadmap
- Module-core-Roadmap
- Module-distributed-knowledge-Roadmap
- Module-distributed-tensor-Roadmap
- Module-document-Roadmap
- Module-ethics-ai-Roadmap
- Module-evaluation-Roadmap
- Module-execution-Roadmap
- Module-exporters-Roadmap
- Module-failover-Roadmap
- Module-geo-Roadmap
- Module-governance-Roadmap
- Module-gpu-Roadmap
- Module-graph-Roadmap
- Module-image-analysis-Roadmap
- Module-importers-Roadmap
- Module-index-Roadmap
- Module-ingestion-Roadmap
- Module-llama-cpp-Roadmap
- Module-llm-Roadmap
- Module-llm-streaming-Roadmap
- Module-llm-wiki-Roadmap
- Module-maintenance-Roadmap
- Module-metadata-Roadmap
- Module-network-Roadmap
- Module-observability-Roadmap
- Module-onnx-clip-Roadmap
- Module-performance-Roadmap
- Module-plugins-Roadmap
- Module-process-Roadmap
- Module-projects-Roadmap
- Module-prompt-engineering-Roadmap
- Module-query-Roadmap
- Module-rag-Roadmap
- Module-replication-Roadmap
- Module-retrieval-Roadmap
- Module-rpc-grpc-Roadmap
- Module-scheduler-Roadmap
- Module-scraper-Roadmap
- Module-search-Roadmap
- Module-security-Roadmap
- Module-server-Roadmap
- Module-sharding-Roadmap
- Module-stable-diffusion-Roadmap
- Module-storage-Roadmap
- Module-temporal-Roadmap
- Module-tensor-Roadmap
- Module-themis-Roadmap
- Module-timeseries-Roadmap
- Module-toolbox-Roadmap
- Module-training-Roadmap
- Module-transaction-Roadmap
- Module-updates-Roadmap
- Module-user-storage-encrypted-Roadmap
- Module-utils-Roadmap
- Module-vector-search-Roadmap
- Module-voice-Roadmap
- Module-whisper-Roadmap