38 lines
1.0 KiB
Python
38 lines
1.0 KiB
Python
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")
|