import base64 import os import secrets import string from typing import Tuple from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from app.core.config import settings def generate_random_key(length: int = 16) -> str: """Generate a random access key.""" alphabet = string.ascii_letters + string.digits return ''.join(secrets.choice(alphabet) for _ in range(length)) def derive_key(password: str, salt: bytes = None) -> Tuple[bytes, bytes]: """Derive a key from a password and salt using PBKDF2.""" if salt is None: salt = os.urandom(16) kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, ) key = base64.urlsafe_b64encode(kdf.derive(password.encode())) return key, salt def encrypt_content(content: str, password: str = None) -> Tuple[str, bytes]: """Encrypt the content using Fernet symmetric encryption.""" if password is None: password = settings.SECRET_KEY key, salt = derive_key(password) cipher = Fernet(key) encrypted_data = cipher.encrypt(content.encode()) return encrypted_data.decode(), salt def decrypt_content(encrypted_content: str, salt: bytes, password: str = None) -> str: """Decrypt the content using Fernet symmetric encryption.""" if password is None: password = settings.SECRET_KEY key, _ = derive_key(password, salt) cipher = Fernet(key) decrypted_data = cipher.decrypt(encrypted_content.encode()) return decrypted_data.decode()