feat(F2): AES-256-CTR encryption module for recordings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Aaron D. Lee
2026-04-03 17:39:40 -04:00
parent 0544f7218a
commit f8d28cf78e
2 changed files with 101 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
"""AES-256-CTR encryption for recording files."""
import os
from collections.abc import Generator
from pathlib import Path
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
CHUNK_SIZE = 64 * 1024 # 64KB
def encrypt_file(plain_path: str, key_hex: str) -> str:
key = bytes.fromhex(key_hex)
iv = os.urandom(16)
cipher = Cipher(algorithms.AES(key), modes.CTR(iv))
encryptor = cipher.encryptor()
vge_path = Path(plain_path).with_suffix(".vge")
with open(plain_path, "rb") as src, open(vge_path, "wb") as dst:
dst.write(iv)
while True:
chunk = src.read(CHUNK_SIZE)
if not chunk:
break
dst.write(encryptor.update(chunk))
dst.write(encryptor.finalize())
Path(plain_path).unlink()
return str(vge_path)
def decrypt_stream(vge_path: str, key_hex: str) -> Generator[bytes, None, None]:
key = bytes.fromhex(key_hex)
with open(vge_path, "rb") as f:
iv = f.read(16)
cipher = Cipher(algorithms.AES(key), modes.CTR(iv))
decryptor = cipher.decryptor()
while True:
chunk = f.read(CHUNK_SIZE)
if not chunk:
break
yield decryptor.update(chunk)
final = decryptor.finalize()
if final:
yield final