"""Field-level encryption using Fernet (AES-256).""" from __future__ import annotations from cryptography.fernet import Fernet _fernet: Fernet | None = None def get_fernet() -> Fernet: global _fernet if _fernet is None: from config import settings _fernet = Fernet(settings.encryption_key.encode()) return _fernet def encrypt(plaintext: str) -> str: """Encrypt plaintext string. Returns 'encrypted:'.""" token = get_fernet().encrypt(plaintext.encode()).decode() return f"encrypted:{token}" def decrypt(ciphertext: str) -> str: """Decrypt 'encrypted:' string. Returns plaintext.""" if not ciphertext.startswith("encrypted:"): return ciphertext # Not encrypted, return as-is token = ciphertext[len("encrypted:"):] return get_fernet().decrypt(token.encode()).decode() def is_encrypted(value: str) -> bool: return isinstance(value, str) and value.startswith("encrypted:")