# 数据库字段加密(AES-256-GCM)。与 app.core.crypto 的接口报文加密相互独立。 import base64 import os from cryptography.hazmat.primitives.ciphers.aead import AESGCM from fastapi import HTTPException, status from app.core.config import get_settings _DETAIL = "字段加密未配置" def _fail() -> None: raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=_DETAIL) def _key() -> bytes: raw = "".join(get_settings().field_aes_key.split()) if not raw: _fail() try: key = base64.b64decode(raw, validate=True) except Exception: _fail() if len(key) != 32: _fail() return key def encrypt_text(plain: str) -> str: if plain == "": return "" nonce = os.urandom(12) ciphertext = AESGCM(_key()).encrypt(nonce, plain.encode("utf-8"), None) return base64.b64encode(nonce + ciphertext).decode("ascii") def decrypt_text(token: str) -> str: if token == "": return "" try: raw = base64.b64decode(token, validate=True) if len(raw) < 13: raise ValueError("short") plain = AESGCM(_key()).decrypt(raw[:12], raw[12:], None) return plain.decode("utf-8") except HTTPException: raise except Exception: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="字段密文无法解密") from None