"""Fernet-based encryption service for sensitive fields. Key is read from the MIMIC_ENCRYPTION_KEY env var (Fernet base64-urlsafe 32-byte key). When the key is absent the service raises C2Disabled so callers can return 503. The key is never logged or returned in any response. """ from __future__ import annotations import os from cryptography.fernet import Fernet, InvalidToken class C2Disabled(Exception): """Raised when MIMIC_ENCRYPTION_KEY is not set.""" def _get_fernet() -> Fernet: key = os.environ.get("MIMIC_ENCRYPTION_KEY") if not key: raise C2Disabled("C2 disabled: MIMIC_ENCRYPTION_KEY not set") return Fernet(key.encode() if isinstance(key, str) else key) def encrypt(plaintext: str) -> str: """Encrypt *plaintext* and return a Fernet token (str).""" f = _get_fernet() return f.encrypt(plaintext.encode()).decode() def decrypt(ciphertext: str) -> str: """Decrypt a Fernet token and return the plaintext string.""" f = _get_fernet() try: return f.decrypt(ciphertext.encode()).decode() except InvalidToken as exc: raise ValueError("Invalid ciphertext") from exc __all__ = ["C2Disabled", "encrypt", "decrypt"]