import base64 import bcrypt from cryptography.fernet import Fernet from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC def _generate_key(salt: bytes, master_pass: bytes) -> bytes: kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, backend=default_backend(), ) key = base64.urlsafe_b64encode(kdf.derive(master_pass)) return key def encrypt_account_info( login: str, passwd: str, master_pass: bytes ) -> tuple[bytes, bytes, bytes]: """Encrypts login and password of a user using hash of their master password as a key. Returns a tuple of encrypted login password and salt""" salt = bcrypt.gensalt() key = _generate_key(salt, master_pass) f = Fernet(key) enc_login = f.encrypt(login.encode("utf-8")) enc_passwd = f.encrypt(passwd.encode("utf-8")) return (enc_login, enc_passwd, salt) def decrypt_account_info( enc_login: bytes, enc_pass: bytes, master_pass: bytes, salt: bytes ) -> tuple[str, str]: key = _generate_key(salt, master_pass) f = Fernet(key) login_bytes = f.decrypt(enc_login) pass_bytes = f.decrypt(enc_pass) return (login_bytes.decode("utf-8"), pass_bytes.decode("utf-8"))