1 /******************************************************************************/
2 /* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
3 /* This work has been released under the CC0 1.0 Universal license! */
4 /******************************************************************************/
7 using System.Collections.ObjectModel;
8 using System.ComponentModel;
9 using System.Diagnostics;
10 using System.Globalization;
14 using System.Threading.Tasks;
16 using System.Windows.Controls;
17 using System.Windows.Input;
18 using System.Windows.Media;
19 using System.Windows.Media.Effects;
20 using System.Windows.Shell;
21 using System.Windows.Threading;
22 using Microsoft.Win32;
24 using com.muldersoft.slunkcrypt.gui.ctrls;
25 using com.muldersoft.slunkcrypt.gui.process;
26 using com.muldersoft.slunkcrypt.gui.utils;
28 namespace com.muldersoft.slunkcrypt.gui
30 public enum ModeOfOperation { Encrypt, Decrypt }
32 public partial class SlunkCryptGUI : Window, INotifyBusyChanged
34 private enum Status { Default, Success, Failure }
35 private delegate Task<bool> SlunkProcessor(string inputFile, string outputFile, string password);
37 public event PropertyChangedEventHandler PropertyChanged;
38 public const int MIN_PASSWD_LENGTH = 8, REC_PASSWD_LENGTH = 12, GEN_PASSWD_LENGTH = 24, MAX_PASSWD_LENGTH = 256, MAX_PATH = 259;
40 private readonly ApplicationConfig m_config = new ApplicationConfig();
41 private readonly Lazy<string> m_about = new Lazy<string>(CreateAboutText);
42 private readonly Random m_random = new Random();
43 private readonly ObservableCollection<string> m_logFile = new ObservableCollection<string>();
44 private readonly string m_defaultStatusText;
45 private readonly DispatcherTimer m_dispatcherTimer;
46 private readonly ReadOnlyObservableCollection<string> m_logFileReadOnly;
48 private volatile ModeOfOperation m_modeOfOperation = (ModeOfOperation)(-1);
49 private volatile bool m_busyFlag = false, m_checksumError = false, m_processReceived = false, m_disableAnimation = false;
50 private volatile SlunkCryptRunner m_processRunner = null;
51 private uint? m_menuId_disableAnimation = null, m_menuId_enableExpertMode = null;
53 public const string ASCII_CHARS = "!#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~";
55 // =============================================================================
57 // =============================================================================
59 public SlunkCryptGUI()
61 InitializeComponent();
62 m_defaultStatusText = Label_Status.Text;
63 m_dispatcherTimer = new DispatcherTimer(DispatcherPriority.ApplicationIdle, Dispatcher);
64 m_dispatcherTimer.Tick += DispatcherTimer_Tick;
65 m_dispatcherTimer.Interval = TimeSpan.FromMilliseconds(200);
66 m_logFileReadOnly = new ReadOnlyObservableCollection<string>(m_logFile);
67 m_disableAnimation = m_config.DisableBusyIndicator;
70 // =============================================================================
72 // =============================================================================
82 if (m_busyFlag != value)
84 m_dispatcherTimer.IsEnabled = (m_busyFlag = value) && (!m_disableAnimation);
85 NotifyPropertyChanged("IsBusy");
86 NotifyPropertyChanged("IsBusyIndicatorVisible");
91 public bool IsBusyIndicatorVisible
95 return m_busyFlag && (!m_disableAnimation);
99 public ReadOnlyObservableCollection<string> LogFile
103 return m_logFileReadOnly;
107 // =============================================================================
109 // =============================================================================
111 protected override void OnContentRendered(EventArgs e)
113 base.OnContentRendered(e);
114 TabControl.MinHeight = TabControl.MaxHeight = TabControl.ActualHeight;
115 MinWidth = MaxWidth = ActualWidth;
116 MinHeight = MaxHeight = ActualHeight;
119 private void Button_Encrypt_InputFile_Click(object sender, RoutedEventArgs e)
122 if (!string.IsNullOrEmpty(fileName = BrowseForFile(Edit_Encrypt_InputFile.Text, false)))
124 Edit_Encrypt_InputFile.Text = fileName;
125 Edit_Encrypt_OutputFile.Text = GenerateEncryptOutputFileName(fileName);
129 private void Button_Encrypt_OutputFile_Click(object sender, RoutedEventArgs e)
132 if (!string.IsNullOrEmpty(fileName = BrowseForFile(Edit_Encrypt_OutputFile.Text, true, "Encrypted file (*.enc)|*.enc")))
134 Edit_Encrypt_OutputFile.Text = fileName;
138 private void Button_Decrypt_InputFile_Click(object sender, RoutedEventArgs e)
141 if (!string.IsNullOrEmpty(fileName = BrowseForFile(Edit_Decrypt_InputFile.Text, false)))
143 Edit_Decrypt_InputFile.Text = fileName;
144 Edit_Decrypt_OutputFile.Text = GenerateDecryptOutputFileName(fileName);
148 private void Button_Decrypt_OutputFile_Click(object sender, RoutedEventArgs e)
151 if (!string.IsNullOrEmpty(fileName = BrowseForFile(Edit_Decrypt_OutputFile.Text, true, "Decrypted file (*.out)|*.out")))
153 Edit_Decrypt_OutputFile.Text = fileName;
157 private async void Button_GeneratePasswd_Click(object sender, RoutedEventArgs e)
159 using (BusyManager busy = new BusyManager(this))
161 Edit_Encrypt_Password.Password = string.Empty;
163 if (!string.IsNullOrEmpty(password = await GeneratePassword()))
165 Button_Encrypt_Toggle.IsChecked = true;
166 Edit_Encrypt_Password.Password = password;
171 private async void Button_Start_Click(object sender, RoutedEventArgs e)
175 ResetKeyboardFocus(Button_Start);
176 switch (GetModeOfOperation(TabControl.SelectedItem))
178 case ModeOfOperation.Encrypt:
179 Debug.Assert(m_modeOfOperation == ModeOfOperation.Encrypt);
180 await ValidateInputFile(Edit_Encrypt_InputFile, Edit_Encrypt_OutputFile, Edit_Encrypt_Password, Encrypt, true);
182 case ModeOfOperation.Decrypt:
183 Debug.Assert(m_modeOfOperation == ModeOfOperation.Decrypt);
184 await ValidateInputFile(Edit_Decrypt_InputFile, Edit_Decrypt_OutputFile, Edit_Decrypt_Password, Decrypt, false);
187 TabControl.SelectedIndex = GetTabIndexOf(m_modeOfOperation);
193 private void Button_About_Click(object sender, RoutedEventArgs e)
197 MessageBox.Show(this, m_about.Value, "About...", MessageBoxButton.OK, MessageBoxImage.Information);
201 private void Button_Exit_Click(object sender, RoutedEventArgs e)
205 Application.Current.Shutdown();
209 private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
211 foreach (object currrentItem in e.AddedItems)
213 ModeOfOperation? modeOfOperation = GetModeOfOperation(currrentItem);
214 if (modeOfOperation.HasValue)
216 if (m_modeOfOperation != modeOfOperation.Value)
218 SetStatus(m_defaultStatusText);
220 m_modeOfOperation = modeOfOperation.Value;
227 private void Button_AbortProcess_Click(object sender, RoutedEventArgs e)
232 private void Link_CopyToClipboard_Click(object sender, MouseButtonEventArgs e)
234 if (m_logFile.Count > 0)
236 StringBuilder builder = new StringBuilder();
237 foreach (string logItem in m_logFile)
239 builder.AppendLine(logItem);
241 Clipboard.SetText(builder.ToString());
242 SystemSounds.Beep.Play();
246 private void Link_ClearLog_Click(object sender, MouseButtonEventArgs e)
248 if (m_logFile.Count > 0)
251 SystemSounds.Beep.Play();
255 private void Process_OutputAvailable(string line, bool stderr)
258 if (line.IndexOf("Checksum mismatch detected!", StringComparison.OrdinalIgnoreCase) >= 0)
260 m_checksumError = true;
264 private void Porcess_ProgressChanged(double progress)
266 if (!m_processReceived)
268 switch (m_modeOfOperation)
270 case ModeOfOperation.Encrypt:
271 SetStatus("Encrypting file contents. Please be patient, this can take a few moments...");
273 case ModeOfOperation.Decrypt:
274 SetStatus("Decrypting file contents. Please be patient, this can take a few moments...");
277 m_processReceived = true;
281 SetProgress(progress);
284 private void Edit_FileName_KeyDown(object sender, KeyEventArgs e)
286 if (e.Key == Key.Return)
288 FrameworkElement source = sender as FrameworkElement;
289 if (!ReferenceEquals(source, null))
291 FrameworkElement target = source.Tag as FrameworkElement;
292 if (!ReferenceEquals(target, null))
294 SetFocusAndSelectAll(target);
301 private void Edit_Password_Entered(object sender, KeyEventArgs e)
305 Button_Start_Click(sender, e);
309 private void Edit_FileName_LostFocus(object sender, RoutedEventArgs e)
312 if (!ReferenceEquals(textBox = sender as TextBox, null))
314 textBox.Text = PathUtils.CleanUpFilePathString(textBox.Text);
318 private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
323 private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
325 if (e.Key == Key.Escape)
331 protected void Window_PreviewDragEnter(object sender, DragEventArgs e)
333 e.Effects = ((!IsBusy) && e.Data.GetDataPresent(DataFormats.FileDrop)) ? DragDropEffects.Copy : DragDropEffects.None;
337 private void Window_PreviewDragLeave(object sender, DragEventArgs e)
342 private void Window_PreviewDrop(object sender, DragEventArgs e)
346 string[] droppedFiles = e.Data.GetData(DataFormats.FileDrop) as string[];
347 if (!ReferenceEquals(droppedFiles, null))
349 foreach (string currentFile in droppedFiles)
351 string fullFilePath = PathUtils.CleanUpFilePathString(currentFile);
352 if ((!string.IsNullOrEmpty(fullFilePath)) && File.Exists(fullFilePath))
354 TabControl.SelectedIndex = GetTabIndexOf(m_modeOfOperation);
355 switch (m_modeOfOperation)
357 case ModeOfOperation.Encrypt:
358 Edit_Encrypt_InputFile .Text = fullFilePath;
359 Edit_Encrypt_OutputFile.Text = GenerateEncryptOutputFileName(fullFilePath);
361 case ModeOfOperation.Decrypt:
362 Edit_Decrypt_InputFile .Text = fullFilePath;
363 Edit_Decrypt_OutputFile.Text = GenerateDecryptOutputFileName(fullFilePath);
374 private async void Window_Loaded(object sender, RoutedEventArgs e)
377 SystemMenu systemMenu = new SystemMenu(this, SystemMenu_Activated);
378 m_menuId_disableAnimation = systemMenu.AppendMenu("Disable Busy Indicator");
379 m_menuId_enableExpertMode = systemMenu.AppendMenu("Expert Settings");
380 if (m_disableAnimation && m_menuId_disableAnimation.HasValue)
382 systemMenu.ModifyMenu(m_menuId_disableAnimation.Value, m_disableAnimation);
384 CreateIndicatorElements();
387 private void Window_Closing(object sender, CancelEventArgs e)
391 SystemSounds.Hand.Play();
396 private void DispatcherTimer_Tick(object sender, EventArgs e)
398 ShuffleIndicatorElements();
401 private void SystemMenu_Activated(SystemMenu sender, uint menuId)
403 if (m_menuId_disableAnimation.HasValue && (menuId == m_menuId_disableAnimation.Value))
405 sender.ModifyMenu(menuId, m_disableAnimation = !m_disableAnimation);
408 m_dispatcherTimer.IsEnabled = !m_disableAnimation;
409 NotifyPropertyChanged("IsBusyIndicatorVisible");
412 else if (m_menuId_enableExpertMode.HasValue && (menuId == m_menuId_enableExpertMode.Value))
416 Process.Start("https://youtu.be/Is_8bjYVmnA").Dispose();
422 // =============================================================================
424 // =============================================================================
426 private async Task ValidateInputFile(TextBox inputFileEdit, TextBox outputFileEdit, PasswordToggleBox passwordEdit, SlunkProcessor processor, bool checkStrongPasswd)
428 string inputFilePath;
429 if (string.IsNullOrEmpty(inputFileEdit.Text = inputFilePath = PathUtils.CleanUpFilePathString(inputFileEdit.Text)))
431 MessageBox.Show(this, "Input file must be selected first!", "Input File Missing", MessageBoxButton.OK, MessageBoxImage.Warning);
432 SetFocusAndSelectAll(inputFileEdit);
435 if (PathUtils.IsInvalidPath(inputFilePath))
437 MessageBox.Show(this, "The specified input file path is invalid!", "Input File Invalid", MessageBoxButton.OK, MessageBoxImage.Warning);
438 SetFocusAndSelectAll(inputFileEdit);
441 if (Directory.Exists(inputFilePath))
443 MessageBox.Show(this, "Specified input file appears to be a directory!", "Input File Invalid", MessageBoxButton.OK, MessageBoxImage.Warning);
444 SetFocusAndSelectAll(inputFileEdit);
447 if (!File.Exists(inputFilePath))
449 MessageBox.Show(this, "Specified input file could not be found!", "Input Not Found", MessageBoxButton.OK, MessageBoxImage.Warning);
450 SetFocusAndSelectAll(inputFileEdit);
453 await ValidateOutputFile(inputFilePath, outputFileEdit, passwordEdit, processor, checkStrongPasswd);
456 private async Task ValidateOutputFile(string inputFilePath, TextBox outputFileEdit, PasswordToggleBox passwordEdit, SlunkProcessor processor, bool checkStrongPasswd)
458 string outputFilePath;
459 if (string.IsNullOrEmpty(outputFileEdit.Text = outputFilePath = PathUtils.CleanUpFilePathString(outputFileEdit.Text)))
461 MessageBox.Show(this, "Output file must be selected first!", "Output File Missing", MessageBoxButton.OK, MessageBoxImage.Warning);
462 SetFocusAndSelectAll(outputFileEdit);
465 if (PathUtils.IsInvalidPath(outputFilePath))
467 MessageBox.Show(this, "The specified output file path is invalid!", "Output File Invalid", MessageBoxButton.OK, MessageBoxImage.Warning);
468 SetFocusAndSelectAll(outputFileEdit);
471 if (Directory.Exists(outputFilePath))
473 MessageBox.Show(this, "Specified output file appears to be a directory!", "Output File Invalid", MessageBoxButton.OK, MessageBoxImage.Warning);
474 SetFocusAndSelectAll(outputFileEdit);
477 if (string.Equals(inputFilePath, outputFilePath, StringComparison.OrdinalIgnoreCase))
479 MessageBox.Show(this, "Input and output file can not be the same!", "File Name Conflict", MessageBoxButton.OK, MessageBoxImage.Warning);
480 SetFocusAndSelectAll(outputFileEdit);
483 if (File.Exists(outputFilePath))
485 if (MessageBox.Show(this, "Specified output file already existst! Overwrite?", "Output File Exists", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) != MessageBoxResult.Yes)
487 SetFocusAndSelectAll(outputFileEdit);
491 await ValidateOutputDirectory(inputFilePath, outputFilePath, passwordEdit, processor, checkStrongPasswd);
495 private async Task ValidateOutputDirectory(string inputFilePath, string outputFilePath, PasswordToggleBox passwordEdit, SlunkProcessor processor, bool checkStrongPasswd)
497 string outputDirectory;
498 if (string.IsNullOrEmpty(outputDirectory = PathUtils.TryGetDirectoryName(outputFilePath)))
500 MessageBox.Show(this, "The output directory could not be determined!", "Output Directory Invalid", MessageBoxButton.OK, MessageBoxImage.Warning);
503 while (!Directory.Exists(outputDirectory))
505 if (MessageBox.Show(this, "Output directory does not exist yet! Create it now?", "Output Directory Nonexistent", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes) != MessageBoxResult.Yes)
509 if (!PathUtils.TryCreateDirectory(outputDirectory))
511 MessageBox.Show(this, "The output directory could not be created!", "Directory Creation Failed", MessageBoxButton.OK, MessageBoxImage.Warning);
515 await ValidatePassword(inputFilePath, outputFilePath, passwordEdit, processor, checkStrongPasswd);
518 private async Task ValidatePassword(string inputFilePath, string outputFilePath, PasswordToggleBox passwordEdit, SlunkProcessor processor, bool checkStrongPasswd)
521 if (string.IsNullOrEmpty(passwordStr = passwordEdit.Password) || (passwordStr.Length < MIN_PASSWD_LENGTH))
523 MessageBox.Show(this, String.Format("Passphrase must be at least {0:D} characters in length!", MIN_PASSWD_LENGTH), "Passphrase Missing", MessageBoxButton.OK, MessageBoxImage.Warning);
524 SetFocusAndSelectAll(passwordEdit);
527 if (checkStrongPasswd)
529 if (passwordStr.Length < REC_PASSWD_LENGTH)
531 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)
533 SetFocusAndSelectAll(passwordEdit);
537 else if (PasswordGen.IsWeakPassword(passwordStr))
539 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)
541 SetFocusAndSelectAll(passwordEdit);
546 await InvokeProcessor(inputFilePath, outputFilePath, passwordStr, processor);
549 private async Task InvokeProcessor(string inputFile, string outputFile, string password, SlunkProcessor processor)
551 using (BusyManager busyManager = new BusyManager(this))
553 ResetKeyboardFocus(this);
554 SetProgress(double.PositiveInfinity);
556 Button_Decrypt_Toggle.IsChecked = Button_Encrypt_Toggle.IsChecked = m_checksumError = m_processReceived = false;
557 if (!await processor(inputFile, outputFile, password))
559 SetProgress(double.NaN, true);
560 PathUtils.TryRemoveFile(outputFile);
566 private async Task<bool> Encrypt(string inputFile, string outputFile, string password)
568 SetStatus("Please wait while the encryption process is initializing...");
569 int? exitCode = await RunProcess(SlunkCryptRunner.Mode.Encrypt, inputFile, outputFile, password);
570 if (exitCode.HasValue)
572 if (exitCode.Value == 0)
575 SetStatus("Completed: The file has been encrypted successfully.", Status.Success);
576 SystemSounds.Asterisk.Play();
580 SetProgress(1, true);
581 SetStatus("Error: Failed to enecrypt the file. Please see the log file for details!", Status.Failure);
582 SystemSounds.Hand.Play();
589 private async Task<bool> Decrypt(string inputFile, string outputFile, string password)
591 SetStatus("Please wait while the decryption process is initializing...");
592 int? exitCode = await RunProcess(SlunkCryptRunner.Mode.Decrypt, inputFile, outputFile, password);
593 if (exitCode.HasValue)
595 if (exitCode.Value == 0)
597 SetStatus("Completed: The file has been decrypted successfully (checksum is correct).", Status.Success);
599 SystemSounds.Asterisk.Play();
605 SetStatus("Error: Checksum mismatch detected! Wrong passphrase or corrupted file?", Status.Failure);
609 SetStatus("Error: Failed to decrypt the file. Please see the log file for details!", Status.Failure);
611 SetProgress(1, true);
612 SystemSounds.Hand.Play();
619 private async Task<int?> RunProcess(SlunkCryptRunner.Mode mode, string inputFile, string outputFile, string password)
621 if (!ReferenceEquals(m_processRunner, null))
623 throw new InvalidOperationException("Process has already been started!");
627 using (m_processRunner = new SlunkCryptRunner(Dispatcher))
629 m_processRunner.OutputAvailable += Process_OutputAvailable;
630 m_processRunner.ProgressChanged += Porcess_ProgressChanged;
631 SetProcessPriority(ProcessPriorityClass.AboveNormal);
632 return await m_processRunner.ExecuteAsync(mode, inputFile, outputFile, password);
635 catch (ProcessRunner.ProcessStartException err)
637 SetStatus(string.Format("Error: The {0} process could not be created! (Error code: {1:D})", GetModeString(m_modeOfOperation), GetWin32ErrorCode(err)), Status.Failure);
638 MessageBox.Show(this, "Failed to create SlunkCrypt process:\n\n" + err.InnerException?.Message ?? err.Message, "Process Creation Error", MessageBoxButton.OK, MessageBoxImage.Error);
640 catch (ExecutableHelper.ExecutableNotFoundException)
642 SetStatus("Error: The required SlunkCrypt executable file could not be found!", Status.Failure);
643 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);
645 catch (ProcessRunner.ProcessInterruptedException)
647 SetStatus(string.Format("Aborted: The {0} process was aborted by the user!", GetModeString(m_modeOfOperation)), Status.Failure);
648 SystemSounds.Hand.Play();
652 m_processRunner = null; /*final clean-up*/
657 private async Task<string> GeneratePassword()
659 string password = string.Empty;
662 Task<string> passwordTask = Task.Run(() => PasswordGen.GeneratePassword(GEN_PASSWD_LENGTH));
663 await Task.WhenAll(passwordTask, Task.Delay(333));
664 password = passwordTask.Result;
666 catch (ProcessRunner.ProcessStartException err)
668 MessageBox.Show(this, "Failed to create SlunkCrypt process:\n\n" + err.InnerException?.Message ?? err.Message, "Process Creation Error", MessageBoxButton.OK, MessageBoxImage.Error);
670 catch (ExecutableHelper.ExecutableNotFoundException)
672 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);
674 catch (PasswordGen.GenerationFailedException)
676 MessageBox.Show(this, "Error: The password could not be generated!", "Generation Failed", MessageBoxButton.OK, MessageBoxImage.Error);
681 private void SetStatus(string text, Status status = Status.Default)
686 Label_Status.Foreground = Brushes.DarkGreen;
689 Label_Status.Foreground = Brushes.DarkRed;
692 Label_Status.Foreground = SystemColors.WindowTextBrush;
695 Label_Status.Text = text;
698 private void SetProgress(double progress, bool failed = false)
700 if (!(double.IsNaN(progress) || double.IsInfinity(progress)))
702 ProgressBar.IsIndeterminate = false;
703 ProgressBar.Value = progress;
704 TaskbarItemInfo.ProgressState = failed ? TaskbarItemProgressState.Error : TaskbarItemProgressState.Normal;
705 TaskbarItemInfo.ProgressValue = progress;
706 Label_Progress.Text = string.Format(CultureInfo.InvariantCulture, "{0:0.0}%", progress * 100.0);
710 if (double.IsInfinity(progress))
712 ProgressBar.IsIndeterminate = true;
713 ProgressBar.Value = 0;
714 TaskbarItemInfo.ProgressState = TaskbarItemProgressState.Indeterminate;
715 Label_Progress.Text = string.Empty;
719 ProgressBar.IsIndeterminate = false;
720 TaskbarItemInfo.ProgressState = failed ? TaskbarItemProgressState.Error : TaskbarItemProgressState.None;
725 private void ClearProgress()
727 ProgressBar.IsIndeterminate = false;
728 ProgressBar.Value = 0;
729 TaskbarItemInfo.ProgressState = TaskbarItemProgressState.None;
730 Label_Progress.Text = string.Empty;
733 private void AbortProcess()
735 ProcessRunner processRunner;
736 if (!ReferenceEquals(processRunner = m_processRunner, null))
740 processRunner.AbortProcess();
746 private string BrowseForFile(string fileName, bool saveDialog, string filterString = null)
748 FileDialog openFileDialog = saveDialog ? new SaveFileDialog() { OverwritePrompt = false } : (FileDialog) new OpenFileDialog();
749 openFileDialog.Filter = string.IsNullOrEmpty(filterString) ? "All files (*.*)|*.*" : filterString;
750 if (!string.IsNullOrEmpty(fileName))
752 openFileDialog.FileName = fileName;
754 if (openFileDialog.ShowDialog().GetValueOrDefault(false))
756 return openFileDialog.FileName;
761 private void CreateIndicatorElements()
763 FontFamily hackFont = new FontFamily(new Uri("pack://application:,,,/"), "./Resources/Fonts/#Hack");
764 DropShadowEffect dropShadowEffect = CreateShadowEffect(Colors.Black, 3.0);
765 TextBlock reference = CreateTextBlock('0', Brushes.Gold, hackFont, dropShadowEffect);
766 reference.Measure(new Size(double.MaxValue, double.MaxValue));
767 Size desiredSize = reference.DesiredSize;
768 double actualWidth = Canvas.ActualWidth, actualHeight = Canvas.ActualHeight;
769 int lenX = (int)Math.Ceiling(desiredSize.Width * 1.25);
770 int lenY = (int)Math.Ceiling(desiredSize.Height * 1.25);
771 int numX = (int)Math.Floor(actualWidth / lenX);
772 int numY = (int)Math.Floor(actualHeight / lenY);
773 int offX = (int)Math.Round((actualWidth - (numX * lenX)) / 2.0);
774 int offY = (int)Math.Round((actualHeight - (numY * lenY)) / 2.0);
775 for (int i = 0; i < numX; ++i)
777 for (int j = 0; j < numY; ++j)
779 TextBlock element = CreateTextBlock('0', Brushes.Gold, hackFont, dropShadowEffect);
780 Canvas.Children.Add(element);
781 Canvas.SetLeft(element, offX + (i * lenX));
782 Canvas.SetTop (element, offY + (j * lenY));
785 ShuffleIndicatorElements();
788 private void ShuffleIndicatorElements()
790 char[] chars = ASCII_CHARS.ToCharArray();
791 UIElementCollection children = Canvas.Children;
792 for (int i = 0; i < children.Count; ++i)
795 if (!ReferenceEquals(element = children[i] as TextBlock, null))
797 if (m_random.Next(7) == 0)
799 element.Visibility = Visibility.Visible;
800 element.Text = char.ToString(chars[m_random.Next(chars.Length)]);
804 element.Visibility = Visibility.Hidden;
810 private void AppendLogFile(string line)
812 if (!string.IsNullOrEmpty(line))
818 private int GetTabIndexOf(ModeOfOperation modeOfOperation)
820 ItemCollection collection = TabControl.Items;
821 for (int index = 0; index < collection.Count; ++index)
823 ModeOfOperation? current = GetModeOfOperation(collection[index]);
824 if (current.HasValue && (current.Value == modeOfOperation))
832 private void ClearLogFile()
837 private void NotifyPropertyChanged(string name)
839 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
842 // -----------------------------------------------------------------------------
844 // -----------------------------------------------------------------------------
846 private static string CreateAboutText()
848 CPUFeatures cpuFeatures = CPUFeatures.Features;
849 return new StringBuilder()
850 .AppendLine("SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de>")
851 .AppendLine(VersionInfo.VersionStr)
852 .AppendLine("This work has been released under the \u201CCC0 1.0\u201D license!")
854 .AppendLine(Environment.OSVersion.VersionString)
855 .AppendLine(string.Format("Operating System Bitness: {0:D}, Process Bitness: {1:D}", Environment.Is64BitOperatingSystem ? 64 : 32, Environment.Is64BitProcess ? 64 : 32))
856 .AppendLine(".NET Runtime Version: " + Environment.Version)
857 .AppendLine(string.Format("CPU Count: {0:D}, Architecture: {1}, SSE2 Support: {2}", Environment.ProcessorCount, cpuFeatures.x64 ? "x64" : "x86", cpuFeatures.sse2 ? "Yes" : "No"))
859 .AppendLine("Using “Silk” icons, by Mark James")
863 private static string GenerateEncryptOutputFileName(string inputFilePath)
865 string directoryPath = Path.GetDirectoryName(inputFilePath), fileName = Path.GetFileNameWithoutExtension(inputFilePath), extension = Path.GetExtension(inputFilePath);
866 string outputFile = Path.Combine(directoryPath, string.Format("{0}{1}.enc", fileName, extension));
867 for (int count = 2; File.Exists(outputFile); ++count)
869 outputFile = Path.Combine(directoryPath, string.Format("{0} ({1:D}){2}.enc", fileName, count, extension));
874 private static string GenerateDecryptOutputFileName(string inputFilePath)
876 string directoryPath = Path.GetDirectoryName(inputFilePath), fileName = Path.GetFileNameWithoutExtension(inputFilePath), extension = Path.GetExtension(inputFilePath);
877 while (extension.Equals(".enc", StringComparison.OrdinalIgnoreCase))
879 extension = Path.GetExtension(fileName);
880 fileName = Path.GetFileNameWithoutExtension(fileName);
882 if (string.IsNullOrEmpty(extension))
886 string outputFile = Path.Combine(directoryPath, string.Concat(fileName, extension));
887 for (int count = 2; File.Exists(outputFile); ++count)
889 outputFile = Path.Combine(directoryPath, String.Format("{0} ({1:D}){2}", fileName, count, extension));
894 private static ModeOfOperation? GetModeOfOperation(object selectedItem)
896 TabItem selectedTabItem = selectedItem as TabItem;
897 if (!ReferenceEquals(selectedTabItem, null))
899 return selectedTabItem.Tag as ModeOfOperation?;
904 private static string GetModeString(ModeOfOperation modeOfOperation)
906 switch(modeOfOperation)
908 case ModeOfOperation.Encrypt:
910 case ModeOfOperation.Decrypt:
913 throw new ArgumentException("modeOfOperation");
917 private static void SetFocusAndSelectAll(FrameworkElement element)
920 if (!ReferenceEquals(textBox = element as TextBox, null))
927 PasswordToggleBox passwordToggleBox;
928 if (!ReferenceEquals(passwordToggleBox = element as PasswordToggleBox, null))
930 passwordToggleBox.Focus();
931 passwordToggleBox.SelectAll();
936 private static void SetProcessPriority(ProcessPriorityClass priorityClass)
940 using (Process currentProcess = Process.GetCurrentProcess())
942 currentProcess.PriorityClass = priorityClass;
948 private static int GetWin32ErrorCode(Exception err)
950 while (!ReferenceEquals(err, null))
952 if (err is Win32Exception)
954 return ((Win32Exception)err).NativeErrorCode;
956 err = err.InnerException;
961 private static TextBlock CreateTextBlock(char c, Brush foreground, FontFamily fontFamily, Effect effect)
963 return new TextBlock()
965 Text = char.ToString(c),
966 Foreground = foreground,
967 FontFamily = fontFamily,
972 private static DropShadowEffect CreateShadowEffect(Color color, double blurRadius)
974 return new DropShadowEffect()
977 BlurRadius = blurRadius,
983 private static void ResetKeyboardFocus(UIElement element)
985 Keyboard.ClearFocus();