import base64 import json import os from cryptography.hazmat.primitives.ciphers.aead import AESGCM def _key() -> bytes: b64 = os.environ.get("LYRA_SECRET_KEY") if not b64: raise RuntimeError("LYRA_SECRET_KEY is not set") k = base64.b64decode(b64) if len(k) != 32: raise RuntimeError("LYRA_SECRET_KEY must decode to 32 bytes") return k def encrypt_secret(plaintext: str) -> str: iv = os.urandom(12) full = AESGCM(_key()).encrypt(iv, plaintext.encode("utf-8"), None) # ct || tag(16) ct, tag = full[:-16], full[-16:] return json.dumps( { "iv": base64.b64encode(iv).decode(), "ct": base64.b64encode(ct).decode(), "tag": base64.b64encode(tag).decode(), } ) def decrypt_secret(envelope: str) -> str: e = json.loads(envelope) iv = base64.b64decode(e["iv"]) ct = base64.b64decode(e["ct"]) tag = base64.b64decode(e["tag"]) pt = AESGCM(_key()).decrypt(iv, ct + tag, None) # AESGCM expects ct || tag return pt.decode("utf-8")