diff --git a/mRemoteNG/Config/Settings/Registry/CommonRegistrySettings.cs b/mRemoteNG/Config/Settings/Registry/CommonRegistrySettings.cs index 7174d9aa..bdc74eb2 100644 --- a/mRemoteNG/Config/Settings/Registry/CommonRegistrySettings.cs +++ b/mRemoteNG/Config/Settings/Registry/CommonRegistrySettings.cs @@ -40,22 +40,22 @@ namespace mRemoteNG.Config.Settings.Registry #region general credential registry settings /// - /// Setting that indicates whether exporting passwords is allowed. + /// Specifies whether the export of passwords for saved connections is allowed. /// public static bool AllowExportPasswords { get; } /// - /// Setting that indicates whether exporting usernames is allowed. + /// Specifies whether the export of usernames for saved connections is allowed. /// public static bool AllowExportUsernames { get; } /// - /// Setting that indicates whether saving passwords in connections is allowed. + /// Specifies whether the saving of usernames for saved connections is allowed. /// public static bool AllowSavePasswords { get; } /// - /// Setting that indicates whether saving in connections usernames is allowed. + /// Specifies whether the saving of passwords for saved connections is allowed. /// public static bool AllowSaveUsernames { get; } diff --git a/mRemoteNG/Config/Settings/Registry/OptRegistrySecurityPage.cs b/mRemoteNG/Config/Settings/Registry/OptRegistrySecurityPage.cs new file mode 100644 index 00000000..d0b64289 --- /dev/null +++ b/mRemoteNG/Config/Settings/Registry/OptRegistrySecurityPage.cs @@ -0,0 +1,103 @@ +using System.Runtime.Versioning; +using Microsoft.Win32; +using mRemoteNG.App.Info; +using mRemoteNG.Security; +using mRemoteNG.Tools.WindowsRegistry; + +namespace mRemoteNG.Config.Settings.Registry +{ + [SupportedOSPlatform("windows")] + public sealed partial class OptRegistrySecurityPage + { + /// + /// Specifies whether the complete connections file is encrypted. + /// + public WinRegistryEntry EncryptCompleteConnectionsFile { get; private set; } + + /// + /// Specifies the encryption engine used for encryption. + /// + public WinRegistryEntry EncryptionEngine { get; private set; } + + /// + /// Specifies the block cipher mode used for encryption. + /// + public WinRegistryEntry EncryptionBlockCipherMode { get; private set; } + + /// + /// Specifies the number of iterations used in the encryption key derivation process. + /// + public WinRegistryEntry EncryptionKeyDerivationIterations { get; private set; } + + public OptRegistrySecurityPage() + { + + RegistryHive hive = WindowsRegistryInfo.Hive; + string subKey = WindowsRegistryInfo.SecurityOptions; + + EncryptCompleteConnectionsFile = new WinRegistryEntry(hive, subKey, nameof(EncryptCompleteConnectionsFile)).Read(); + EncryptionEngine = new WinRegistryEntry(hive, subKey, nameof(EncryptionEngine)).Read(); + EncryptionBlockCipherMode = new WinRegistryEntry(hive, subKey, nameof(EncryptionBlockCipherMode)).Read(); + EncryptionKeyDerivationIterations = new WinRegistryEntry(hive, subKey, nameof(EncryptionKeyDerivationIterations)).Read(); + + SetupValidation(); + Apply(); + } + + /// + /// Configures validation settings for various parameters + /// + private void SetupValidation() + { + var SecurityPage = new UI.Forms.OptionsPages.SecurityPage(); + + EncryptionEngine.SetValidation(); + EncryptionBlockCipherMode.SetValidation(); + + int EncryptionKeyDerivIteraMin = (int)SecurityPage.numberBoxKdfIterations.Minimum; + int EncryptionKeyDerivIteraMax = (int)SecurityPage.numberBoxKdfIterations.Maximum; + EncryptionKeyDerivationIterations.SetValidation(EncryptionKeyDerivIteraMin, EncryptionKeyDerivIteraMax); + } + + /// + /// Applies registry settings and overrides various properties. + /// + private void Apply() + { + ApplyEncryptCompleteConnectionsFile(); + ApplyEncryptionEngine(); + ApplyEncryptionBlockCipherMode(); + ApplyEncryptionKeyDerivationIterations(); + } + + private void ApplyEncryptCompleteConnectionsFile() + { + if (EncryptCompleteConnectionsFile.IsSet) + Properties.OptionsSecurityPage.Default.EncryptCompleteConnectionsFile = EncryptCompleteConnectionsFile.Value; + } + + private void ApplyEncryptionEngine() + { + if (EncryptionEngine.IsValid) + { + BlockCipherEngines blockCipherEngines = (BlockCipherEngines)System.Enum.Parse(typeof(BlockCipherEngines), EncryptionEngine.Value); + Properties.OptionsSecurityPage.Default.EncryptionEngine = blockCipherEngines; + } + } + + private void ApplyEncryptionBlockCipherMode() + { + if (EncryptionBlockCipherMode.IsValid) + { + BlockCipherModes blockCipherModes = (BlockCipherModes)System.Enum.Parse(typeof(BlockCipherModes), EncryptionBlockCipherMode.Value); + Properties.OptionsSecurityPage.Default.EncryptionBlockCipherMode = blockCipherModes; + } + } + + private void ApplyEncryptionKeyDerivationIterations() + { + if (EncryptionKeyDerivationIterations.IsValid) + Properties.OptionsSecurityPage.Default.EncryptionKeyDerivationIterations = EncryptionKeyDerivationIterations.Value; + } + } +} \ No newline at end of file diff --git a/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.Designer.cs b/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.Designer.cs index 87765b46..5280b1db 100644 --- a/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.Designer.cs +++ b/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.Designer.cs @@ -40,20 +40,32 @@ namespace mRemoteNG.UI.Forms.OptionsPages labelKdfIterations = new MrngLabel(); numberBoxKdfIterations = new MrngNumericUpDown(); btnTestSettings = new MrngButton(); + lblRegistrySettingsUsedInfo = new System.Windows.Forms.Label(); + pnlOptions = new System.Windows.Forms.Panel(); + groupPasswordGenerator = new System.Windows.Forms.GroupBox(); + pnlPasswordTxtAndBtn = new System.Windows.Forms.TableLayoutPanel(); + txtPasswdGenerator = new System.Windows.Forms.TextBox(); + btnPasswdGenerator = new System.Windows.Forms.Button(); + lblPasswdGenDescription = new System.Windows.Forms.Label(); groupAdvancedSecurityOptions.SuspendLayout(); tableLayoutPanel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)numberBoxKdfIterations).BeginInit(); + pnlOptions.SuspendLayout(); + groupPasswordGenerator.SuspendLayout(); + pnlPasswordTxtAndBtn.SuspendLayout(); SuspendLayout(); // // chkEncryptCompleteFile // chkEncryptCompleteFile._mice = MrngCheckBox.MouseState.OUT; chkEncryptCompleteFile.AutoSize = true; + chkEncryptCompleteFile.Dock = System.Windows.Forms.DockStyle.Top; chkEncryptCompleteFile.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); - chkEncryptCompleteFile.Location = new System.Drawing.Point(12, 10); + chkEncryptCompleteFile.Location = new System.Drawing.Point(0, 0); chkEncryptCompleteFile.Margin = new System.Windows.Forms.Padding(6); chkEncryptCompleteFile.Name = "chkEncryptCompleteFile"; - chkEncryptCompleteFile.Size = new System.Drawing.Size(286, 27); + chkEncryptCompleteFile.Padding = new System.Windows.Forms.Padding(4); + chkEncryptCompleteFile.Size = new System.Drawing.Size(610, 25); chkEncryptCompleteFile.TabIndex = 0; chkEncryptCompleteFile.Text = "Encrypt complete connection file"; chkEncryptCompleteFile.UseVisualStyleBackColor = true; @@ -64,10 +76,10 @@ namespace mRemoteNG.UI.Forms.OptionsPages comboBoxEncryptionEngine.Dock = System.Windows.Forms.DockStyle.Fill; comboBoxEncryptionEngine.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; comboBoxEncryptionEngine.FormattingEnabled = true; - comboBoxEncryptionEngine.Location = new System.Drawing.Point(280, 4); - comboBoxEncryptionEngine.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + comboBoxEncryptionEngine.Location = new System.Drawing.Point(197, 8); + comboBoxEncryptionEngine.Margin = new System.Windows.Forms.Padding(4); comboBoxEncryptionEngine.Name = "comboBoxEncryptionEngine"; - comboBoxEncryptionEngine.Size = new System.Drawing.Size(196, 31); + comboBoxEncryptionEngine.Size = new System.Drawing.Size(196, 21); comboBoxEncryptionEngine.Sorted = true; comboBoxEncryptionEngine.TabIndex = 1; // @@ -75,10 +87,10 @@ namespace mRemoteNG.UI.Forms.OptionsPages // labelEncryptionEngine.AutoSize = true; labelEncryptionEngine.Dock = System.Windows.Forms.DockStyle.Fill; - labelEncryptionEngine.Location = new System.Drawing.Point(4, 0); + labelEncryptionEngine.Location = new System.Drawing.Point(8, 4); labelEncryptionEngine.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); labelEncryptionEngine.Name = "labelEncryptionEngine"; - labelEncryptionEngine.Size = new System.Drawing.Size(268, 39); + labelEncryptionEngine.Size = new System.Drawing.Size(181, 29); labelEncryptionEngine.TabIndex = 0; labelEncryptionEngine.Text = "Encryption Engine"; labelEncryptionEngine.TextAlign = System.Drawing.ContentAlignment.MiddleRight; @@ -87,10 +99,10 @@ namespace mRemoteNG.UI.Forms.OptionsPages // labelBlockCipher.AutoSize = true; labelBlockCipher.Dock = System.Windows.Forms.DockStyle.Fill; - labelBlockCipher.Location = new System.Drawing.Point(4, 39); + labelBlockCipher.Location = new System.Drawing.Point(8, 33); labelBlockCipher.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); labelBlockCipher.Name = "labelBlockCipher"; - labelBlockCipher.Size = new System.Drawing.Size(268, 39); + labelBlockCipher.Size = new System.Drawing.Size(181, 29); labelBlockCipher.TabIndex = 2; labelBlockCipher.Text = "Block Cipher Mode"; labelBlockCipher.TextAlign = System.Drawing.ContentAlignment.MiddleRight; @@ -101,20 +113,22 @@ namespace mRemoteNG.UI.Forms.OptionsPages comboBoxBlockCipher.Dock = System.Windows.Forms.DockStyle.Fill; comboBoxBlockCipher.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; comboBoxBlockCipher.FormattingEnabled = true; - comboBoxBlockCipher.Location = new System.Drawing.Point(280, 43); - comboBoxBlockCipher.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + comboBoxBlockCipher.Location = new System.Drawing.Point(197, 37); + comboBoxBlockCipher.Margin = new System.Windows.Forms.Padding(4); comboBoxBlockCipher.Name = "comboBoxBlockCipher"; - comboBoxBlockCipher.Size = new System.Drawing.Size(196, 31); + comboBoxBlockCipher.Size = new System.Drawing.Size(196, 21); comboBoxBlockCipher.TabIndex = 2; // // groupAdvancedSecurityOptions // + groupAdvancedSecurityOptions.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; groupAdvancedSecurityOptions.Controls.Add(tableLayoutPanel1); - groupAdvancedSecurityOptions.Location = new System.Drawing.Point(12, 51); + groupAdvancedSecurityOptions.Dock = System.Windows.Forms.DockStyle.Top; + groupAdvancedSecurityOptions.Location = new System.Drawing.Point(0, 25); groupAdvancedSecurityOptions.Margin = new System.Windows.Forms.Padding(6); groupAdvancedSecurityOptions.Name = "groupAdvancedSecurityOptions"; - groupAdvancedSecurityOptions.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4); - groupAdvancedSecurityOptions.Size = new System.Drawing.Size(906, 201); + groupAdvancedSecurityOptions.Padding = new System.Windows.Forms.Padding(4); + groupAdvancedSecurityOptions.Size = new System.Drawing.Size(610, 159); groupAdvancedSecurityOptions.TabIndex = 1; groupAdvancedSecurityOptions.TabStop = false; groupAdvancedSecurityOptions.Text = "Advanced Security Options"; @@ -133,25 +147,26 @@ namespace mRemoteNG.UI.Forms.OptionsPages tableLayoutPanel1.Controls.Add(comboBoxBlockCipher, 1, 1); tableLayoutPanel1.Controls.Add(btnTestSettings, 1, 3); tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Left; - tableLayoutPanel1.Location = new System.Drawing.Point(4, 26); - tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + tableLayoutPanel1.Location = new System.Drawing.Point(4, 19); + tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(4); tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(4); tableLayoutPanel1.RowCount = 4; tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - tableLayoutPanel1.Size = new System.Drawing.Size(480, 171); + tableLayoutPanel1.Size = new System.Drawing.Size(401, 136); tableLayoutPanel1.TabIndex = 2; // // labelKdfIterations // labelKdfIterations.AutoSize = true; labelKdfIterations.Dock = System.Windows.Forms.DockStyle.Fill; - labelKdfIterations.Location = new System.Drawing.Point(4, 78); + labelKdfIterations.Location = new System.Drawing.Point(8, 62); labelKdfIterations.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); labelKdfIterations.Name = "labelKdfIterations"; - labelKdfIterations.Size = new System.Drawing.Size(268, 37); + labelKdfIterations.Size = new System.Drawing.Size(181, 30); labelKdfIterations.TabIndex = 4; labelKdfIterations.Text = "Key Derivation Function Iterations"; labelKdfIterations.TextAlign = System.Drawing.ContentAlignment.MiddleRight; @@ -160,12 +175,12 @@ namespace mRemoteNG.UI.Forms.OptionsPages // numberBoxKdfIterations.Dock = System.Windows.Forms.DockStyle.Fill; numberBoxKdfIterations.Increment = new decimal(new int[] { 1000, 0, 0, 0 }); - numberBoxKdfIterations.Location = new System.Drawing.Point(280, 82); - numberBoxKdfIterations.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + numberBoxKdfIterations.Location = new System.Drawing.Point(197, 66); + numberBoxKdfIterations.Margin = new System.Windows.Forms.Padding(4); numberBoxKdfIterations.Maximum = new decimal(new int[] { 50000, 0, 0, 0 }); numberBoxKdfIterations.Minimum = new decimal(new int[] { 1000, 0, 0, 0 }); numberBoxKdfIterations.Name = "numberBoxKdfIterations"; - numberBoxKdfIterations.Size = new System.Drawing.Size(196, 29); + numberBoxKdfIterations.Size = new System.Drawing.Size(196, 22); numberBoxKdfIterations.TabIndex = 3; numberBoxKdfIterations.ThousandsSeparator = true; numberBoxKdfIterations.Value = new decimal(new int[] { 1000, 0, 0, 0 }); @@ -174,32 +189,121 @@ namespace mRemoteNG.UI.Forms.OptionsPages // btnTestSettings._mice = MrngButton.MouseState.OUT; btnTestSettings.AutoSize = true; - btnTestSettings.Dock = System.Windows.Forms.DockStyle.Right; - btnTestSettings.Location = new System.Drawing.Point(294, 119); - btnTestSettings.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + btnTestSettings.Location = new System.Drawing.Point(197, 96); + btnTestSettings.Margin = new System.Windows.Forms.Padding(4); btnTestSettings.Name = "btnTestSettings"; - btnTestSettings.Size = new System.Drawing.Size(182, 52); + btnTestSettings.Padding = new System.Windows.Forms.Padding(4); + btnTestSettings.Size = new System.Drawing.Size(196, 33); btnTestSettings.TabIndex = 4; btnTestSettings.Text = "Test Settings"; btnTestSettings.UseVisualStyleBackColor = true; btnTestSettings.Click += BtnTestSettings_Click; // + // lblRegistrySettingsUsedInfo + // + lblRegistrySettingsUsedInfo.BackColor = System.Drawing.SystemColors.ControlLight; + lblRegistrySettingsUsedInfo.Dock = System.Windows.Forms.DockStyle.Top; + lblRegistrySettingsUsedInfo.ForeColor = System.Drawing.SystemColors.ControlText; + lblRegistrySettingsUsedInfo.Location = new System.Drawing.Point(0, 0); + lblRegistrySettingsUsedInfo.Name = "lblRegistrySettingsUsedInfo"; + lblRegistrySettingsUsedInfo.Padding = new System.Windows.Forms.Padding(0, 2, 0, 0); + lblRegistrySettingsUsedInfo.Size = new System.Drawing.Size(610, 30); + lblRegistrySettingsUsedInfo.TabIndex = 3; + lblRegistrySettingsUsedInfo.Text = "Some settings are configured by your Administrator. Please contact your administrator for more information."; + lblRegistrySettingsUsedInfo.Visible = false; + // + // pnlOptions + // + pnlOptions.Controls.Add(groupAdvancedSecurityOptions); + pnlOptions.Controls.Add(chkEncryptCompleteFile); + pnlOptions.Dock = System.Windows.Forms.DockStyle.Top; + pnlOptions.Location = new System.Drawing.Point(0, 30); + pnlOptions.Name = "pnlOptions"; + pnlOptions.Size = new System.Drawing.Size(610, 201); + pnlOptions.TabIndex = 2; + // + // groupPasswordGenerator + // + groupPasswordGenerator.Controls.Add(pnlPasswordTxtAndBtn); + groupPasswordGenerator.Controls.Add(lblPasswdGenDescription); + groupPasswordGenerator.Dock = System.Windows.Forms.DockStyle.Top; + groupPasswordGenerator.Location = new System.Drawing.Point(0, 231); + groupPasswordGenerator.Name = "groupPasswordGenerator"; + groupPasswordGenerator.Size = new System.Drawing.Size(610, 116); + groupPasswordGenerator.TabIndex = 4; + groupPasswordGenerator.TabStop = false; + groupPasswordGenerator.Text = "Secure Key Generator"; + // + // pnlPasswordTxtAndBtn + // + pnlPasswordTxtAndBtn.ColumnCount = 2; + pnlPasswordTxtAndBtn.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 63.91437F)); + pnlPasswordTxtAndBtn.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 36.08563F)); + pnlPasswordTxtAndBtn.Controls.Add(txtPasswdGenerator, 0, 0); + pnlPasswordTxtAndBtn.Controls.Add(btnPasswdGenerator, 1, 0); + pnlPasswordTxtAndBtn.Location = new System.Drawing.Point(4, 43); + pnlPasswordTxtAndBtn.Name = "pnlPasswordTxtAndBtn"; + pnlPasswordTxtAndBtn.RowCount = 1; + pnlPasswordTxtAndBtn.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + pnlPasswordTxtAndBtn.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + pnlPasswordTxtAndBtn.Size = new System.Drawing.Size(327, 31); + pnlPasswordTxtAndBtn.TabIndex = 1; + // + // txtPasswdGenerator + // + txtPasswdGenerator.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + txtPasswdGenerator.Location = new System.Drawing.Point(3, 4); + txtPasswdGenerator.Name = "txtPasswdGenerator"; + txtPasswdGenerator.PasswordChar = '*'; + txtPasswdGenerator.Size = new System.Drawing.Size(203, 22); + txtPasswdGenerator.TabIndex = 1; + txtPasswdGenerator.TextChanged += txtPasswdGenerator_TextChanged; + // + // btnPasswdGenerator + // + btnPasswdGenerator.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + btnPasswdGenerator.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + btnPasswdGenerator.Enabled = false; + btnPasswdGenerator.Location = new System.Drawing.Point(212, 4); + btnPasswdGenerator.Name = "btnPasswdGenerator"; + btnPasswdGenerator.Size = new System.Drawing.Size(112, 23); + btnPasswdGenerator.TabIndex = 2; + btnPasswdGenerator.Text = "Copy to Clipboard"; + btnPasswdGenerator.UseVisualStyleBackColor = true; + btnPasswdGenerator.Click += btnPasswdGenerator_Click; + // + // lblPasswdGenDescription + // + lblPasswdGenDescription.AutoSize = true; + lblPasswdGenDescription.Dock = System.Windows.Forms.DockStyle.Top; + lblPasswdGenDescription.Location = new System.Drawing.Point(3, 18); + lblPasswdGenDescription.Name = "lblPasswdGenDescription"; + lblPasswdGenDescription.Size = new System.Drawing.Size(327, 13); + lblPasswdGenDescription.TabIndex = 0; + lblPasswdGenDescription.Text = "Generate an encrypted password suitable for registry settings."; + // // SecurityPage // - AutoScaleDimensions = new System.Drawing.SizeF(144F, 144F); + AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - Controls.Add(chkEncryptCompleteFile); - Controls.Add(groupAdvancedSecurityOptions); - Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + Controls.Add(groupPasswordGenerator); + Controls.Add(pnlOptions); + Controls.Add(lblRegistrySettingsUsedInfo); + Margin = new System.Windows.Forms.Padding(4); Name = "SecurityPage"; - Size = new System.Drawing.Size(915, 735); + Size = new System.Drawing.Size(610, 490); groupAdvancedSecurityOptions.ResumeLayout(false); groupAdvancedSecurityOptions.PerformLayout(); tableLayoutPanel1.ResumeLayout(false); tableLayoutPanel1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)numberBoxKdfIterations).EndInit(); + pnlOptions.ResumeLayout(false); + pnlOptions.PerformLayout(); + groupPasswordGenerator.ResumeLayout(false); + groupPasswordGenerator.PerformLayout(); + pnlPasswordTxtAndBtn.ResumeLayout(false); + pnlPasswordTxtAndBtn.PerformLayout(); ResumeLayout(false); - PerformLayout(); } #endregion @@ -210,9 +314,16 @@ namespace mRemoteNG.UI.Forms.OptionsPages private Controls.MrngLabel labelBlockCipher; private MrngComboBox comboBoxBlockCipher; private MrngGroupBox groupAdvancedSecurityOptions; - private Controls.MrngNumericUpDown numberBoxKdfIterations; + internal Controls.MrngNumericUpDown numberBoxKdfIterations; private Controls.MrngLabel labelKdfIterations; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private MrngButton btnTestSettings; + internal System.Windows.Forms.Label lblRegistrySettingsUsedInfo; + private System.Windows.Forms.Panel pnlOptions; + private System.Windows.Forms.GroupBox groupPasswordGenerator; + private System.Windows.Forms.TableLayoutPanel pnlPasswordTxtAndBtn; + private System.Windows.Forms.TextBox txtPasswdGenerator; + private System.Windows.Forms.Button btnPasswdGenerator; + private System.Windows.Forms.Label lblPasswdGenDescription; } } diff --git a/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.cs b/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.cs index 502c6816..e07b03c5 100644 --- a/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.cs +++ b/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.cs @@ -10,12 +10,22 @@ using mRemoteNG.Security; using mRemoteNG.Security.Factories; using mRemoteNG.Resources.Language; using System.Runtime.Versioning; +using mRemoteNG.Config.Settings.Registry; +using mRemoteNG.Security.SymmetricEncryption; namespace mRemoteNG.UI.Forms.OptionsPages { [SupportedOSPlatform("windows")] public sealed partial class SecurityPage : OptionsPage { + #region Private Fields + private OptRegistrySecurityPage pageRegSettingsInstance; + + private readonly Timer clipboardClearTimer = new() { Interval = 1000 }; + private const int clipboardClearSeconds = 30; + private int countdownSeconds = clipboardClearSeconds; + #endregion + public SecurityPage() { InitializeComponent(); @@ -41,6 +51,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages labelKdfIterations.Text = Language.EncryptionKeyDerivationIterations; groupAdvancedSecurityOptions.Text = Language.AdvancedSecurityOptions; btnTestSettings.Text = Language.TestSettings; + lblRegistrySettingsUsedInfo.Text = Language.OptionsCompanyPolicyMessage; } public override void LoadSettings() @@ -60,6 +71,41 @@ namespace mRemoteNG.UI.Forms.OptionsPages Properties.OptionsSecurityPage.Default.EncryptionKeyDerivationIterations = (int)numberBoxKdfIterations.Value; } + public override void LoadRegistrySettings() + { + Type settingsType = typeof(OptRegistrySecurityPage); + RegistryLoader.RegistrySettings.TryGetValue(settingsType, out var settings); + pageRegSettingsInstance = settings as OptRegistrySecurityPage; + + RegistryLoader.Cleanup(settingsType); + + // *** + // Disable controls based on the registry settings. + // + if (pageRegSettingsInstance.EncryptCompleteConnectionsFile.IsSet) + DisableControl(chkEncryptCompleteFile); + + if (pageRegSettingsInstance.EncryptionEngine.IsSet) + DisableControl(comboBoxEncryptionEngine); + + if (pageRegSettingsInstance.EncryptionBlockCipherMode.IsSet) + DisableControl(comboBoxBlockCipher); + + if (pageRegSettingsInstance.EncryptionKeyDerivationIterations.IsSet) + DisableControl(numberBoxKdfIterations); + + // Updates the visibility of the information label indicating whether registry settings are used. + lblRegistrySettingsUsedInfo.Visible = ShowRegistrySettingsUsedInfo(); + } + + private bool ShowRegistrySettingsUsedInfo() + { + return pageRegSettingsInstance.EncryptCompleteConnectionsFile.IsSet + || pageRegSettingsInstance.EncryptionEngine.IsSet + || pageRegSettingsInstance.EncryptionBlockCipherMode.IsSet + || pageRegSettingsInstance.EncryptionKeyDerivationIterations.IsSet; + } + public override void RevertSettings() { } @@ -101,5 +147,108 @@ namespace mRemoteNG.UI.Forms.OptionsPages MessageBoxButtons.OK, MessageBoxIcon.Information); } + + + /// + /// Encrypts the entered password, copies it to the clipboard, and starts a 30-second timer to clear the clipboard. + /// Also updates a countdown display in the UI. + /// + /// Event source. + /// Event data. + private void btnPasswdGenerator_Click(object sender, EventArgs e) + { + if (string.IsNullOrEmpty(txtPasswdGenerator.Text)) return; + + var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); + + try + { + // Encrypt and set the clipboard content + string encryptedText = cryptographyProvider.Encrypt(txtPasswdGenerator.Text, Runtime.EncryptionKey); + System.Windows.Clipboard.SetText(encryptedText); + } + catch (System.Runtime.InteropServices.COMException) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Failed to set clipboard content. Please try again."); + return; + } + + // Reset the countdown and start the timer + ResetAndStartTimer(); + } + + /// + /// Resets the countdown timer and starts it. + /// + private void ResetAndStartTimer() + { + // Stop the timer if it's running + if (clipboardClearTimer.Enabled) + { + clipboardClearTimer.Stop(); + } + + countdownSeconds = clipboardClearSeconds; // Reset countdown + clipboardClearTimer.Tick -= ClipboardClearTimer_Tick; // Detach in case it was previously attached + clipboardClearTimer.Tick += ClipboardClearTimer_Tick; // Re-attach event handler + clipboardClearTimer.Start(); + } + + /// + /// Handles the timer tick event for clearing the clipboard. + /// Decrements the countdown, updates the UI label, and clears the clipboard when the countdown reaches zero. + /// Stops the timer and handles any errors that occur during clipboard clearing. + /// + /// Event source. + /// Event data. + private void ClipboardClearTimer_Tick(object sender, EventArgs e) + { + if (countdownSeconds > 0) + { + countdownSeconds--; + } + else + { + StopClipboardClearTimer(); + ClearClipboard(); + } + } + + /// + /// Stops the clipboard clear timer and detaches the event handler. + /// + private void StopClipboardClearTimer() + { + clipboardClearTimer.Stop(); + clipboardClearTimer.Tick -= ClipboardClearTimer_Tick; + } + + /// + /// Clears the clipboard and handles any exceptions that occur. + /// + private void ClearClipboard() + { + try + { + System.Windows.Clipboard.Clear(); + txtPasswdGenerator.Clear(); + } + catch (System.Runtime.InteropServices.COMException) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Failed to clear clipboard."); + } + } + + /// + /// Handles the TextChanged event for the password generator TextBox. + /// Enables or disables the button depending on whether the TextBox has content. + /// + /// Event source. + /// Event data. + private void txtPasswdGenerator_TextChanged(object sender, EventArgs e) + { + // Enable the button if there's text in the TextBox, disable it otherwise. + btnPasswdGenerator.Enabled = !string.IsNullOrWhiteSpace(txtPasswdGenerator.Text); + } } } \ No newline at end of file diff --git a/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.resx b/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.resx index f298a7be..8b2ff64a 100644 --- a/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.resx +++ b/mRemoteNG/UI/Forms/OptionsPages/SecurityPage.resx @@ -1,4 +1,64 @@ - + + + diff --git a/mRemoteNGDocumentation/registry/credential_settings.rst b/mRemoteNGDocumentation/registry/credential_settings.rst index 17a26d05..81fda2e9 100644 --- a/mRemoteNGDocumentation/registry/credential_settings.rst +++ b/mRemoteNGDocumentation/registry/credential_settings.rst @@ -18,7 +18,7 @@ Common Allow Export Usernames ---------------------- -Determines whether exporting usernames is allowed. +Specifies whether the export of usernames for saved connections is allowed. - **Value Name:** ``AllowExportUsernames`` - **Value Type:** ``REG_SZ`` @@ -30,7 +30,7 @@ Determines whether exporting usernames is allowed. Allow Export Passwords ---------------------- -Determines whether exporting passwords is allowed. +Specifies whether the export of passwords for saved connections is allowed. - **Value Name:** ``AllowExportPasswords`` - **Value Type:** ``REG_SZ`` @@ -42,7 +42,7 @@ Determines whether exporting passwords is allowed. Allow Save Usernames -------------------- -Determines whether saving usernames is allowed. +Specifies whether the saving of usernames for saved connections is allowed. - **Value Name:** ``AllowSaveUsernames`` - **Value Type:** ``REG_SZ`` @@ -61,7 +61,7 @@ Determines whether saving usernames is allowed. Allow Save Passwords -------------------- -Determines whether saving passwords is allowed. +Specifies whether the saving of passwords for saved connections is allowed. - **Value Name:** ``AllowSavePasswords`` - **Value Type:** ``REG_SZ`` @@ -154,7 +154,8 @@ Specifies the default domain. Default Username Enabled ------------------------ -Specifies that entering the custom default username field is enabled. +Controls whether the default username field is enabled or disabled. +Locking the field may make more sense than disabling the entire settings option. - **Value Name:** ``DefaultUsernameEnabled`` - **Value Type:** ``REG_SZ`` @@ -166,7 +167,8 @@ Specifies that entering the custom default username field is enabled. Default Password Enabled ------------------------ -Specifies that entering the custom default password field is enabled. +Controls whether the default password field is enabled or disabled. +Locking the field may make more sense than disabling the entire settings option. - **Value Name:** ``DefaultPasswordEnabled`` - **Value Type:** ``REG_SZ`` @@ -178,7 +180,8 @@ Specifies that entering the custom default password field is enabled. Default User Via API Enabled ---------------------------- -Specifies that entering the custom default api user field is enabled. +Controls whether the default user via API field is enabled or disabled. +Locking the field may make more sense than disabling the entire settings option. - **Value Name:** ``DefaultUserViaAPIEnabled`` - **Value Type:** ``REG_SZ`` diff --git a/mRemoteNGDocumentation/registry/security_settings.rst b/mRemoteNGDocumentation/registry/security_settings.rst new file mode 100644 index 00000000..dc0ef564 --- /dev/null +++ b/mRemoteNGDocumentation/registry/security_settings.rst @@ -0,0 +1,82 @@ +***************** +Security Settings +***************** +.. versionadded:: v1.77.3 + +.. warning:: + Before proceeding with any changes to the Windows Registry, it is imperative that you carefully read and comprehend the + **Modifying the Registry**, **Restricted Registry Settings** and **Disclaimer** + on :doc:`Registry Settings Infromation `. + + +Options +==================== +Configure the options page to modify functionalities as described. + +- **Registry Hive:** ``HKEY_LOCAL_MACHINE`` +- **Registry Path:** ``SOFTWARE\mRemoteNG\Security\Options`` + +Encrypt Complete Connections File +--------------------------------- +Specifies the encryption engine used for encryption. + +- **Value Name:** ``EncryptCompleteConnectionsFile`` +- **Value Type:** ``REG_SZ`` +- **Values:** + + - Enable: ``true`` + - Disable: ``false`` + + +Encryption Engine +----------------- +Specifies the encryption engine used for encryption. + +- **Value Name:** ``EncryptionEngine`` +- **Value Type:** ``REG_SZ`` +- **Values:** + + - ``AES`` + - ``Serpent`` + - ``Twofish`` + + +Encryption Block Cipher Mode +---------------------------- +Specifies the block cipher mode used for encryption. + +- **Value Name:** ``EncryptionBlockCipherMode`` +- **Value Type:** ``REG_SZ`` +- **Values:** + + - ``GCM`` + - ``CCM`` + - ``EAX`` + + +Encryption Key Derivation Iterations +------------------------------------ +Specifies the number of iterations used in the encryption key derivation process. + +- **Value Name:** ``EncryptionKeyDerivationIterations`` +- **Value Type:** ``REG_DWORD`` +- **Values:** + + - Minimum: ``1000`` + - Maximum: ``50000`` + + +Registry Template +================= + +.. code:: + + Windows Registry Editor Version 5.00 + + [HKEY_LOCAL_MACHINE\SOFTWARE\mRemoteNG\Security] + + [HKEY_LOCAL_MACHINE\SOFTWARE\mRemoteNG\Security\Options] + "EncryptionEngine"="AES" + "EncryptionBlockCipherMode"="GCM" + "EncryptCompleteConnectionsFile"="false" + "EncryptionKeyDerivationIterations"=dword:00009c40 diff --git a/mRemoteNGDocumentation/registry_settings_guide.rst b/mRemoteNGDocumentation/registry_settings_guide.rst index dd92db66..9b149600 100644 --- a/mRemoteNGDocumentation/registry_settings_guide.rst +++ b/mRemoteNGDocumentation/registry_settings_guide.rst @@ -29,4 +29,5 @@ Make changes with caution and ensure that you have backups before making any adj registry/notification_settings.rst registry/credential_settings.rst registry/sqlServer_settings.rst - registry/updates_settings.rst \ No newline at end of file + registry/updates_settings.rst + registry/security_settings.rst \ No newline at end of file