import hashlib import base64 import os from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC # --- CORE LOGIC: THE TWIN KEY GENERATOR --- def generate_keys(group_name: str, password: str) -> tuple[str, str]: """ Generates two distinct values from the inputs: 1. encryption_key: Used to lock/unlock the data (Fernet). 2. blind_index: Used to find the data in the database. Why separate them? If the DB is hacked, they see the 'blind_index'. They cannot reverse-engineer the 'encryption_key' from the index easily. """ # 1. Use the group_name as the Salt. # This ensures "ProjectX" generates different keys than "ProjectY". salt = group_name.encode() # 2. Derive a 32-byte Master Key from the password kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, ) master_key_bytes = kdf.derive(password.encode()) # 3. Create the Fernet Key (Base64 encoded version of master key) encryption_key = base64.urlsafe_b64encode(master_key_bytes) # 4. Create the Blind Index (Hash of the master key) # We hash the key again so the database admin sees a hash, # but not the actual key used for decryption. blind_index = hashlib.sha256(master_key_bytes).hexdigest() return encryption_key, blind_index