""" AES-256-GCM Verschluesselung fuer Secrets at rest (SSH-Private-Keys, TOTP-Secrets). Prinzip (siehe Konzept 6.4): Der Key-Encryption-Key (KEK) liegt NICHT in der Datenbank, sondern kommt aus app.config.settings (systemd-creds/Env). Jeder verschluesselte Datensatz erhaelt einen frischen, zufaelligen Nonce; Nonce + Ciphertext + Auth-Tag werden gemeinsam gespeichert. """ from __future__ import annotations import os from cryptography.hazmat.primitives.ciphers.aead import AESGCM from app.config import settings NONCE_LEN = 12 # 96 Bit, empfohlene GCM-Noncelaenge def encrypt_secret(plaintext: bytes, *, associated_data: bytes = b"") -> bytes: """Verschluesselt plaintext mit dem globalen KEK. Rueckgabe: nonce || ciphertext.""" aesgcm = AESGCM(settings.kek) nonce = os.urandom(NONCE_LEN) ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data or None) return nonce + ciphertext def decrypt_secret(blob: bytes, *, associated_data: bytes = b"") -> bytes: """Entschluesselt einen mit encrypt_secret() erzeugten Blob.""" aesgcm = AESGCM(settings.kek) nonce, ciphertext = blob[:NONCE_LEN], blob[NONCE_LEN:] return aesgcm.decrypt(nonce, ciphertext, associated_data or None)