from os.path import exists from enum import Enum from subprocess import Popen, PIPE from cryptography.fernet import Fernet import json class ReturnCode(Enum): UNKNOW_ERROR = 0 REG_KEY_ERROR = 1 ADD_REG_KEY_ERROR = 2 DEL_REG_KEY_ERROR = 3 INVALID_PATH = 4 REG_KEY_DELETED = 5 class Cryptography(): def __init__(self, appname: str): self.appname = appname key = self.__get_key() if type(key) is not bytes: key = self.__create_key() if type(key) is not bytes: raise ReturnCode.REG_KEY_ERROR self.fernet = Fernet(key) def __get_key(self): try: proces = Popen(f"reg QUERY HKEY_CURRENT_USER\{self.appname}", stdout=PIPE, stderr=PIPE) #Get key if proces.stderr.read() !=b'': return self.__create_key() else: return proces.stdout.read().decode("CP850").splitlines()[2].rsplit()[2].encode() #Return key as binary except: return ReturnCode.UNKNOW_ERROR def __create_key(self): try: key = Fernet.generate_key() proces = Popen(f"reg ADD HKEY_CURRENT_USER\{self.appname} /v fernkey /d {key.decode()}", stdout=PIPE, stderr=PIPE) #Add key in reg str if proces.stderr.read() != b'': return ReturnCode.ADD_REG_KEY_ERROR return key except: return ReturnCode.REG_KEY_ERROR def delete_key(self): """Delete the key used for decryption, WARNING ONCE THE KEY IS DELETED ALL YOUR CRYPTED DATA ARE UNDECRYPTABLE AND LOST""" try: proces = Popen(f"reg DELETE HKEY_CURRENT_USER\{self.appname} /f", stdout=PIPE, stderr=PIPE) stderr = proces.stderr.read() if stderr != b'': return ReturnCode.DEL_REG_KEY_ERROR return ReturnCode.REG_KEY_DELETED except: return ReturnCode.UNKNOW_ERROR def decrypt(self, data: bytes): return self.fernet.decrypt(data) def encrypt(self, data: bytes): return self.fernet.encrypt(data) class Credentials(): def __init__(self, appname: str, credentials_path: str): """Used to decode crypted credential csv files""" if not exists(self.creds_path): return ReturnCode.INVALID_PATH self.creds_path = credentials_path self.crypt = Cryptography(appname) def get_creds(self): """Return the uncrypted version of the usernames and passwords as a list of tuple : [(username0, password0), (username1, password1), ...]""" with open(self.creds_path, "rb") as f: return json.loads(self.crypt.decrypt(f.read()).decode()) def write_creds(self, data: list[tuple[str, str]]): with open(self.creds_path, "wb") as f: f.write(self.crypt.encrypt(json.dumps(data).encode())) return def add_cred(self, username: str, password: str): """Add username and password to the crypted file""" data = self.get_creds() data.append((username, password)) self.write_creds(data) return