import hmac
import hashlib
import base64
from cryptography.fernet import Fernet
from app.config import settings
def sign_payload(payload: str) -> str:
"""Signs a string payload using HMAC-SHA256."""
return hmac.new(settings.SECRET_KEY.encode(), payload.encode(), hashlib.sha256).hexdigest()
def sign_bytes(data: bytes) -> str:
"""Signs bytes using HMAC-SHA256."""
return hmac.new(settings.SECRET_KEY.encode(), data, hashlib.sha256).hexdigest()
def verify_signature(payload: str, signature: str) -> bool:
"""Verifies a signature against a payload using HMAC-SHA256."""
expected = sign_payload(payload)
return hmac.compare_digest(signature, expected)
def verify_bytes_signature(data: bytes, signature: str) -> bool:
"""Verifies a signature against bytes using HMAC-SHA256."""
expected = sign_bytes(data)
return hmac.compare_digest(signature, expected)
def get_fernet() -> Fernet:
"""Derives a Fernet key from the system SECRET_KEY."""
key = base64.urlsafe_b64encode(hashlib.sha256(settings.SECRET_KEY.encode()).digest())
return Fernet(key)
def encrypt_value(value: str) -> str:
"""Encrypts a string value and returns it with an ENC() wrapper."""
if not value or value == "***": return value
try:
f = get_fernet()
token = f.encrypt(value.encode()).decode()
return f"ENC({token})"
except Exception:
return value
def decrypt_value(enc_value: str) -> str:
"""Decrypts a value if it is wrapped in ENC(), otherwise returns as-is."""
if not isinstance(enc_value, str) or not enc_value.startswith("ENC("):
return enc_value
token = enc_value[4:-1]
try:
f = get_fernet()
return f.decrypt(token.encode()).decode()
except Exception:
return enc_value