2021-04-24 02:59:39 +02:00
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
using System ;
using System.Collections.ObjectModel ;
using System.ComponentModel ;
using System.Diagnostics ;
using System.Globalization ;
using System.IO ;
using System.Media ;
using System.Text ;
using System.Threading.Tasks ;
using System.Windows ;
using System.Windows.Controls ;
using System.Windows.Input ;
using System.Windows.Media ;
using System.Windows.Media.Effects ;
using System.Windows.Shell ;
using System.Windows.Threading ;
using Microsoft.Win32 ;
using com.muldersoft.slunkcrypt.gui.ctrls ;
using com.muldersoft.slunkcrypt.gui.process ;
using com.muldersoft.slunkcrypt.gui.utils ;
namespace com.muldersoft.slunkcrypt.gui
{
public enum ModeOfOperation { Encrypt , Decrypt }
public partial class SlunkCryptGUI : Window , INotifyBusyChanged
{
private enum Status { Default , Success , Failure }
private delegate Task < bool > SlunkProcessor ( string inputFile , string outputFile , string password ) ;
public event PropertyChangedEventHandler PropertyChanged ;
2021-05-08 17:55:16 +02:00
public const int MIN_PASSWD_LENGTH = 8 , REC_PASSWD_LENGTH = 12 , GEN_PASSWD_LENGTH = 24 , MAX_PASSWD_LENGTH = 256 , MAX_PATH = 259 ;
2021-04-24 02:59:39 +02:00
2021-11-13 17:11:08 +01:00
private readonly ApplicationConfig m_config = new ApplicationConfig ( ) ;
2021-04-24 02:59:39 +02:00
private readonly Lazy < string > m_about = new Lazy < string > ( CreateAboutText ) ;
private readonly Random m_random = new Random ( ) ;
private readonly ObservableCollection < string > m_logFile = new ObservableCollection < string > ( ) ;
private readonly string m_defaultStatusText ;
private readonly DispatcherTimer m_dispatcherTimer ;
private readonly ReadOnlyObservableCollection < string > m_logFileReadOnly ;
private volatile ModeOfOperation m_modeOfOperation = ( ModeOfOperation ) ( - 1 ) ;
2021-11-11 21:36:13 +01:00
private volatile bool m_busyFlag = false , m_checksumError = false , m_processReceived = false , m_disableAnimation = false ;
2021-04-24 02:59:39 +02:00
private volatile SlunkCryptRunner m_processRunner = null ;
2021-11-11 21:36:13 +01:00
private uint? m_menuId_disableAnimation = null , m_menuId_enableExpertMode = null ;
2021-04-24 02:59:39 +02:00
2021-05-08 17:55:16 +02:00
private const string ASCII_CHARS = "!#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~" ;
2021-04-24 02:59:39 +02:00
// =============================================================================
// Constructor
// =============================================================================
public SlunkCryptGUI ( )
{
InitializeComponent ( ) ;
m_defaultStatusText = Label_Status . Text ;
2021-11-11 21:36:13 +01:00
m_dispatcherTimer = new DispatcherTimer ( DispatcherPriority . ApplicationIdle , Dispatcher ) ;
2021-04-24 02:59:39 +02:00
m_dispatcherTimer . Tick + = DispatcherTimer_Tick ;
2021-11-11 21:36:13 +01:00
m_dispatcherTimer . Interval = TimeSpan . FromMilliseconds ( 200 ) ;
2021-04-24 02:59:39 +02:00
m_logFileReadOnly = new ReadOnlyObservableCollection < string > ( m_logFile ) ;
2021-11-13 17:11:08 +01:00
m_disableAnimation = m_config . DisableBusyIndicator ;
2021-04-24 02:59:39 +02:00
}
// =============================================================================
// Properties
// =============================================================================
public bool IsBusy
{
get
{
return m_busyFlag ;
}
set
{
2021-11-11 21:36:13 +01:00
if ( m_busyFlag ! = value )
{
m_dispatcherTimer . IsEnabled = ( m_busyFlag = value ) & & ( ! m_disableAnimation ) ;
NotifyPropertyChanged ( "IsBusy" ) ;
NotifyPropertyChanged ( "IsBusyIndicatorVisible" ) ;
}
}
}
public bool IsBusyIndicatorVisible
{
get
{
return m_busyFlag & & ( ! m_disableAnimation ) ;
2021-04-24 02:59:39 +02:00
}
}
public ReadOnlyObservableCollection < string > LogFile
{
get
{
return m_logFileReadOnly ;
}
}
// =============================================================================
// Event handlers
// =============================================================================
protected override void OnContentRendered ( EventArgs e )
{
base . OnContentRendered ( e ) ;
TabControl . MinHeight = TabControl . MaxHeight = TabControl . ActualHeight ;
MinWidth = MaxWidth = ActualWidth ;
MinHeight = MaxHeight = ActualHeight ;
}
private void Button_Encrypt_InputFile_Click ( object sender , RoutedEventArgs e )
{
string fileName ;
if ( ! string . IsNullOrEmpty ( fileName = BrowseForFile ( Edit_Encrypt_InputFile . Text , false ) ) )
{
Edit_Encrypt_InputFile . Text = fileName ;
Edit_Encrypt_OutputFile . Text = GenerateEncryptOutputFileName ( fileName ) ;
}
}
private void Button_Encrypt_OutputFile_Click ( object sender , RoutedEventArgs e )
{
string fileName ;
if ( ! string . IsNullOrEmpty ( fileName = BrowseForFile ( Edit_Encrypt_OutputFile . Text , true , "Encrypted file (*.enc)|*.enc" ) ) )
{
Edit_Encrypt_OutputFile . Text = fileName ;
}
}
private void Button_Decrypt_InputFile_Click ( object sender , RoutedEventArgs e )
{
string fileName ;
if ( ! string . IsNullOrEmpty ( fileName = BrowseForFile ( Edit_Decrypt_InputFile . Text , false ) ) )
{
Edit_Decrypt_InputFile . Text = fileName ;
Edit_Decrypt_OutputFile . Text = GenerateDecryptOutputFileName ( fileName ) ;
}
}
private void Button_Decrypt_OutputFile_Click ( object sender , RoutedEventArgs e )
{
string fileName ;
if ( ! string . IsNullOrEmpty ( fileName = BrowseForFile ( Edit_Decrypt_OutputFile . Text , true , "Decrypted file (*.out)|*.out" ) ) )
{
Edit_Decrypt_OutputFile . Text = fileName ;
}
}
2021-05-08 17:55:16 +02:00
private async void Button_GeneratePasswd_Click ( object sender , RoutedEventArgs e )
{
using ( BusyManager busy = new BusyManager ( this ) )
{
Edit_Encrypt_Password . Password = string . Empty ;
Task < string > password = Task . Run ( ( ) = > GenerateRandomString ( GEN_PASSWD_LENGTH ) ) ;
await Task . WhenAll ( password , Task . Delay ( 500 ) ) ;
Button_Encrypt_Toggle . IsChecked = true ;
Edit_Encrypt_Password . Password = password . Result ;
}
}
2021-04-24 02:59:39 +02:00
private async void Button_Start_Click ( object sender , RoutedEventArgs e )
{
if ( ! IsBusy )
{
ResetKeyboardFocus ( Button_Start ) ;
switch ( GetModeOfOperation ( TabControl . SelectedItem ) )
{
case ModeOfOperation . Encrypt :
Debug . Assert ( m_modeOfOperation = = ModeOfOperation . Encrypt ) ;
await ValidateInputFile ( Edit_Encrypt_InputFile , Edit_Encrypt_OutputFile , Edit_Encrypt_Password , Encrypt , true ) ;
break ;
case ModeOfOperation . Decrypt :
Debug . Assert ( m_modeOfOperation = = ModeOfOperation . Decrypt ) ;
await ValidateInputFile ( Edit_Decrypt_InputFile , Edit_Decrypt_OutputFile , Edit_Decrypt_Password , Decrypt , false ) ;
break ;
default :
TabControl . SelectedIndex = GetTabIndexOf ( m_modeOfOperation ) ;
break ;
}
}
}
private void Button_About_Click ( object sender , RoutedEventArgs e )
{
if ( ! IsBusy )
{
MessageBox . Show ( this , m_about . Value , "About..." , MessageBoxButton . OK , MessageBoxImage . Information ) ;
}
}
private void Button_Exit_Click ( object sender , RoutedEventArgs e )
{
if ( ! IsBusy )
{
Application . Current . Shutdown ( ) ;
}
}
private void TabControl_SelectionChanged ( object sender , SelectionChangedEventArgs e )
{
foreach ( object currrentItem in e . AddedItems )
{
ModeOfOperation ? modeOfOperation = GetModeOfOperation ( currrentItem ) ;
if ( modeOfOperation . HasValue )
{
if ( m_modeOfOperation ! = modeOfOperation . Value )
{
SetStatus ( m_defaultStatusText ) ;
ClearProgress ( ) ;
m_modeOfOperation = modeOfOperation . Value ;
}
}
break ;
}
}
private void Button_AbortProcess_Click ( object sender , RoutedEventArgs e )
{
AbortProcess ( ) ;
}
private void Link_CopyToClipboard_Click ( object sender , MouseButtonEventArgs e )
{
if ( m_logFile . Count > 0 )
{
StringBuilder builder = new StringBuilder ( ) ;
foreach ( string logItem in m_logFile )
{
builder . AppendLine ( logItem ) ;
}
Clipboard . SetText ( builder . ToString ( ) ) ;
SystemSounds . Beep . Play ( ) ;
}
}
private void Link_ClearLog_Click ( object sender , MouseButtonEventArgs e )
{
if ( m_logFile . Count > 0 )
{
ClearLogFile ( ) ;
SystemSounds . Beep . Play ( ) ;
}
}
private void Process_OutputAvailable ( string line , bool stderr )
{
AppendLogFile ( line ) ;
if ( line . IndexOf ( "Checksum mismatch detected!" , StringComparison . OrdinalIgnoreCase ) > = 0 )
{
m_checksumError = true ;
}
}
private void Porcess_ProgressChanged ( double progress )
{
if ( ! m_processReceived )
{
switch ( m_modeOfOperation )
{
case ModeOfOperation . Encrypt :
SetStatus ( "Encrypting file contents. Please be patient, this can take a few moments..." ) ;
goto default ;
case ModeOfOperation . Decrypt :
SetStatus ( "Decrypting file contents. Please be patient, this can take a few moments..." ) ;
goto default ;
default :
m_processReceived = true ;
break ;
}
}
SetProgress ( progress ) ;
}
private void Edit_FileName_KeyDown ( object sender , KeyEventArgs e )
{
if ( e . Key = = Key . Return )
{
FrameworkElement source = sender as FrameworkElement ;
if ( ! ReferenceEquals ( source , null ) )
{
FrameworkElement target = source . Tag as FrameworkElement ;
if ( ! ReferenceEquals ( target , null ) )
{
SetFocusAndSelectAll ( target ) ;
}
}
e . Handled = true ;
}
}
private void Edit_Password_Entered ( object sender , KeyEventArgs e )
{
if ( ! IsBusy )
{
Button_Start_Click ( sender , e ) ;
}
}
private void Edit_FileName_LostFocus ( object sender , RoutedEventArgs e )
{
TextBox textBox ;
if ( ! ReferenceEquals ( textBox = sender as TextBox , null ) )
{
textBox . Text = PathUtils . CleanUpFilePathString ( textBox . Text ) ;
}
}
private void Image_MouseLeftButtonDown ( object sender , MouseButtonEventArgs e )
{
DragMove ( ) ;
}
private void Window_PreviewKeyDown ( object sender , KeyEventArgs e )
{
if ( e . Key = = Key . Escape )
{
AbortProcess ( ) ;
}
}
protected void Window_PreviewDragEnter ( object sender , DragEventArgs e )
{
e . Effects = ( ( ! IsBusy ) & & e . Data . GetDataPresent ( DataFormats . FileDrop ) ) ? DragDropEffects . Copy : DragDropEffects . None ;
e . Handled = true ;
}
private void Window_PreviewDragLeave ( object sender , DragEventArgs e )
{
e . Handled = true ;
}
private void Window_PreviewDrop ( object sender , DragEventArgs e )
{
if ( ! IsBusy )
{
string [ ] droppedFiles = e . Data . GetData ( DataFormats . FileDrop ) as string [ ] ;
if ( ! ReferenceEquals ( droppedFiles , null ) )
{
foreach ( string currentFile in droppedFiles )
{
string fullFilePath = PathUtils . CleanUpFilePathString ( currentFile ) ;
if ( ( ! string . IsNullOrEmpty ( fullFilePath ) ) & & File . Exists ( fullFilePath ) )
{
TabControl . SelectedIndex = GetTabIndexOf ( m_modeOfOperation ) ;
switch ( m_modeOfOperation )
{
case ModeOfOperation . Encrypt :
Edit_Encrypt_InputFile . Text = fullFilePath ;
Edit_Encrypt_OutputFile . Text = GenerateEncryptOutputFileName ( fullFilePath ) ;
break ;
case ModeOfOperation . Decrypt :
Edit_Decrypt_InputFile . Text = fullFilePath ;
Edit_Decrypt_OutputFile . Text = GenerateDecryptOutputFileName ( fullFilePath ) ;
break ;
}
break ;
}
}
}
}
e . Handled = true ;
}
private async void Window_Loaded ( object sender , RoutedEventArgs e )
{
await Task . Yield ( ) ;
2021-11-11 21:36:13 +01:00
SystemMenu systemMenu = new SystemMenu ( this , SystemMenu_Activated ) ;
m_menuId_disableAnimation = systemMenu . AppendMenu ( "Disable Busy Indicator" ) ;
m_menuId_enableExpertMode = systemMenu . AppendMenu ( "Expert Settings" ) ;
2021-11-13 17:11:08 +01:00
if ( m_disableAnimation & & m_menuId_disableAnimation . HasValue )
{
systemMenu . ModifyMenu ( m_menuId_disableAnimation . Value , m_disableAnimation ) ;
}
2021-04-24 02:59:39 +02:00
CreateIndicatorElements ( ) ;
}
private void Window_Closing ( object sender , CancelEventArgs e )
{
if ( IsBusy )
{
SystemSounds . Hand . Play ( ) ;
e . Cancel = true ;
}
}
private void DispatcherTimer_Tick ( object sender , EventArgs e )
{
ShuffleIndicatorElements ( ) ;
}
private void SystemMenu_Activated ( SystemMenu sender , uint menuId )
{
2021-11-11 21:36:13 +01:00
if ( m_menuId_disableAnimation . HasValue & & ( menuId = = m_menuId_disableAnimation . Value ) )
{
sender . ModifyMenu ( menuId , m_disableAnimation = ! m_disableAnimation ) ;
if ( m_busyFlag )
{
m_dispatcherTimer . IsEnabled = ! m_disableAnimation ;
NotifyPropertyChanged ( "IsBusyIndicatorVisible" ) ;
}
}
else if ( m_menuId_enableExpertMode . HasValue & & ( menuId = = m_menuId_enableExpertMode . Value ) )
2021-04-24 02:59:39 +02:00
{
try
{
Process . Start ( "https://youtu.be/Is_8bjYVmnA" ) . Dispose ( ) ;
}
catch { }
}
}
// =============================================================================
// Internal methods
// =============================================================================
private async Task ValidateInputFile ( TextBox inputFileEdit , TextBox outputFileEdit , PasswordToggleBox passwordEdit , SlunkProcessor processor , bool checkStrongPasswd )
{
string inputFilePath ;
if ( string . IsNullOrEmpty ( inputFileEdit . Text = inputFilePath = PathUtils . CleanUpFilePathString ( inputFileEdit . Text ) ) )
{
MessageBox . Show ( this , "Input file must be selected first!" , "Input File Missing" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
SetFocusAndSelectAll ( inputFileEdit ) ;
return ;
}
if ( PathUtils . IsInvalidPath ( inputFilePath ) )
{
MessageBox . Show ( this , "The specified input file path is invalid!" , "Input File Invalid" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
SetFocusAndSelectAll ( inputFileEdit ) ;
return ;
}
if ( Directory . Exists ( inputFilePath ) )
{
MessageBox . Show ( this , "Specified input file appears to be a directory!" , "Input File Invalid" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
SetFocusAndSelectAll ( inputFileEdit ) ;
return ;
}
if ( ! File . Exists ( inputFilePath ) )
{
MessageBox . Show ( this , "Specified input file could not be found!" , "Input Not Found" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
SetFocusAndSelectAll ( inputFileEdit ) ;
return ;
}
await ValidateOutputFile ( inputFilePath , outputFileEdit , passwordEdit , processor , checkStrongPasswd ) ;
}
private async Task ValidateOutputFile ( string inputFilePath , TextBox outputFileEdit , PasswordToggleBox passwordEdit , SlunkProcessor processor , bool checkStrongPasswd )
{
string outputFilePath ;
if ( string . IsNullOrEmpty ( outputFileEdit . Text = outputFilePath = PathUtils . CleanUpFilePathString ( outputFileEdit . Text ) ) )
{
MessageBox . Show ( this , "Output file must be selected first!" , "Output File Missing" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
SetFocusAndSelectAll ( outputFileEdit ) ;
return ;
}
if ( PathUtils . IsInvalidPath ( outputFilePath ) )
{
MessageBox . Show ( this , "The specified output file path is invalid!" , "Output File Invalid" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
SetFocusAndSelectAll ( outputFileEdit ) ;
return ;
}
if ( Directory . Exists ( outputFilePath ) )
{
MessageBox . Show ( this , "Specified output file appears to be a directory!" , "Output File Invalid" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
SetFocusAndSelectAll ( outputFileEdit ) ;
return ;
}
if ( string . Equals ( inputFilePath , outputFilePath , StringComparison . OrdinalIgnoreCase ) )
{
MessageBox . Show ( this , "Input and output file can not be the same!" , "File Name Conflict" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
SetFocusAndSelectAll ( outputFileEdit ) ;
return ;
}
if ( File . Exists ( outputFilePath ) )
{
if ( MessageBox . Show ( this , "Specified output file already existst! Overwrite?" , "Output File Exists" , MessageBoxButton . YesNo , MessageBoxImage . Question , MessageBoxResult . No ) ! = MessageBoxResult . Yes )
{
SetFocusAndSelectAll ( outputFileEdit ) ;
return ;
}
}
await ValidateOutputDirectory ( inputFilePath , outputFilePath , passwordEdit , processor , checkStrongPasswd ) ;
}
private async Task ValidateOutputDirectory ( string inputFilePath , string outputFilePath , PasswordToggleBox passwordEdit , SlunkProcessor processor , bool checkStrongPasswd )
{
string outputDirectory ;
if ( string . IsNullOrEmpty ( outputDirectory = PathUtils . TryGetDirectoryName ( outputFilePath ) ) )
{
MessageBox . Show ( this , "The output directory could not be determined!" , "Output Directory Invalid" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
return ;
}
while ( ! Directory . Exists ( outputDirectory ) )
{
if ( MessageBox . Show ( this , "Output directory does not exist yet! Create it now?" , "Output Directory Nonexistent" , MessageBoxButton . YesNo , MessageBoxImage . Question , MessageBoxResult . Yes ) ! = MessageBoxResult . Yes )
{
return ;
}
if ( ! PathUtils . TryCreateDirectory ( outputDirectory ) )
{
MessageBox . Show ( this , "The output directory could not be created!" , "Directory Creation Failed" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
return ;
}
}
await ValidatePassword ( inputFilePath , outputFilePath , passwordEdit , processor , checkStrongPasswd ) ;
}
private async Task ValidatePassword ( string inputFilePath , string outputFilePath , PasswordToggleBox passwordEdit , SlunkProcessor processor , bool checkStrongPasswd )
{
string passwordStr ;
if ( string . IsNullOrEmpty ( passwordStr = passwordEdit . Password ) | | ( passwordStr . Length < MIN_PASSWD_LENGTH ) )
{
MessageBox . Show ( this , String . Format ( "Passphrase must be at least {0:D} characters in length!" , MIN_PASSWD_LENGTH ) , "Passphrase Missing" , MessageBoxButton . OK , MessageBoxImage . Warning ) ;
SetFocusAndSelectAll ( passwordEdit ) ;
return ;
}
if ( checkStrongPasswd )
{
if ( passwordStr . Length < REC_PASSWD_LENGTH )
{
if ( MessageBox . Show ( this , String . Format ( "Recommended passphrase length is at least {0:D} characters!" , REC_PASSWD_LENGTH ) , "Short Passphrase" , MessageBoxButton . OKCancel , MessageBoxImage . Warning , MessageBoxResult . Cancel ) ! = MessageBoxResult . OK )
{
SetFocusAndSelectAll ( passwordEdit ) ;
return ;
}
}
else if ( IsWeakPassword ( passwordStr ) )
{
if ( MessageBox . Show ( this , "Passphrase should contain a mix of upper case characters, lower case characters, digits and other characters!" , "Weak Passphrase" , MessageBoxButton . OKCancel , MessageBoxImage . Warning , MessageBoxResult . Cancel ) ! = MessageBoxResult . OK )
{
SetFocusAndSelectAll ( passwordEdit ) ;
return ;
}
}
}
await InvokeProcessor ( inputFilePath , outputFilePath , passwordStr , processor ) ;
}
private async Task InvokeProcessor ( string inputFile , string outputFile , string password , SlunkProcessor processor )
{
using ( BusyManager busyManager = new BusyManager ( this ) )
{
ResetKeyboardFocus ( this ) ;
SetProgress ( double . PositiveInfinity ) ;
ClearLogFile ( ) ;
Button_Decrypt_Toggle . IsChecked = Button_Encrypt_Toggle . IsChecked = m_checksumError = m_processReceived = false ;
if ( ! await processor ( inputFile , outputFile , password ) )
{
SetProgress ( double . NaN , true ) ;
PathUtils . TryRemoveFile ( outputFile ) ;
}
await Task . Yield ( ) ;
}
}
private async Task < bool > Encrypt ( string inputFile , string outputFile , string password )
{
SetStatus ( "Please wait while the encryption process is initializing..." ) ;
int? exitCode = await RunProcess ( SlunkCryptRunner . Mode . Encrypt , inputFile , outputFile , password ) ;
if ( exitCode . HasValue )
{
if ( exitCode . Value = = 0 )
{
SetProgress ( 1 ) ;
SetStatus ( "Completed: The file has been encrypted successfully." , Status . Success ) ;
SystemSounds . Asterisk . Play ( ) ;
}
else
{
SetProgress ( 1 , true ) ;
SetStatus ( "Error: Failed to enecrypt the file. Please see the log file for details!" , Status . Failure ) ;
SystemSounds . Hand . Play ( ) ;
}
return true ;
}
return false ;
}
private async Task < bool > Decrypt ( string inputFile , string outputFile , string password )
{
SetStatus ( "Please wait while the decryption process is initializing..." ) ;
int? exitCode = await RunProcess ( SlunkCryptRunner . Mode . Decrypt , inputFile , outputFile , password ) ;
if ( exitCode . HasValue )
{
if ( exitCode . Value = = 0 )
{
SetStatus ( "Completed: The file has been decrypted successfully (checksum is correct)." , Status . Success ) ;
SetProgress ( 1 ) ;
SystemSounds . Asterisk . Play ( ) ;
}
else
{
if ( m_checksumError )
{
SetStatus ( "Error: Checksum mismatch detected! Wrong passphrase or corrupted file?" , Status . Failure ) ;
}
else
{
SetStatus ( "Error: Failed to decrypt the file. Please see the log file for details!" , Status . Failure ) ;
}
SetProgress ( 1 , true ) ;
SystemSounds . Hand . Play ( ) ;
}
return true ;
}
return false ;
}
private async Task < int? > RunProcess ( SlunkCryptRunner . Mode mode , string inputFile , string outputFile , string password )
{
if ( ! ReferenceEquals ( m_processRunner , null ) )
{
throw new InvalidOperationException ( "Process has already been started!" ) ;
}
try
{
using ( m_processRunner = new SlunkCryptRunner ( Dispatcher ) )
{
m_processRunner . OutputAvailable + = Process_OutputAvailable ;
m_processRunner . ProgressChanged + = Porcess_ProgressChanged ;
SetProcessPriority ( ProcessPriorityClass . AboveNormal ) ;
return await m_processRunner . ExecuteAsync ( mode , inputFile , outputFile , password ) ;
}
}
catch ( ProcessRunner . ProcessStartException err )
{
SetStatus ( string . Format ( "Error: The {0} process could not be created! (Error code: {1:D})" , GetModeString ( m_modeOfOperation ) , GetWin32ErrorCode ( err ) ) , Status . Failure ) ;
MessageBox . Show ( this , "Failed to create SlunkCrypt process:\n\n" + err . InnerException ? . Message ? ? err . Message , "Process Creation Error" , MessageBoxButton . OK , MessageBoxImage . Error ) ;
}
catch ( SlunkCryptRunner . ExecutableNotFoundException )
{
SetStatus ( "Error: The required SlunkCrypt executable file could not be found!" , Status . Failure ) ;
MessageBox . Show ( this , "The SlunkCrypt executable file could not be found.\n\nPlease make sure that the SlunkCrypt CLI executable file is located in the same directory as the GUI program!" , "Executable Not Found" , MessageBoxButton . OK , MessageBoxImage . Error ) ;
}
catch ( ProcessRunner . ProcessInterruptedException )
{
SetStatus ( string . Format ( "Aborted: The {0} process was aborted by the user!" , GetModeString ( m_modeOfOperation ) ) , Status . Failure ) ;
SystemSounds . Hand . Play ( ) ;
}
finally
{
m_processRunner = null ; /*final clean-up*/
}
return null ;
}
private void SetStatus ( string text , Status status = Status . Default )
{
switch ( status )
{
case Status . Success :
Label_Status . Foreground = Brushes . DarkGreen ;
break ;
case Status . Failure :
Label_Status . Foreground = Brushes . DarkRed ;
break ;
default :
Label_Status . Foreground = SystemColors . WindowTextBrush ;
break ;
}
Label_Status . Text = text ;
}
private void SetProgress ( double progress , bool failed = false )
{
if ( ! ( double . IsNaN ( progress ) | | double . IsInfinity ( progress ) ) )
{
ProgressBar . IsIndeterminate = false ;
ProgressBar . Value = progress ;
TaskbarItemInfo . ProgressState = failed ? TaskbarItemProgressState . Error : TaskbarItemProgressState . Normal ;
TaskbarItemInfo . ProgressValue = progress ;
Label_Progress . Text = string . Format ( CultureInfo . InvariantCulture , "{0:0.0}%" , progress * 100.0 ) ;
}
else
{
if ( double . IsInfinity ( progress ) )
{
ProgressBar . IsIndeterminate = true ;
ProgressBar . Value = 0 ;
TaskbarItemInfo . ProgressState = TaskbarItemProgressState . Indeterminate ;
Label_Progress . Text = string . Empty ;
}
else
{
ProgressBar . IsIndeterminate = false ;
TaskbarItemInfo . ProgressState = failed ? TaskbarItemProgressState . Error : TaskbarItemProgressState . None ;
}
}
}
private void ClearProgress ( )
{
ProgressBar . IsIndeterminate = false ;
ProgressBar . Value = 0 ;
TaskbarItemInfo . ProgressState = TaskbarItemProgressState . None ;
Label_Progress . Text = string . Empty ;
}
private void AbortProcess ( )
{
ProcessRunner processRunner ;
if ( ! ReferenceEquals ( processRunner = m_processRunner , null ) )
{
try
{
processRunner . AbortProcess ( ) ;
}
catch { }
}
}
private string BrowseForFile ( string fileName , bool saveDialog , string filterString = null )
{
FileDialog openFileDialog = saveDialog ? new SaveFileDialog ( ) { OverwritePrompt = false } : ( FileDialog ) new OpenFileDialog ( ) ;
openFileDialog . Filter = string . IsNullOrEmpty ( filterString ) ? "All files (*.*)|*.*" : filterString ;
if ( ! string . IsNullOrEmpty ( fileName ) )
{
openFileDialog . FileName = fileName ;
}
if ( openFileDialog . ShowDialog ( ) . GetValueOrDefault ( false ) )
{
return openFileDialog . FileName ;
}
return null ;
}
private void CreateIndicatorElements ( )
{
FontFamily hackFont = new FontFamily ( new Uri ( "pack://application:,,,/" ) , "./Resources/Fonts/#Hack" ) ;
DropShadowEffect dropShadowEffect = CreateShadowEffect ( Colors . Black , 3.0 ) ;
TextBlock reference = CreateTextBlock ( '0' , Brushes . Gold , hackFont , dropShadowEffect ) ;
reference . Measure ( new Size ( double . MaxValue , double . MaxValue ) ) ;
Size desiredSize = reference . DesiredSize ;
double actualWidth = Canvas . ActualWidth , actualHeight = Canvas . ActualHeight ;
int lenX = ( int ) Math . Ceiling ( desiredSize . Width * 1.25 ) ;
int lenY = ( int ) Math . Ceiling ( desiredSize . Height * 1.25 ) ;
int numX = ( int ) Math . Floor ( actualWidth / lenX ) ;
int numY = ( int ) Math . Floor ( actualHeight / lenY ) ;
int offX = ( int ) Math . Round ( ( actualWidth - ( numX * lenX ) ) / 2.0 ) ;
int offY = ( int ) Math . Round ( ( actualHeight - ( numY * lenY ) ) / 2.0 ) ;
for ( int i = 0 ; i < numX ; + + i )
{
for ( int j = 0 ; j < numY ; + + j )
{
TextBlock element = CreateTextBlock ( '0' , Brushes . Gold , hackFont , dropShadowEffect ) ;
Canvas . Children . Add ( element ) ;
Canvas . SetLeft ( element , offX + ( i * lenX ) ) ;
Canvas . SetTop ( element , offY + ( j * lenY ) ) ;
}
}
ShuffleIndicatorElements ( ) ;
}
private void ShuffleIndicatorElements ( )
{
char [ ] chars = ASCII_CHARS . ToCharArray ( ) ;
UIElementCollection children = Canvas . Children ;
for ( int i = 0 ; i < children . Count ; + + i )
{
TextBlock element ;
if ( ! ReferenceEquals ( element = children [ i ] as TextBlock , null ) )
{
if ( m_random . Next ( 7 ) = = 0 )
{
element . Visibility = Visibility . Visible ;
element . Text = char . ToString ( chars [ m_random . Next ( chars . Length ) ] ) ;
}
else
{
element . Visibility = Visibility . Hidden ;
}
}
}
}
private void AppendLogFile ( string line )
{
if ( ! string . IsNullOrEmpty ( line ) )
{
m_logFile . Add ( line ) ;
}
}
private int GetTabIndexOf ( ModeOfOperation modeOfOperation )
{
ItemCollection collection = TabControl . Items ;
for ( int index = 0 ; index < collection . Count ; + + index )
{
ModeOfOperation ? current = GetModeOfOperation ( collection [ index ] ) ;
if ( current . HasValue & & ( current . Value = = modeOfOperation ) )
{
return index ;
}
}
return - 1 ;
}
private void ClearLogFile ( )
{
m_logFile . Clear ( ) ;
}
private void NotifyPropertyChanged ( string name )
{
PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( name ) ) ;
}
// -----------------------------------------------------------------------------
// Static methods
// -----------------------------------------------------------------------------
private static string CreateAboutText ( )
{
2021-11-07 21:18:33 +01:00
CPUFeatures cpuFeatures = CPUFeatures . Features ;
2021-04-24 02:59:39 +02:00
return new StringBuilder ( )
. AppendLine ( "SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de>" )
. AppendLine ( VersionInfo . VersionStr )
. AppendLine ( "This work has been released under the \u201CCC0 1.0\u201D license!" )
. AppendLine ( )
. AppendLine ( "Source-code repository:" )
. AppendLine ( "https://gitlab.com/lord_mulder/slunkcrypt/" )
. AppendLine ( )
. AppendLine ( "Operating System: " + Environment . OSVersion . VersionString )
2021-11-07 21:18:33 +01:00
. AppendLine ( string . Format ( "Operating System Bitness: {0:D}, Process Bitness: {1:D}" , Environment . Is64BitOperatingSystem ? 64 : 32 , Environment . Is64BitProcess ? 64 : 32 ) )
2021-04-24 02:59:39 +02:00
. AppendLine ( ".NET Runtime Version: " + Environment . Version )
2021-11-07 21:18:33 +01:00
. AppendLine ( string . Format ( "CPU Count: {0:D}, Architecture: {1}, SSE2 Supported: {2}" , Environment . ProcessorCount , cpuFeatures . x64 ? "x64" : "x86" , cpuFeatures . sse2 ? "Yes" : "No" ) )
2021-04-24 02:59:39 +02:00
. AppendLine ( )
2021-11-07 21:18:33 +01:00
. AppendLine ( "Using “Silk” icons, by Mark James" )
2021-04-24 02:59:39 +02:00
. ToString ( ) ;
}
private static string GenerateEncryptOutputFileName ( string inputFilePath )
{
string directoryPath = Path . GetDirectoryName ( inputFilePath ) , fileName = Path . GetFileNameWithoutExtension ( inputFilePath ) , extension = Path . GetExtension ( inputFilePath ) ;
string outputFile = Path . Combine ( directoryPath , string . Format ( "{0}{1}.enc" , fileName , extension ) ) ;
for ( int count = 2 ; File . Exists ( outputFile ) ; + + count )
{
outputFile = Path . Combine ( directoryPath , string . Format ( "{0} ({1:D}){2}.enc" , fileName , count , extension ) ) ;
}
return outputFile ;
}
private static string GenerateDecryptOutputFileName ( string inputFilePath )
{
string directoryPath = Path . GetDirectoryName ( inputFilePath ) , fileName = Path . GetFileNameWithoutExtension ( inputFilePath ) , extension = Path . GetExtension ( inputFilePath ) ;
while ( extension . Equals ( ".enc" , StringComparison . OrdinalIgnoreCase ) )
{
extension = Path . GetExtension ( fileName ) ;
fileName = Path . GetFileNameWithoutExtension ( fileName ) ;
}
if ( string . IsNullOrEmpty ( extension ) )
{
extension = ".out" ;
}
string outputFile = Path . Combine ( directoryPath , string . Concat ( fileName , extension ) ) ;
for ( int count = 2 ; File . Exists ( outputFile ) ; + + count )
{
outputFile = Path . Combine ( directoryPath , String . Format ( "{0} ({1:D}){2}" , fileName , count , extension ) ) ;
}
return outputFile ;
}
private static ModeOfOperation ? GetModeOfOperation ( object selectedItem )
{
TabItem selectedTabItem = selectedItem as TabItem ;
if ( ! ReferenceEquals ( selectedTabItem , null ) )
{
return selectedTabItem . Tag as ModeOfOperation ? ;
}
return null ;
}
private static string GetModeString ( ModeOfOperation modeOfOperation )
{
switch ( modeOfOperation )
{
case ModeOfOperation . Encrypt :
return "encryption" ;
case ModeOfOperation . Decrypt :
return "decryption" ;
default :
throw new ArgumentException ( "modeOfOperation" ) ;
}
}
private static bool IsWeakPassword ( string password )
{
int flags = 0 ;
foreach ( char c in password )
{
if ( char . IsLetter ( c ) )
{
flags | = char . IsUpper ( c ) ? 0x2 : 0x1 ;
}
else
{
flags | = char . IsDigit ( c ) ? 0x8 : 0x4 ;
}
}
return ( flags ! = 0xF ) ;
}
2021-05-08 17:55:16 +02:00
private static string GenerateRandomString ( int length )
{
if ( length > 0 )
{
char [ ] asciiChars = ASCII_CHARS . ToCharArray ( ) ;
using ( SecureRandom secureRandom = new SecureRandom ( ) )
{
string result ;
do
{
StringBuilder builder = new StringBuilder ( ) ;
for ( int i = 0 ; i < length ; + + i )
{
builder . Append ( asciiChars [ secureRandom . NextUInt32 ( ) % ( ( uint ) asciiChars . Length ) ] ) ;
}
result = builder . ToString ( ) ;
}
while ( ( ! char . IsLetterOrDigit ( result [ 0 ] ) ) | | ( ! char . IsLetterOrDigit ( result [ result . Length - 1 ] ) ) | | IsWeakPassword ( result ) ) ;
return result ;
}
}
return string . Empty ;
}
2021-04-24 02:59:39 +02:00
private static void SetFocusAndSelectAll ( FrameworkElement element )
{
TextBox textBox ;
if ( ! ReferenceEquals ( textBox = element as TextBox , null ) )
{
textBox . Focus ( ) ;
textBox . SelectAll ( ) ;
}
else
{
PasswordToggleBox passwordToggleBox ;
if ( ! ReferenceEquals ( passwordToggleBox = element as PasswordToggleBox , null ) )
{
passwordToggleBox . Focus ( ) ;
passwordToggleBox . SelectAll ( ) ;
}
}
}
private static void SetProcessPriority ( ProcessPriorityClass priorityClass )
{
try
{
using ( Process currentProcess = Process . GetCurrentProcess ( ) )
{
currentProcess . PriorityClass = priorityClass ;
}
}
catch { }
}
private static int GetWin32ErrorCode ( Exception err )
{
while ( ! ReferenceEquals ( err , null ) )
{
if ( err is Win32Exception )
{
return ( ( Win32Exception ) err ) . NativeErrorCode ;
}
err = err . InnerException ;
}
return 0 ;
}
private static TextBlock CreateTextBlock ( char c , Brush foreground , FontFamily fontFamily , Effect effect )
{
return new TextBlock ( )
{
Text = char . ToString ( c ) ,
Foreground = foreground ,
FontFamily = fontFamily ,
Effect = effect
} ;
}
private static DropShadowEffect CreateShadowEffect ( Color color , double blurRadius )
{
return new DropShadowEffect ( )
{
Color = color ,
BlurRadius = blurRadius ,
Direction = 0.0 ,
ShadowDepth = 0.0
} ;
}
private static void ResetKeyboardFocus ( UIElement element )
{
Keyboard . ClearFocus ( ) ;
element . Focus ( ) ;
}
}
}