The lifespan decrypts the key and compares a fixed sample (reserve/round pool addresses, the 10 lowest and highest user addresses, unrevealed round secrets) with the database, and refuses to serve on any mismatch without printing key material. The key scripts refuse a new or imported key that would not reproduce the stored addresses, and write 0600. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
34 lines
1.2 KiB
Python
34 lines
1.2 KiB
Python
import os
|
|
|
|
from cryptography.fernet import Fernet
|
|
|
|
from app.config import settings
|
|
|
|
|
|
def encrypt_xprv(xprv_base58: str) -> bytes:
|
|
return Fernet(settings.xprv_encryption_key).encrypt(xprv_base58.encode())
|
|
|
|
|
|
def decrypt_xprv(token: bytes) -> str:
|
|
return Fernet(settings.xprv_encryption_key).decrypt(token).decode()
|
|
|
|
|
|
def encrypt_round_seed(server_seed_hex: str) -> str:
|
|
"""B-73 (DAT-64, SEC-56): a round's secret encrypted at rest with the same key that
|
|
protects the master xprv, so a copy of the database alone never reveals it. The Fernet
|
|
token is ASCII, stored as text."""
|
|
return Fernet(settings.xprv_encryption_key).encrypt(server_seed_hex.encode()).decode()
|
|
|
|
|
|
def decrypt_round_seed(token: str) -> str:
|
|
return Fernet(settings.xprv_encryption_key).decrypt(token.encode()).decode()
|
|
|
|
|
|
def write_secret_file(path: str, data: bytes) -> None:
|
|
"""B-89 (SEC-50): created `0600` from the start (never through a wider mode) and
|
|
rewritten with the same mode, so a key file is not readable by other users."""
|
|
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
|
|
with os.fdopen(fd, "wb") as f:
|
|
os.fchmod(f.fileno(), 0o600)
|
|
f.write(data)
|