figenc

[RADIOACTIVE] rsa and symmetric key encryption scripts and executables
git clone git://git.figbert.com/figenc.git
Log | Files | Refs | README

commit 2813f010be5fcc23b34f3e8432707eeac290d9ef
parent f60fd28e1be084399d5e72d83e65d4b3e013c158
Author: therealFIGBERT <figbertwelner@gmail.com>
Date:   Thu,  8 Aug 2019 16:15:01 -0700

2.0.0

Diffstat:
AOutlines/figENC Map.drawio | 2++
AOutlines/figENC Map.png | 0
MScripts/check.py | 528+++++++++++++++++++++----------------------------------------------------------
MScripts/decrypt.py | 189+++++++++++++++++++++++++++++++------------------------------------------------
MScripts/encrypt.py | 47++++++++++++++++-------------------------------
MScripts/figENC.py | 582+++++++++++++++++++++++++++++++++++++++++++------------------------------------
DScripts/initiate_key.py | 56--------------------------------------------------------
AScripts/key.py | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AScripts/prompts.py | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MScripts/settings.json | 1-
MScripts/tips.json | 1+
MScripts/version.txt | 4++--
MScripts/version_check.py | 4+---
13 files changed, 699 insertions(+), 864 deletions(-)

diff --git a/Outlines/figENC Map.drawio b/Outlines/figENC Map.drawio @@ -0,0 +1 @@ +<mxfile modified="2019-08-08T15:49:29.158Z" host="www.draw.io" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36" etag="gboWnSb1Uz1TyrMlN4N6" version="11.1.3" type="device"><diagram id="R-sONxbmBFkUxC5WE6_2" name="Page-1">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</diagram></mxfile> +\ No newline at end of file diff --git a/Outlines/figENC Map.png b/Outlines/figENC Map.png Binary files differ. diff --git a/Scripts/check.py b/Scripts/check.py @@ -1,188 +1,16 @@ -import errno -import os -from os import makedirs, path -import tempfile -import inspect -import sys -from sys import platform -import tkinter as tk -from tkinter import messagebox - -#Windows-specific error code indicating an invalid pathname -ERROR_INVALID_NAME = 123 - - -def is_pathname_valid(pathname: str) -> bool: - ''' - Return `True` if the passed pathname is a valid pathname for the current - OS, and `False` otherwise. If the pathname provided is either not a string - or is a string but is empty, return `False`. - ''' - try: - if not isinstance(pathname, str) or not pathname: - return False - #Strips this pathname's Windows-specific drive specifier (e.g., `C:\`) - #if any. - _, pathname = os.path.splitdrive(pathname) - - # Directory guaranteed to exist. If the current OS is Windows, this is - # the drive to which Windows was installed (e.g., the "%HOMEDRIVE%" - # environment variable); else, the typical root directory. - root_dirname = os.environ.get('HOMEDRIVE', 'C:') \ - if sys.platform == 'win32' else os.path.sep - assert os.path.isdir(root_dirname) - - # Append a path separator to this directory if needed. - root_dirname = root_dirname.rstrip(os.path.sep) + os.path.sep - - # Test whether each path component split from this pathname is valid or - # not, ignoring non-existent and non-readable path components. - for pathname_part in pathname.split(os.path.sep): - try: - os.lstat(root_dirname + pathname_part) - except OSError as exc: - if hasattr(exc, 'winerror'): - if exc.winerror == ERROR_INVALID_NAME: - return False - elif exc.errno in {errno.ENAMETOOLONG, errno.ERANGE}: - return False - except TypeError as exc: - return False - else: - return True - - -def is_path_creatable(pathname: str) -> bool: - ''' - Return `True` if the current user has sufficient permissions to create the - passed pathname; `False` otherwise. - ''' - # Parent directory of the passed path. If empty, we substitute the current - # working directory (CWD) instead. - dirname = os.path.dirname(pathname) or os.getcwd() - return os.access(dirname, os.W_OK) - - -def is_path_exists_or_creatable(pathname: str) -> bool: - ''' - Return `True` if the passed pathname is a valid pathname for the current - OS and either currently exists or is hypothetically createable; `False - otherwise. - ''' - try: - # To prevent "os" module calls from raising undesirable exceptions on - # invalid pathnames, is_pathname_valid() is explicitly called first. - return is_pathname_valid(pathname) and ( - os.path.exists(pathname) or is_path_creatable(pathname)) - except OSError: - return False - - -def is_path_sibling_creatable(pathname: str) -> bool: - ''' - Return `True` if the current user has sifficient permissions to create - siblings (arbitrary files in the parent directory) of the passed pathname, - and `False` otherwise. - ''' - # Parent directory of the passed path. If empty, we substitute the current - # working directory (CWD) instead. - dirname = os.path.dirname(pathname) or os.getcwd() - - try: - # Opening and immediately closing the temporary file - with tempfile.TemporaryFile(dir=dirname): pass - return True - # All exceptions fall under the EnvironmentError subclass - except EnvironmentError: - return False - - -def is_path_exists_or_creatable_portable(pathname: str) -> bool: - ''' - Return `True` if the passed pathname is a valid pathname on the current OS - and either currently exists or is hypothetically creatable in a - cross-platform manner optimized for POSIX-unfriendly filesystems; `False` - otherwise. - Never raises errors. - ''' - try: - # Calls is_pathname_valid() first to prevent "os" module from raising - # undesirable exceptions on invalid pathnames - return is_pathname_valid(pathname) and ( - os.path.exists(pathname) or is_path_sibling_creatable(pathname)) - except OSError: - pass - - -def overwrite(): - """Raise an error informing the user that the provided folder - where they wish to write the keys has keys in that will be - overwritten if they continue. Returns `True` if they wish to - overwrite the keys, `False` otherwise. - """ - return messagebox.askokcancel( - "Overwrite Keys", - ( - "The savefolder provided already has keys stored. If you continue, " - "these keys will be overwritten and any files encrypted with them " - "will be lost forever.\n\nContinue?" - ) - ) - - -def missing_key_error(save_folder): - """Raise an error informing the user that the provided folder - where the keys should be stored is missing the required keys. - """ - messagebox.showwarning( - "Missing Keys", - ( - "The savefolder provided is missing the required keys to perform " - "the requested operation. Please correct this and try again." - "\n\nFolder Provided:\n%s" % save_folder - ) - ) - - -def path_error(paths): - """Raise an error informing the user that the provided pathnames - are invalid. - - Arguments: - paths -- all of the broken filepaths - """ - messagebox.showwarning( - "Path Error", - ( - "One or more of the filepaths provided are invalid." - "\nCheck that the filepath was entered correctly, or that the user " - "has permission to edit the file." - "\n\nBroken Filepaths:\n%s" % paths - ) - ) - -def password_error(one, two): - """"Raise an error informing the user that the provided passwords - do not match. - """ - messagebox.showwarning( - "Passwords Do Not Match", - ("The passwords provided do not match. Please Try again." - "\n\nFirst: {}\nSecond: {}".format(one, two) - ) - ) +import os, inspect, sys +import prompts def password_check(first_pass, second_pass): if first_pass == second_pass: return True else: - password_error(first_pass, second_pass) return False def find_path(filename): """Return the filepath from the filename when running from a - pyinstaller onefile application. + pyinstaller application. Keyword arguments: filename -- the filename to convert to a filepath @@ -212,219 +40,141 @@ def find_path(filename): # ) + "/{}".format(file) -def quick_check(mode, target_file_raw=None, save_folder=None): - """Return `True` only if both the target file and save folder provided - by the user are valid pathnames (If the save folder is createable but does - not exist, it will be created). Otherwise, return `False` and notify the - user with an error messagebox. - - Keyword arguments: - target_file_raw -- a string list of pathnames - save_folder -- a string pathname to a directory - """ - save_folder += "/" if save_folder[-1] is not "/" else "" - if mode is not "just_key" or mode is not "weak_key": - target_file_list = target_file_raw.split(":") - targets_exist = True - broken_paths = "" - for target_file in target_file_list: - if targets_exist: - if not os.path.exists(target_file): - target_file = False - broken_paths += (target_file + "\n") - else: - if not os.path.exists(target_file): - broken_paths += (target_file + "\n") - if not targets_exist: - path_error(broken_paths) - return False - if ( - mode is "just_key" - or mode is "weak_key" - or mode is "key_enc" - or mode is "weak_key_enc" - ): - if platform is "win32": - if is_path_exists_or_creatable_portable(save_folder): - try: - os.makedirs(save_folder) - return True - except OSError: - if ( - os.path.exists(save_folder + "symmetric_key.key") - or os.path.exists(save_folder + "private_key.pem") - or os.path.exists(save_folder + "public_key.pem") - ): - return overwrite() - else: - return True - else: - return False - else: - if is_path_exists_or_creatable(save_folder): - try: - os.makedirs(save_folder) - return True - except OSError: - if ( - os.path.exists(save_folder + "symmetric_key.key") - or os.path.exists(save_folder + "private_key.pem") - or os.path.exists(save_folder + "public_key.pem") - ): - return overwrite() - else: - return True - else: - return False - elif mode is "dec" or mode is "weak_dec": - encryption_type = "" - for target_file in target_file_list: - with open(target_file, "rb") as read_file: - content = read_file.read() - if ( - content[-1] == b"1" - and (encryption_type is "" or encryption_type is "SYM") - ): - encryption_type = "SYM" - elif ( - content[-1] == b"1" - and (encryption_type is "RSA" or encryption_type is "MIX") - ): - encryption_type = "MIX" - elif ( - content[-1] == b"0" - and (encryption_type is "" or encryption_type is "RSA") - ): - encryption_type = "RSA" - elif ( - content[-1] == b"0" - and (encryption_type is "SYM" or encryption_type is "MIX") - ): - encryption_type = "MIX" - if encryption_type is "RSA": - if platform is "win32": - if os.path.exists(save_folder): - if ( - os.path.exists(save_folder + "private_key.pem") - and os.path.exists(save_folder + "public_key.pem") - ): - return True - else: - missing_key_error(save_folder) - return False - else: - return False - else: - if os.path.exists(save_folder): - if ( - os.path.exists(save_folder + "private_key.pem") - and os.path.exists(save_folder + "public_key.pem") - ): - return True - else: - missing_key_error(save_folder) - return False - else: - return False +def key_enc(files, pass1, pass2, key_dir): + broken_paths = "" + for fl in files: + if not os.access(fl, os.W_OK): + broken_paths += (fl + "\n") else: - if platform is "win32": - if os.path.exists(save_folder): - if ( - os.path.exists(save_folder + "private_key.pem") - and os.path.exists(save_folder + "public_key.pem") - and os.path.exists(save_folder + "symmetric_key.key") - ): - return True - else: - missing_key_error(save_folder) - return False - else: - return False - else: - if os.path.exists(save_folder): - if ( - os.path.exists(save_folder + "private_key.pem") - and os.path.exists(save_folder + "public_key.pem") - and os.path.exists(save_folder + "symmetric_key.key") - ): - return True - else: - missing_key_error(save_folder) - return False - else: - return False + continue + password_match = password_check(pass1, pass2) + key_dir_access = True if os.access(key_dir, os.W_OK) else False + priv = key_dir + "/private_key.pem" + pub = key_dir + "/public_key.pem" + sym = key_dir + "/symmetric_key.key" + write_key = prompts.overwrite_prompt() if os.path.exists(priv) or os.path.exists(pub) or os.path.exists(sym) else True + if broken_paths == "" and password_match and key_dir_access and write_key: + return True + elif not write_key: + return False else: - encryption_type = "" - for target_file in target_file_list: - if ( - os.path.getsize(target_file) > 446 - and (encryption_type is "" or encryption_type is "SYM") - ): - encryption_type = "SYM" - elif ( - os.path.getsize(target_file) > 446 - and (encryption_type is "RSA" or encryption_type is "MIX") - ): - encryption_type = "MIX" - elif ( - os.path.getsize(target_file) <= 446 - and (encryption_type is "" or encryption_type is "RSA") - ): - encryption_type = "RSA" - elif ( - os.path.getsize(target_file) <= 446 - and (encryption_type is "SYM" or encryption_type is "MIX") - ): - encryption_type = "MIX" - if encryption_type is "RSA": - if platform is "win32": - if os.path.exists(save_folder): - if ( - os.path.exists(save_folder + "private_key.pem") - and os.path.exists(save_folder + "public_key.pem") - ): - return True - else: - missing_key_error(save_folder) - return False - else: - return False - else: - if os.path.exists(save_folder): - if ( - os.path.exists(save_folder + "private_key.pem") - and os.path.exists(save_folder + "public_key.pem") - ): - return True - else: - missing_key_error(save_folder) - return False - else: - return False + if broken_paths != "": + prompts.file_access_error(broken_paths) + if not password_match: + prompts.password_error(pass1, pass2) + if not key_dir_access: + prompts.key_dir_error(key_dir) + return False + + +def weak_key_enc(files, key_dir): + broken_paths = "" + for fl in files: + if not os.access(fl, os.W_OK): + broken_paths += (fl + "\n") else: - if platform is "win32": - if os.path.exists(save_folder): - if ( - os.path.exists(save_folder + "private_key.pem") - and os.path.exists(save_folder + "public_key.pem") - and os.path.exists(save_folder + "symmetric_key.key") - ): - return True - else: - missing_key_error(save_folder) - return False - else: - return False - else: - if os.path.exists(save_folder): - if ( - os.path.exists(save_folder + "private_key.pem") - and os.path.exists(save_folder + "public_key.pem") - and os.path.exists(save_folder + "symmetric_key.key") - ): - return True - else: - missing_key_error(save_folder) - return False - else: - return False -\ No newline at end of file + continue + key_dir_access = True if os.access(key_dir, os.W_OK) else False + priv = key_dir + "/private_key.pem" + pub = key_dir + "/public_key.pem" + sym = key_dir + "/symmetric_key.key" + write_key = prompts.overwrite_prompt() if os.path.exists(priv) or os.path.exists(pub) or os.path.exists(sym) else True + if broken_paths == "" and key_dir_access and write_key: + return True + elif not write_key: + return False + else: + if broken_paths != "": + prompts.file_access_error(broken_paths) + if not key_dir_access: + prompts.key_dir_error(key_dir) + return False + + +def enc(files, key_dir): + broken_paths = "" + rsa = True + for fl in files: + if not os.access(fl, os.W_OK): + broken_paths += (fl + "\n") + if os.path.getsize(fl) > 446: + rsa = False + pub = key_dir + "/public_key.pem" + sym = key_dir + "/symmetric_key.key" + proper_keys = True if (os.path.exists(pub) and rsa) or (not rsa and os.path.exists(pub) and os.path.exists(sym)) else False + if broken_paths == "" and proper_keys: + return True + else: + if broken_paths != "": + prompts.file_access_error(broken_paths) + if not proper_keys: + prompts.missing_keys(key_dir) + + +def key(key_dir): + key_dir_access = True if os.access(key_dir, os.W_OK) else False + priv = key_dir + "/private_key.pem" + pub = key_dir + "/public_key.pem" + sym = key_dir + "/symmetric_key.key" + write_key = prompts.overwrite_prompt() if os.path.exists(priv) or os.path.exists(pub) or os.path.exists(sym) else True + if key_dir_access and write_key: + return True + else: + if not key_dir_access: + prompts.key_dir_error(key_dir) + return False + + +def dec(files, pass1, pass2, key_dir): + broken_paths = "" + rsa = True + for fl in files: + if not os.access(fl, os.W_OK): + broken_paths += fl + "\n" + with open(fl, "rb") as read_file: + tag = read_file.read()[-1] + if tag == 49: + rsa = False + password_match = password_check(pass1, pass2) + key_dir_access = True if os.access(key_dir, os.W_OK) else False + priv = key_dir + "/private_key.pem" + sym = key_dir + "/symmetric_key.key" + proper_keys = True if (rsa and os.path.exists(priv)) or (not rsa and os.path.exists(priv) and os.path.exists(sym)) else False + if broken_paths == "" and key_dir_access and password_match and proper_keys: + return True + else: + if broken_paths != "": + prompts.file_access_error(broken_paths) + if not key_dir_access: + prompts.key_dir_error(key_dir) + if not password_match: + prompts.password_error(pass1, pass2) + if not proper_keys: + prompts.missing_keys(key_dir) + return False + + +def weak_dec(files, key_dir): + broken_paths = "" + rsa = True + for fl in files: + if not os.access(fl, os.W_OK): + broken_paths += fl + "\n" + with open(fl, "rb") as read_file: + tag = read_file.read()[-1] + if tag == 49: + rsa = False + key_dir_access = True if os.access(key_dir, os.W_OK) else False + priv = key_dir + "/private_key.pem" + sym = key_dir + "/symmetric_key.key" + proper_keys = True if (rsa and os.path.exists(priv)) or (not rsa and os.path.exists(priv) and os.path.exists(sym)) else False + if broken_paths == "" and key_dir_access and proper_keys: + return True + else: + if broken_paths != "": + prompts.file_access_error(broken_paths) + if not key_dir_access: + prompts.key_dir_error(key_dir) + if not proper_keys: + prompts.missing_keys(key_dir) + return False +\ No newline at end of file diff --git a/Scripts/decrypt.py b/Scripts/decrypt.py @@ -1,5 +1,3 @@ -import os -from check import find_path from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import serialization @@ -8,124 +6,85 @@ from cryptography.hazmat.primitives.asymmetric import padding from cryptography.fernet import Fernet -def rsa_dec(target_file_raw, save_folder, passkey): - """Decrypt all files passed to the function with the symmetric key, - and then replace the symmetric key file's contents with the decrypted - version, decrypted with the private key. +def rsa_dec(file, priv, passkey): + with open(priv, "rb") as priv_src, \ + open(file, "rb") as read_file: + private_key = serialization.load_pem_private_key( + priv_src.read(), + password=bytes(passkey, "utf-8") if passkey != "" else None, + backend=default_backend() + ) + content = read_file.read()[:-1] + original_message = private_key.decrypt( + content, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None + ) + ) + with open(file, "wb") as write_file: + write_file.write(original_message) - Keyword arguements: - target_file_raw -- a string composed of file locations seperated by colons - save_folder -- the location of the saved key trio - passkey -- the passkey used to enhance the encryption algorithm (OPTIONAL) - """ - #Turning target_file_raw from a list in string form to a list - target_file_list = target_file_raw.split(":") - if save_folder[-1] != "/": - save_folder += "/" - #Determining the key source - private_key_source = save_folder + "private_key.pem" - symmetric_key_source = save_folder + "symmetric_key.key" - #Creating the keys from the source files - print("3. Reached the decryption for loop") - for target_file in target_file_list: - with open(target_file, "rb") as read_file: - content = read_file.read() - print("4. Opened the target file") - if content[-1] == 48: - print("5. Dectected encryption type as RSA") - with open(private_key_source, "rb") as private_key_file: - if passkey != "": - print("6. Passcode") - private_key = serialization.load_pem_private_key( - private_key_file.read(), - password = bytes(passkey, "utf-8"), - backend = default_backend() - ) - else: - print("6. No passcode") - private_key = serialization.load_pem_private_key( - private_key_file.read(), - password = None, - backend = default_backend() - ) - print("7. Private key loaded") - encrypted_data = content[:-1] - print("8. Removed final character from encrypted data") - original_message = private_key.decrypt( - encrypted_data, +def mixed_dec(file, priv, sym, passkey): + with open(priv, "rb") as priv_src, \ + open(sym, "rb") as sym_src, \ + open(file, "rb") as read_file: + private_key = serialization.load_pem_private_key( + priv_src.read(), + password=bytes(passkey, "utf-8") if passkey != "" else None, + backend=default_backend() + ) + sym_data = sym_src.read() + try: + sym_dec = private_key.decrypt( + sym_data, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) - print("9. Decrypted data") - with open(target_file, "wb") as write_file: - write_file.write(original_message) - print("10. Wrote decrypted data to file") - elif content[-1] == 49: - print("5. Detected the encryption type as symmetric") - with open(private_key_source, "rb") as private_key_file, \ - open(symmetric_key_source, "rb") as symmetric_key_file: - if passkey != "": - print("6. Passcode") - private_key = serialization.load_pem_private_key( - private_key_file.read(), - password = bytes(passkey, "utf-8"), - backend = default_backend() - ) - else: - print("6. Passcode") - private_key = serialization.load_pem_private_key( - private_key_file.read(), - password = None, - backend = default_backend() - ) - print("7. Private key loaded") - encoded_key_data = symmetric_key_file.read() - print("8. Symmetric key loaded") - symmetric_key_data = private_key.decrypt( - encoded_key_data, - padding.OAEP( - mgf = padding.MGF1(algorithm = hashes.SHA256()), - algorithm = hashes.SHA256(), - label = None - ) + symmetric_key = Fernet(sym_dec) + except: + symmetric_key = Fernet(sym_data) + content = read_file.read()[:-1] + original_message = symmetric_key.decrypt(content) + with open(file, "wb") as write_file: + write_file.write(original_message) + + +def dec_manager(files, key_dir, passkey): + priv = key_dir + "/private_key.pem" + sym = key_dir + "/symmetric_key.key" + rsa = True + for fl in files: + with open(fl, "rb") as read_file: + tag = read_file.read()[-1] + if tag == 48: + rsa_dec(fl, priv, passkey) + else: + mixed_dec(fl, priv, sym, passkey) + rsa = False + if not rsa: + with open(priv, "rb") as priv_src, \ + open(sym, "rb") as sym_src: + private_key = serialization.load_pem_private_key( + priv_src.read(), + password=bytes(passkey, "utf-8") if passkey != "" else None, + backend=default_backend() ) - print("9. Symmetric key data activated") - symmetric_key = Fernet(symmetric_key_data) - print("10. Symmetric key activated") - #Decrypting and outputting the data - encrypted_data = content[:-1] - print("11. Removed final characted from encrypted data") - original_message = symmetric_key.decrypt(encrypted_data) - print("12. Decrypted data") - with open(target_file, "wb") as write_file: - write_file.write(original_message) - print("13. Wrote decrypted data to file") - if os.path.exists(symmetric_key_source): - with open(private_key_source, "rb") as private_key_file, \ - open(symmetric_key_source, "rb") as symmetric_key_file: - if passkey != "": - private_key = serialization.load_pem_private_key( - private_key_file.read(), - password = bytes(passkey, "utf-8"), - backend = default_backend() - ) - else: - private_key = serialization.load_pem_private_key( - private_key_file.read(), - password = None, - backend = default_backend() + sym_data = sym_src.read() + try: + sym_dec = private_key.decrypt( + sym_data, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None + ) ) - encoded_key_data = symmetric_key_file.read() - symmetric_key_data = private_key.decrypt( - encoded_key_data, - padding.OAEP( - mgf = padding.MGF1(algorithm = hashes.SHA256()), - algorithm = hashes.SHA256(), - label = None - ) - ) - with open(symmetric_key_source, "wb") as symmetric_out: - symmetric_out.write(symmetric_key_data) -\ No newline at end of file + except: + return None + with open(sym, "wb") as sym_src: + sym_src.write(sym_dec) +\ No newline at end of file diff --git a/Scripts/encrypt.py b/Scripts/encrypt.py @@ -1,6 +1,4 @@ import os -import inspect -from check import find_path from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import serialization @@ -48,7 +46,7 @@ def Symmetric(target_file, public_key_source, symmetric_key_source): with open(target_file, "wb") as write_file: write_file.write(data) -def rsa_enc(target_file_raw, save_folder): +def enc_manager(target_files, save_folder): """Encrypt all files passed to the function with the symmetric key, and then replace the symmetric key file's contents with an encrypted version, encrypted with the public key. @@ -57,37 +55,24 @@ def rsa_enc(target_file_raw, save_folder): target_file_raw -- a string composed of file locations seperated by colons save_folder -- the location of the saved key trio """ - #Turning target_file_raw from a list in string form to a list - target_file_list = target_file_raw.split(":") - if save_folder[-1] != "/": - save_folder += "/" - #Determining the key source - public_key_source = save_folder + "public_key.pem" - symmetric_key_source = save_folder + "symmetric_key.key" - encryption_type = "" - for target_file in target_file_list: - if os.path.getsize(target_file) > 446: - Symmetric(target_file, public_key_source, symmetric_key_source) - if encryption_type is "" or encryption_type is "SYM": - encryption_type = "SYM" - else: - encryption_type = "MIX" - else: - RSA(target_file, public_key_source) - if encryption_type is "" or encryption_type is "RSA": - encryption_type = "RSA" - else: - encryption_type = "MIX" - if encryption_type is "RSA": - os.remove(symmetric_key_source) + pub_src = save_folder + "/public_key.pem" + sym_src = save_folder + "/symmetric_key.key" + if not os.path.exists(sym_src): + for fl in target_files: + RSA(fl, pub_src) else: - with open(public_key_source, "rb") as public_key_file, \ - open(symmetric_key_source, "rb") as symmetric_key_file: + for fl in target_files: + if os.path.getsize(fl) > 446: + Symmetric(fl, pub_src, sym_src) + else: + RSA(fl, pub_src) + with open(pub_src, "rb") as pub_file, \ + open(sym_src, "rb") as sym_file: public_key = serialization.load_pem_public_key( - public_key_file.read(), + pub_file.read(), backend=default_backend() ) - symmetric_key_data = symmetric_key_file.read() + symmetric_key_data = sym_file.read() encrypted_key = public_key.encrypt( symmetric_key_data, padding.OAEP( @@ -96,5 +81,5 @@ def rsa_enc(target_file_raw, save_folder): label = None ) ) - with open(symmetric_key_source, "wb") as crypto_key_file: + with open(sym_src, "wb") as crypto_key_file: crypto_key_file.write(encrypted_key) \ No newline at end of file diff --git a/Scripts/figENC.py b/Scripts/figENC.py @@ -1,13 +1,11 @@ -import sys, os, inspect +import sys, json import tkinter as tk +from tkinter import filedialog from random import choice -import json -import requests -from initiate_key import rsa_key -from encrypt import rsa_enc -from decrypt import rsa_dec -import version_check -import check +import key, check +from encrypt import enc_manager +from decrypt import dec_manager +import version_check as vc from check import find_path @@ -21,12 +19,99 @@ class App(): """ self.crypto_mode = "" self.show_pass = False + self.crypto_filepaths = () + self.key_dir = "" + self.settings_file = find_path("settings.json") self.tips_file = find_path("tips.json") - with open(self.settings_file) as settings_file: settings = json.load(settings_file) + self.main_app(root, settings) + + self.launcher = tk.Toplevel() + self.launcher.wm_title("figENC") + self.canvas = tk.Canvas( + self.launcher, + height=settings["win_height"]/6, + width=settings["win_width"]/1.5 + ) + self.canvas.pack(fill=tk.BOTH, expand=True) + self.frame = tk.Frame(self.canvas, bg="#1A181C") + self.frame.place(relwidth=1, relheight=1) + self.header = tk.Label( + self.frame, + text="Loading application...", + font=("Arial", ( + settings["font_size"]-2 if settings["font_size"]-2 > 0 else 2 + ) + ), + bg="#1A181C", + fg="#F2DAFF", + pady=5 + ) + self.header.pack(side=tk.TOP) + self.subheader = tk.Label( + self.frame, + text=self.pick_tip(), + font=("Arial", ( + settings["font_size"]-4 if settings["font_size"]-4 > 0 else 1 + ) + ), + bg="#1A181C", + fg="#B494C7" + ) + self.subheader.pack(side=tk.TOP) + self.button_frame = tk.Frame(self.frame, bg="#1A181C", pady=5) + self.button_frame.pack(side=tk.TOP) + if sys.platform == "darwin": + self.launch_button = tk.Button( + self.button_frame, + fg="#643181", + text="Launch App", + font=("Arial", "10"), + highlightthickness=5, + highlightbackground="#1A181C", + command=lambda: self.launch_app(root) + ) + self.settings_button = tk.Button( + self.button_frame, + fg="#643181", + text="Settings", + font=("Arial", "10"), + highlightbackground="#1A181C", + highlightthickness=5, + command=lambda: self.open_settings(self.launcher) + ) + else: + self.launch_button = tk.Button( + self.button_frame, + fg="#B494C7", + bg="#643181", + text="Launch App", + font=("Arial", "10"), + command=lambda: self.launch_app(root) + ) + self.settings_button = tk.Button( + self.button_frame, + fg="#B494C7", + bg="#643181", + text="Settings", + font=("Arial", "10"), + command=lambda: self.open_settings(self.launcher) + ) + self.launch_button.pack(side=tk.LEFT) + self.settings_button.pack(side=tk.RIGHT) + + root.mainloop() + + def main_app(self, root, settings): + """Create the main app widgets in the passed root variable, and then + minimize the root window. + Keyword arguments: + root -- the main app window + settings -- a dictionary of settings used to build the widget + """ root.wm_title("figENC") self.canvas = tk.Canvas( root, @@ -43,7 +128,7 @@ class App(): font=("Arial", str(settings["font_size"] + 6)), bg="#643181", fg="#F2DAFF", - pady="2" + pady=2 ) self.subheader = tk.Label( self.frame, @@ -52,11 +137,11 @@ class App(): font=("Arial", str(settings["font_size"])), bg="#643181", fg="#F2DAFF", - pady="2" + pady=2 ) self.header.pack(fill="x", side=tk.TOP) self.subheader.pack(fill="x", side=tk.TOP) - self.action = tk.Frame(self.frame, bg="#1A181C", pady="5") + self.action = tk.Frame(self.frame, bg="#1A181C", pady=5) self.action.pack(fill="both") self.action_label = tk.Label( self.action, @@ -94,7 +179,7 @@ class App(): ) self.action_list.insert(6, "Only create fresh keys (password locked)") self.action_list.insert(7, "Only create fresh keys (no password)") - self.action_list.pack(fill="both", pady="10") + self.action_list.pack(fill="both", pady=10) if sys.platform == "darwin": self.submit_action = tk.Button( self.action, @@ -103,7 +188,6 @@ class App(): fg="#643181", highlightthickness=0, highlightbackground="#1A181C", - pady="3", command=lambda: self.setup(self.action_list.curselection()) ) else: @@ -118,7 +202,7 @@ class App(): self.submit_action.pack() self.step_two = tk.Frame(self.frame, bg="#1A181C") self.step_two.pack(fill="both") - self.file_frame = tk.Frame(self.step_two, bg="#1A181C", pady="8") + self.file_frame = tk.Frame(self.step_two, bg="#1A181C", pady=8) self.file_label = tk.Label( self.file_frame, text="If you see this, the app broke", @@ -133,17 +217,26 @@ class App(): bg="#1A181C", fg="#B494C7" ) - self.file_input = tk.Entry( - self.file_frame, - font=("Arial", str(settings["font_size"] - 2)), - justify=tk.CENTER, - textvariable=tk.StringVar, - bg="#1A181C", - fg="#F2DAFF", - highlightthickness=0, - insertbackground="#F2DAFF" - ) - self.passcode_frame = tk.Frame(self.step_two, bg="#1A181C", pady="8") + if sys.platform == "darwin": + self.file_input = tk.Button( + self.file_frame, + text="Select File/s", + font=("Arial", str(settings["font_size"] - 2)), + fg="#643181", + highlightthickness=0, + highlightbackground="#1A181C", + command=self.select_filepaths + ) + else: + self.file_input = tk.Button( + self.file_frame, + text="Select File/s", + font=("Arial", str(settings["font_size"] - 2)), + bg="#643181", + fg="#B494C7", + command=self.select_filepaths + ) + self.passcode_frame = tk.Frame(self.step_two, bg="#1A181C", pady=8) self.passcode_label = tk.Label( self.passcode_frame, text="If you see this, the app broke", @@ -196,7 +289,7 @@ class App(): insertbackground="#F2DAFF" ) self.confirm_input.bind("<Button-2>", self.toggle_pass) - self.save = tk.Frame(self.step_two, bg="#1A181C", pady="8") + self.save = tk.Frame(self.step_two, bg="#1A181C", pady=8) self.save_label = tk.Label( self.save, text="Save location for keys", @@ -211,126 +304,93 @@ class App(): bg="#1A181C", fg="#B494C7" ) - self.save_input = tk.Entry( - self.save, + if sys.platform == "darwin": + self.save_input = tk.Button( + self.save, + text="Select Directory", + font=("Arial", str(settings["font_size"] - 2)), + fg="#643181", + highlightthickness=0, + highlightbackground="#1A181C", + command=self.select_key_dir + ) + else: + self.save_input = tk.Button( + self.save, + text="Select Directory", + font=("Arial", str(settings["font_size"] - 2)), + bg="#643181", + fg="#B494C7", + command=self.select_key_dir + ) + self.type_frame = tk.Frame(self.step_two, bg="#1A181C", pady=8) + self.type_label = tk.Label( + self.type_frame, + text="Type of keys to generate", + font=("Arial", str(settings["font_size"])), + bg="#1A181C", + fg="#F2DAFF" + ) + self.type_instructions = tk.Label( + self.type_frame, + text=("Selecting RSA will generate a public and private key,\nbut" + " selecting Mixed will also generate a symmetric key." + ), font=("Arial", str(settings["font_size"] - 2)), - justify=tk.CENTER, - textvariable=tk.StringVar, + bg="#1A181C", + fg="#B494C7" + ) + self.type_button_frame = tk.Frame(self.type_frame, bg="#1A181C") + self.type_control = tk.IntVar() + self.rsa_radiobutton = tk.Radiobutton( + self.type_button_frame, + text="RSA", bg="#1A181C", fg="#F2DAFF", - highlightthickness=0, - insertbackground="#F2DAFF" + variable=self.type_control, + value=0 + ) + self.mixed_radiobutton = tk.Radiobutton( + self.type_button_frame, + text="Mixed", + bg="#1A181C", + fg="#F2DAFF", + variable=self.type_control, + value=1 ) if sys.platform == "darwin": self.submit = tk.Button( - self.save, + self.step_two, text="If you see this, the app broke", font=("Arial", str(settings["font_size"] - 2)), fg="#643181", highlightbackground="#1A181C", highlightthickness=0, - pady="3", command=lambda: self.go( mode=self.crypto_mode, - save_folder=self.save_input.get(), - target_file=self.file_input.get(), + key_dir=self.key_paths, + target_files=self.crypto_filepaths, passkey=self.passcode_input.get(), passcheck=self.confirm_input.get() ) ) else: self.submit = tk.Button( - self.save, + self.step_two, text="If you see this, the app broke", font=("Arial", str(settings["font_size"] - 2)), bg="#643181", fg="#B494C7", - pady="3", command=lambda: self.go( mode=self.crypto_mode, - save_folder=self.save_input.get(), - target_file=self.file_input.get(), + key_dir=self.key_paths, + target_files=self.crypto_filepaths, passkey=self.passcode_input.get(), passcheck=self.confirm_input.get() ) ) root.withdraw() - self.launcher = tk.Toplevel() - self.launcher.wm_title("figENC") - self.canvas = tk.Canvas( - self.launcher, - height=100, - width=450 - ) - self.canvas.pack(fill=tk.BOTH, expand=True) - self.frame = tk.Frame(self.canvas, bg="#1A181C") - self.frame.place(relwidth=1, relheight=1) - self.header = tk.Label( - self.frame, - text="Loading application...", - font=("Arial", "12"), - bg="#1A181C", - fg="#F2DAFF", - pady="5" - ) - self.header.pack(side=tk.TOP) - self.subheader = tk.Label( - self.frame, - text=self.pick_tip(), - font=("Arial", "10"), - bg="#1A181C", - fg="#B494C7" - ) - self.subheader.pack(side=tk.TOP) - self.button_frame = tk.Frame(self.frame, bg="#1A181C", pady=5) - self.button_frame.pack(side=tk.TOP) - if sys.platform == "darwin": - self.launch_button = tk.Button( - self.button_frame, - fg="#643181", - text="Launch App", - font=("Arial", "10"), - highlightthickness=5, - highlightbackground="#1A181C", - command=lambda: self.launch_app(root) - ) - else: - self.launch_button = tk.Button( - self.button_frame, - fg="#B494C7", - bg="#643181", - text="Launch App", - font=("Arial", "10"), - command=lambda: self.launch_app(root) - ) - if sys.platform == "darwin": - self.settings_button = tk.Button( - self.button_frame, - fg="#643181", - text="Settings", - font=("Arial", "10"), - highlightbackground="#1A181C", - highlightthickness=5, - command=lambda: self.open_settings(self.launcher) - ) - else: - self.settings_button = tk.Button( - self.button_frame, - fg="#B494C7", - bg="#643181", - text="Settings", - font=("Arial", "10"), - command=lambda: self.open_settings(self.launcher) - ) - self.launch_button.pack(side=tk.LEFT) - self.settings_button.pack(side=tk.RIGHT) - root.mainloop() - def launch_app(self, root): - root.deiconify() - self.launcher.destroy() - self.frame.update() - def open_settings(self, root): """Open the settings window and temporarily minimize the root window @@ -338,14 +398,14 @@ class App(): root -- the window to be minimized """ root.withdraw() + with open(self.settings_file) as settings_file: + self.settings = json.load(settings_file) self.settings_window = tk.Toplevel( - height=400, - width=700, + height=self.settings["win_height"], + width=self.settings["win_width"], bg="#1A181C" ) self.settings_window.wm_title("figENC - Settings") - with open(self.settings_file) as settings_file: - self.settings = json.load(settings_file) self.canvas = tk.Canvas( self.settings_window, height=self.settings["win_height"], @@ -387,52 +447,40 @@ class App(): ) self.font_menu.config(bg="#1A181C", fg="#643181") self.font_menu.pack(side=tk.LEFT) - self.width_frame = tk.Frame(self.frame, bg="#1A181C") - self.width_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=10) - self.width_label = tk.Label( - self.width_frame, - text="Default window width: ", - justify=tk.LEFT, - font=("Arial", str(self.settings["font_size"])), - bg="#1A181C", - fg="#F2DAFF", - pady=2 - ) - self.width_label.pack(side=tk.LEFT) - self.width_options = [500, 700, 900, 1000, 1200, 1500] - self.width_dropdown = tk.StringVar() - self.width_dropdown.set(self.settings["win_width"]) - self.width_menu = tk.OptionMenu( - self.width_frame, - self.width_dropdown, - *self.width_options, - command=self.modify_width - ) - self.width_menu.config(bg="#1A181C", fg="#643181") - self.width_menu.pack(side=tk.LEFT) - self.height_frame = tk.Frame(self.frame, bg="#1A181C") - self.height_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=10) - self.height_label = tk.Label( - self.height_frame, - text="Default window height: ", + self.dim_frame = tk.Frame(self.frame, bg="#1A181C") + self.dim_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=10) + self.dim_label = tk.Label( + self.dim_frame, + text="Default window dimension: ", justify=tk.LEFT, font=("Arial", str(self.settings["font_size"])), bg="#1A181C", fg="#F2DAFF", pady=2 ) - self.height_label.pack(side=tk.LEFT) - self.height_options = [500, 700, 900, 1000, 1200, 1500] - self.height_dropdown = tk.StringVar() - self.height_dropdown.set(self.settings["win_width"]) - self.height_menu = tk.OptionMenu( - self.height_frame, - self.height_dropdown, - *self.height_options, - command=self.modify_height - ) - self.height_menu.config(bg="#1A181C", fg="#643181") - self.height_menu.pack(side=tk.LEFT) + self.dim_label.pack(side=tk.LEFT) + self.dim_options = [ + "500x500", + "700x700", + "900x900", + "1000x1000", + "1200x1200", + "1500x1500" + ] + self.dim_dropdown = tk.StringVar() + self.dim_dropdown.set( + str(self.settings["win_width"]) + + "x" + + str(self.settings["win_height"]) + ) + self.dim_menu = tk.OptionMenu( + self.dim_frame, + self.dim_dropdown, + *self.dim_options, + command=self.modify_dim + ) + self.dim_menu.config(bg="#1A181C", fg="#643181") + self.dim_menu.pack(side=tk.LEFT) self.update_frame = tk.Frame(self.frame, bg="#1A181C") self.update_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=10) self.update_label = tk.Label( @@ -445,7 +493,7 @@ class App(): pady=2 ) self.update_label.pack(side=tk.LEFT) - self.update_bool = version_check.update_available() + self.update_bool = vc.update_available() if self.update_bool == "available": self.update_text = "Available" self.update_color = "#84D373" @@ -465,44 +513,29 @@ class App(): pady=2 ) self.update_status.pack(side=tk.LEFT) - self.save_frame = tk.Frame(self.frame, bg="#1A181C") - self.save_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, pady=5, padx=5) - if sys.platform == "darwin": - self.save_button = tk.Button( - self.save_frame, - fg="#643181", - text="Save", - font=("Arial", str(self.settings["font_size"] - 2)), - highlightbackground="#1A181C", - padx=5, - command=lambda: self.export(self.settings_window, root) - ) - else: - self.save_button = tk.Button( - self.save_frame, - fg="#B494C7", - bg="#643181", - text="Save", - font=("Arial", str(self.settings["font_size"] - 2)), - padx=5, - command=lambda: self.export(self.settings_window, root) - ) - self.save_button.pack(side=tk.LEFT) + self.settings_window.protocol( + "WM_DELETE_WINDOW", + lambda: self.close_settings(self.settings_window, root) + ) self.settings_window.mainloop() - - def pick_tip(self): - """Return a random string from the tips.json file""" - with open(self.tips_file) as source: - self.tips = json.load(source) - self.tip = "Tip: " + choice(self.tips) - return self.tip + + def launch_app(self, root): + """Deiconifies the passed root window, destroys the launcher + window and updates the frame + + Keyword arguments: + root -- the main app window + """ + root.deiconify() + self.launcher.destroy() + self.frame.update() + def reset(self): - """Hide all elements of the app GUI and reset the entered text""" + """Hide all elements of the main app GUI and reset the entered text""" self.file_frame.pack_forget() self.file_instructions.pack_forget() self.file_label.pack_forget() - self.reset_text(self.file_input) self.file_input.pack_forget() self.passcode_frame.pack_forget() self.passcode_label.pack_forget() @@ -516,8 +549,13 @@ class App(): self.save.pack_forget() self.save_label.pack_forget() self.save_instructions.pack_forget() - self.reset_text(self.save_input) self.save_input.pack_forget() + self.type_frame.pack_forget() + self.type_label.pack_forget() + self.type_instructions.pack_forget() + self.type_button_frame.pack_forget() + self.rsa_radiobutton.pack_forget() + self.mixed_radiobutton.pack_forget() self.submit.pack_forget() def reset_text(self, entry_widget): @@ -571,9 +609,9 @@ class App(): ) ) self.save_instructions.pack() - self.save_input.pack(fill="both") + self.save_input.pack(fill="x") self.submit.config(text="Encrypt file/s") - self.submit.pack(pady="10") + self.submit.pack(pady=10) self.crypto_mode = "key_enc" self.frame.update() elif mode == 1: #Encrypt with fresh keys (no password) @@ -595,9 +633,9 @@ class App(): ) ) self.save_instructions.pack() - self.save_input.pack(fill="both") + self.save_input.pack(fill="x") self.submit.config(text="Encrypt file/s") - self.submit.pack(pady="10") + self.submit.pack(pady=10) self.crypto_mode = "weak_key_enc" self.frame.update() elif mode == 2: #Encrypt with generated keys @@ -614,9 +652,9 @@ class App(): text="Filepath to matching key trio" ) self.save_instructions.pack() - self.save_input.pack(fill="both") + self.save_input.pack(fill="x") self.submit.config(text="Encrypt file/s") - self.submit.pack(pady="10") + self.submit.pack(pady=10) self.crypto_mode = "enc" self.frame.update() elif mode == 3: #Decrypt with generated keys (password locked) @@ -647,9 +685,9 @@ class App(): text="Filepath to matching key trio" ) self.save_instructions.pack() - self.save_input.pack(fill="both") + self.save_input.pack(fill="x") self.submit.config(text="Decrypt file/s") - self.submit.pack(pady="10") + self.submit.pack(pady=10) self.crypto_mode = "dec" self.frame.update() elif mode == 4: #Decrypt with generated keys (no password) @@ -666,9 +704,9 @@ class App(): text="Filepath to matching key trio" ) self.save_instructions.pack() - self.save_input.pack(fill="both") + self.save_input.pack(fill="x") self.submit.config(text="Decrypt file/s") - self.submit.pack(pady="10") + self.submit.pack(pady=10) self.crypto_mode = "weak_dec" self.frame.update() elif mode == 5: #Only create fresh keys (password locked) @@ -699,9 +737,15 @@ class App(): ) ) self.save_instructions.pack() - self.save_input.pack(fill="both") + self.save_input.pack(fill="x") + self.type_frame.pack() + self.type_label.pack() + self.type_instructions.pack() + self.type_button_frame.pack() + self.rsa_radiobutton.pack(side=tk.LEFT) + self.mixed_radiobutton.pack(side=tk.LEFT) self.submit.config(text="Create keys") - self.submit.pack(pady="10") + self.submit.pack(pady=10) self.crypto_mode = "just_key" self.frame.update() elif mode == 6: #Only create fresh keys (no password) @@ -718,17 +762,23 @@ class App(): ) ) self.save_instructions.pack() - self.save_input.pack(fill="both") + self.save_input.pack(fill="x") + self.type_frame.pack() + self.type_label.pack() + self.type_instructions.pack() + self.type_button_frame.pack() + self.rsa_radiobutton.pack(side=tk.LEFT) + self.mixed_radiobutton.pack(side=tk.LEFT) self.submit.config(text="Create keys") - self.submit.pack(pady="10") + self.submit.pack(pady=10) self.crypto_mode = "weak_key" self.frame.update() def go( self, mode, - save_folder=None, - target_file=None, + key_dir=None, + target_files=None, passkey=None, passcheck=None ): @@ -744,85 +794,77 @@ class App(): passcheck - the access code to the RSA keys that have them confirmed, to prevent spelling errors. """ - if check.quick_check( - mode=mode, - target_file_raw=target_file, - save_folder=save_folder + if mode == "key_enc" and check.key_enc( + target_files, + passkey, + passcheck, + key_dir + ): + key.key_manager(target_files, key_dir, passkey) + enc_manager(target_files, key_dir) + elif mode == "weak_key_enc" and check.weak_key_enc( + target_files, + key_dir + ): + key.key_manager(target_files, key_dir, passkey) + enc_manager(target_files, key_dir) + elif mode == "enc" and check.enc(target_files, key_dir): + enc_manager(target_files, key_dir) + elif mode == "dec" and check.dec( + target_files, + passkey, + passcheck, + key_dir ): - print("1. Quick check works") - if mode == "key_enc" and check.password_check(passkey, passcheck): - rsa_key(passkey, save_folder) - rsa_enc(target_file, save_folder) - elif mode == "weak_key_enc": - rsa_key(passkey, save_folder) - rsa_enc(target_file, save_folder) - elif mode == "enc": - rsa_enc(target_file, save_folder) - elif mode == "dec" and check.password_check(passkey, passcheck): - rsa_dec(target_file, save_folder, passkey) - elif mode == "weak_dec": - print("2. Reached function call") - rsa_dec(target_file, save_folder, passkey) - elif mode == "just_key" and check.password_check(passkey, - passcheck): - rsa_key(passkey, save_folder) - elif mode == "weak_key": - rsa_key(passkey, save_folder) + dec_manager(target_files, key_dir, passkey) + elif mode == "weak_dec" and check.weak_dec(target_files, key_dir): + dec_manager(target_files, key_dir, passkey) + elif mode == "just_key" and check.key(key_dir): + key.just_key_manager(self.type_control.get(), key_dir, passkey) + elif mode == "weak_key" and check.key(key_dir): + key.just_key_manager(self.type_control.get(), key_dir, passkey) - def export(self, settings_window, root): - """Export the data contained in the modified settings variable - derived from the file settings.json, delete the settings window - and restore the launcher window. + def pick_tip(self): + """Return a random string from the tips.json file""" + with open(self.tips_file) as source: + self.tips = json.load(source) + self.tip = "Tip: " + choice(self.tips) + return self.tip + + def close_settings(self, settings_window, root): + """Destroy the settings toplevel and deiconify the root window Keyword arguments: settings_window -- the window of the app to destory root -- the window of the app to deiconify() """ - with open(self.settings_file, "w") as write_file: - json.dump(self.settings, write_file, indent=4, sort_keys=True) settings_window.destroy() root.deiconify() - + def modify_font(self, value): """Change the value of the font_size key in the self.settings variable + and export settings to file. Keyword arguments: value -- the int to which the self.settings variable will change """ self.settings["font_size"] = value - self.frame.update() - - - def modify_auto(self, value): - """Change the value of the auto_update key in the self.settings - variable - - Keyword arguments: - value -- a string, "on" or "off" to be converted to a boolean - """ - bool_val = True if value is "On" else False - self.settings["auto_update"] = bool_val - self.frame.update() + with open(self.settings_file, "w") as fl: + json.dump(self.settings, fl, indent=4, sort_keys=True) - def modify_width(self, value): + def modify_dim(self, value): """Change the value of the win_width key in the self.settings - variable + variable and export settings to file. Keyword arguments: value -- an int represeting the new width of the window """ - self.settings["win_width"] = value - self.frame.update() - - def modify_height(self, value): - """Change the value of the win_height key in the self.settings - variable - - Keyword arguments: - value -- an int represeting the new height of the window - """ - self.settings["win_height"] = value - self.frame.update() + width = int(value.split("x")[0]) + height = int(value.split("x")[1]) + self.settings["win_width"] = width + self.settings["win_height"] = height + with open(self.settings_file, "w") as fl: + json.dump(self.settings, fl, indent=4, sort_keys=True) def toggle_pass(self, *args): """Toogle the password fields between showing the characters and @@ -836,6 +878,12 @@ class App(): self.passcode_input.config(show="*") self.confirm_input.config(show="*") self.show_pass = not self.show_pass + + def select_filepaths(self): + self.crypto_filepaths = filedialog.askopenfilenames() + + def select_key_dir(self): + self.key_paths = filedialog.askdirectory() if __name__ == "__main__": diff --git a/Scripts/initiate_key.py b/Scripts/initiate_key.py @@ -1,55 +0,0 @@ -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import padding -from cryptography.fernet import Fernet - - -def rsa_key(passkey, save_folder): - """Generate and save a private, public and symmetric key. - - Keyword arguments: - save_folder -- the folder to save the keys to (i.e. C://Desktop) - passkey -- the passkey used to enhance the encryption algorithm (OPTIONAL) - """ - #Generating three key objects (symmetric, private, public) - symmetric_key = Fernet.generate_key() - private_key = rsa.generate_private_key( - public_exponent = 65537, - key_size = 4096, - backend = default_backend() - ) - public_key = private_key.public_key() - #Converting the public and private key objects to a saveable format - if passkey != "": # - private_key_passcode = passkey - private_key_text = private_key.private_bytes( - encoding = serialization.Encoding.PEM, - format = serialization.PrivateFormat.PKCS8, - encryption_algorithm = serialization.BestAvailableEncryption( - bytes(private_key_passcode, 'utf-8') - ) - ) - else: - private_key_text = private_key.private_bytes( - encoding = serialization.Encoding.PEM, - format = serialization.PrivateFormat.PKCS8, - encryption_algorithm = serialization.NoEncryption() - ) - public_key_text = public_key.public_bytes( - encoding = serialization.Encoding.PEM, - format = serialization.PublicFormat.SubjectPublicKeyInfo - ) - #Saving the keys to the provided directory. - if save_folder[-1] != '/': - save_folder += '/' - private_key_file = save_folder + 'private_key.pem' - public_key_file = save_folder + 'public_key.pem' - symmetric_key_file = save_folder + 'symmetric_key.key' - with open(private_key_file, 'wb') as private_file, \ - open(public_key_file, 'wb') as public_file, \ - open(symmetric_key_file, 'wb') as symmetric_file: - private_file.write(private_key_text) - public_file.write(public_key_text) - symmetric_file.write(symmetric_key) -\ No newline at end of file diff --git a/Scripts/key.py b/Scripts/key.py @@ -0,0 +1,89 @@ +import os +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import rsa, padding +from cryptography.hazmat.primitives import serialization, hashes +from cryptography.fernet import Fernet + + +def rsa_key(pub, priv, passkey): + """Generate a private and public key to the provided filepaths. + + Keyword arguments: + pub -- path to save the public key + priv -- path to save the private key + """ + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=4096, + backend=default_backend() + ) + public_key = private_key.public_key() + private_key_text = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=( + serialization.BestAvailableEncryption( + bytes(passkey, "utf-8") + ) if passkey != "" else serialization.NoEncryption() + ) + ) + public_key_text = public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo + ) + with open(priv, "wb") as private_file, \ + open(pub, "wb") as public_file: + private_file.write(private_key_text) + public_file.write(public_key_text) + + +def mixed_key(pub, priv, sym, passkey): + """Generate a private, public, and symmetric key to the + provided filepaths. + + Keyword arguments: + pub -- path to save the public key + priv -- path to save the private key + sym -- path to save the symmetric key + """ + rsa_key(pub, priv, passkey) + symmetric_key = Fernet.generate_key() + with open(sym, "wb") as sym_file: + sym_file.write(symmetric_key) + + +def key_manager(target_files, save_folder, passkey): + """Call either the `rsa_key` function or the `mixed_key` + function, according to the needs of the target files. + + Keyword arguments: + target_files -- a list of the files to be encrypted + save_folder -- the directory to save the keys + passkey -- the password to enhance the RSA encryption (OPTIONAL) + """ + priv_src = save_folder + "/private_key.pem" + pub_src = save_folder + "/public_key.pem" + sym_src = save_folder + "/symmetric_key.key" + rsa = True + for fl in target_files: + if os.path.getsize(fl) > 446: + rsa = False + if rsa: + rsa_key(pub_src, priv_src, passkey) + else: + mixed_key( + pub_src, + priv_src, + sym_src, + passkey + ) + +def just_key_manager(mode, save_folder, passkey): + rsa = True if mode == 0 else False + pub_src = save_folder + "/public_key.pem" + priv_src = save_folder + "/private_key.pem" + sym_src = save_folder + "/symmetric_key.key" + if rsa: + rsa_key(pub_src, priv_src, passkey) + else: + mixed_key(pub_src, priv_src, sym_src, passkey) +\ No newline at end of file diff --git a/Scripts/prompts.py b/Scripts/prompts.py @@ -0,0 +1,58 @@ +from tkinter import messagebox + + +def overwrite_prompt(): + """Opens a tkinter messagebox asking if the user wants to + overwrite the previously generated keys detected in the provided + savefolder. Returns `True` if the user clicks ok, `False` if they + click cancel. + """ + return messagebox.askokcancel( + "Overwrite Warning", + ( + "The directory selected contains previously generated keys." + " If you choose to continue, these keys will be overwritten" + " and any files encrypted using these keys will be lost forever." + "\n\nContinue?" + ) + ) + +def password_error(one, two): + """"Raise an error informing the user that the provided passwords + do not match. + """ + messagebox.showwarning( + "Passwords Do Not Match", + ("The passwords provided do not match. Please Try again." + "\n\nFirst: {}\nSecond: {}".format(one, two) + ) + ) + +def file_access_error(broken_paths): + messagebox.showwarning( + "Filepath Access Failure", + ( + "figENC can't access some of the files provided:\n\n" + "Broken Paths:\n%s"%broken_paths + ) + ) + +def key_dir_error(folder): + messagebox.showwarning( + "Directory Access Failure", + ( + "The key directory provided cannot be accessed by figENC." + " Please try again with a new directory.\n\nDirectory" + " provided:\n%s"%folder + ) + ) + +def missing_keys(folder): + messagebox.showwarning( + "Directory Missing Keys", + ( + "The directory provided is missing keys critical to encrypting" + " files. Please correct and try again.\n\nDirectory provided:" + "\n%s"%folder + ) + ) +\ No newline at end of file diff --git a/Scripts/settings.json b/Scripts/settings.json @@ -1,5 +1,4 @@ { - "auto_update": false, "font_size": 16, "win_height": 700, "win_width": 700 diff --git a/Scripts/tips.json b/Scripts/tips.json @@ -5,6 +5,7 @@ "if you give someone access to your keys, they can decrypt your files.\nKeep your keys private!", "figENC supports image encryption as well as text file encryption.\nHide your private pics!", "password encryption on your keys enhances the encryption algorithm,\nfurther securing your files.", + "keys generated by figENC are PEM-compatible, and should\nwork with other encryption programs.", "figENC uses a unique encryption algorithm to provide\nRSA encryption to files of any size.", "figENC's RSA encryption is military grade, and has never been broken\nby hackers or governments.", "fonts in figENC are relative – there's one font size in settings,\nand other sizes are determined based on that selection", diff --git a/Scripts/version.txt b/Scripts/version.txt @@ -1 +1 @@ -1.7.0 -\ No newline at end of file +2.0.0 +\ No newline at end of file diff --git a/Scripts/version_check.py b/Scripts/version_check.py @@ -1,6 +1,4 @@ -import os -import inspect -import requests +import os, inspect, requests, sys from check import find_path def update_available():