rev / src /hm_api /crypto.py
LerinaOwO's picture
Upload 16 files
cce1f2d verified
Raw
History Blame Contribute Delete
2.53 kB
"""Lightweight local encryption helpers for credentials."""
from __future__ import annotations
import base64
import json
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from .config import CRED_DIR
SENSITIVE_KEYS = {"access", "refresh", "key", "token"}
KEY_FILE = CRED_DIR / ".kek"
def _get_kek() -> bytes:
CRED_DIR.mkdir(parents=True, exist_ok=True)
if KEY_FILE.exists():
with open(KEY_FILE, "rb") as f:
return f.read()
key = AESGCM.generate_key(bit_length=256)
with open(KEY_FILE, "wb") as f:
f.write(key)
os.chmod(KEY_FILE, 0o600)
return key
def _aes_gcm_encrypt(plaintext: str) -> dict[str, str]:
key = _get_kek()
aesgcm = AESGCM(key)
iv = os.urandom(12)
ct = aesgcm.encrypt(iv, plaintext.encode("utf-8"), None)
return {
"iv": base64.b64encode(iv).decode(),
"ct": base64.b64encode(ct).decode(),
}
def _aes_gcm_decrypt(blob: dict[str, str]) -> str:
key = _get_kek()
aesgcm = AESGCM(key)
iv = base64.b64decode(blob["iv"])
ct = base64.b64decode(blob["ct"])
return aesgcm.decrypt(iv, ct, None).decode("utf-8")
def encrypt_value(value: str) -> dict[str, str]:
return _aes_gcm_encrypt(value)
def decrypt_value(blob: dict[str, str]) -> str:
return _aes_gcm_decrypt(blob)
def encrypt_record(record: dict) -> dict:
result: dict = {}
for k, v in record.items():
if isinstance(v, str) and k in SENSITIVE_KEYS:
result[k] = encrypt_value(v)
else:
result[k] = v
return result
def decrypt_record(record: dict) -> dict:
result: dict = {}
for k, v in record.items():
if isinstance(v, dict) and "iv" in v and "ct" in v:
result[k] = decrypt_value(v)
else:
result[k] = v
return result
def load_auth_data() -> dict:
from .config import AUTH_FILE
if not AUTH_FILE.exists():
return {}
with open(AUTH_FILE, "r", encoding="utf-8") as f:
raw = json.load(f)
if not isinstance(raw, dict):
return {}
return {k: decrypt_record(v) if isinstance(v, dict) else v for k, v in raw.items()}
def save_auth_data(data: dict) -> None:
from .config import AUTH_FILE
CRED_DIR.mkdir(parents=True, exist_ok=True)
encrypted = {
k: encrypt_record(v) if isinstance(v, dict) else v for k, v in data.items()
}
with open(AUTH_FILE, "w", encoding="utf-8") as f:
json.dump(encrypted, f, indent=2)
os.chmod(AUTH_FILE, 0o600)