""" AES-256-GCM Cookie encryption / decryption utilities. """ import base64 import hashlib from Crypto.Cipher import AES def derive_key(raw_key: str) -> bytes: """Derive a 32-byte key from an arbitrary string using SHA-256.""" return hashlib.sha256(raw_key.encode("utf-8")).digest() def encrypt_cookie(plaintext: str, key: bytes) -> tuple[str, str]: """ Encrypt a cookie string with AES-256-GCM. Returns: (ciphertext_b64, iv_b64) — both base64-encoded strings. """ cipher = AES.new(key, AES.MODE_GCM) ciphertext, tag = cipher.encrypt_and_digest(plaintext.encode("utf-8")) # Append the 16-byte tag to the ciphertext so decryption can verify it ciphertext_with_tag = ciphertext + tag ciphertext_b64 = base64.b64encode(ciphertext_with_tag).decode("utf-8") iv_b64 = base64.b64encode(cipher.nonce).decode("utf-8") return ciphertext_b64, iv_b64 def decrypt_cookie(ciphertext_b64: str, iv_b64: str, key: bytes) -> str: """ Decrypt a cookie string previously encrypted with encrypt_cookie. Raises ValueError on decryption failure (wrong key, corrupted data, etc.). """ raw = base64.b64decode(ciphertext_b64) nonce = base64.b64decode(iv_b64) # Last 16 bytes are the GCM tag ciphertext, tag = raw[:-16], raw[-16:] cipher = AES.new(key, AES.MODE_GCM, nonce=nonce) plaintext = cipher.decrypt_and_verify(ciphertext, tag) return plaintext.decode("utf-8")