import base64 import json import os from cryptography.hazmat.primitives.ciphers.aead import AESGCM from fastapi import HTTPException, status from app.core.config import get_settings def _key() -> bytes: settings = get_settings() raw = settings.api_payload_aes_key.strip() if not raw: raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="接口加密未配置") try: key = base64.b64decode(raw) except Exception: raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="接口加密未配置") if len(key) not in {16, 24, 32}: raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="接口加密未配置") return key def encrypt_json(payload: dict | list) -> dict: nonce = os.urandom(12) plain = json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode() ciphertext = AESGCM(_key()).encrypt(nonce, plain, None) return {"data": base64.b64encode(nonce + ciphertext).decode()} def decrypt_json(envelope: dict) -> dict | list: token = envelope.get("data") if not isinstance(token, str): raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="加密报文格式不正确") try: raw = base64.b64decode(token) plain = AESGCM(_key()).decrypt(raw[:12], raw[12:], None) return json.loads(plain) except HTTPException: raise except Exception: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="加密报文无法解密")