From 3374f96bca2747ecd84e38fc87d4f984a9eecfc5 Mon Sep 17 00:00:00 2001 From: Peery Date: Mon, 20 Mar 2023 18:10:35 +0100 Subject: [PATCH] Configuration Key moved into key file Removed the hard-coded config encryption key and replaced it with a key file that gets generated by ArtNet if not present with a pseudo-random hex using the secret module. This should improve credential security. Deletion of the old config files might be necessary. --- ArtNet/artnet_manager.py | 2 +- ArtNet/file/config_reader.py | 50 +++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/ArtNet/artnet_manager.py b/ArtNet/artnet_manager.py index 53ab721..c41c721 100644 --- a/ArtNet/artnet_manager.py +++ b/ArtNet/artnet_manager.py @@ -38,7 +38,7 @@ class ArtNetManager: logging.info("Starting ArtNet client ...") self.known_image_amount = None - self.config = ConfigReader(config_location, "somePassword") + self.config = ConfigReader(config_location) if self.config.data["version"] != self.config.CONFIG_VERSION: logging.warning("Loaded config version is unequal to expected version! {0} (current) != {1} (expected)" diff --git a/ArtNet/file/config_reader.py b/ArtNet/file/config_reader.py index 301739a..672aaa0 100644 --- a/ArtNet/file/config_reader.py +++ b/ArtNet/file/config_reader.py @@ -1,35 +1,42 @@ import os import base64 import copy +import secrets import yaml -from cryptography.exceptions import AlreadyFinalized from cryptography.exceptions import InvalidTag -from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC -# TODO make the config actually safe, hard-coded encryption password is BAD (but a bit better than plaintext) - class ConfigReader: kdf = None nonce = None - CONFIG_VERSION = 3 + CONFIG_VERSION = 4 - def __init__(self, root_folder: str, password: str): + def __init__(self, root_folder: str): if root_folder is None: raise Exception("No root folder was defined!") self.__key = None self.__aesgcm = None self.data = {} - self.__password = password self.__config_location = os.path.join(root_folder, ".artnet", "artnet.config") + self.__config_key_location = os.path.join(root_folder, ".artnet", "artnet_config.key") + + try: + password = self.try_get_config_password() + except FileNotFoundError as e: + if not os.path.exists(self.__config_location): + self.generate_config_key_file() + password = self.try_get_config_password() + else: + raise e + ConfigReader.__create_kdf() self.__key = ConfigReader.kdf.derive(bytes(password.encode('utf-8'))) @@ -43,6 +50,35 @@ class ConfigReader: self.create_default_config() self.read_config() + def try_get_config_password(self) -> str: + """ + Attempts to read the config encryption password from the default location + """ + if os.path.exists(self.__config_key_location) and os.path.isfile(self.__config_key_location): + with open(self.__config_key_location, "r") as file: + password = file.readline() + file.close() + return password + else: + raise FileNotFoundError(f"The config encryption key file could not be found! " + f"FileNotFound: {self.__config_key_location}") + + def generate_config_key_file(self): + """ + Tries to generate a new pseudo-random generated key file for encrypting the config file. + + The key is in plain text and therefore not ideal. + """ + if not os.path.exists(self.__config_key_location) and not os.path.exists(self.__config_location): + with open(self.__config_key_location, "w") as file: + file.write(secrets.token_hex(100)) + file.close() + else: + raise Exception("Something went terribly wrong! " + "Tried to create new config key file although the key file or config file aready exists! " + "Perhaps old config?") + + def update_config(self): """ Update the written config with the local settings