feat: Add registry settings for Security Page and encryption key generator

- Added new registry settings for managing security-related configurations on the Security Page.
- Implemented an encryption key generator to securely generate a password for store in the registry.
- Passwords are placed encrypted on the clipboard for 30 seconds.
- Update documents and finalize comments
This commit is contained in:
xRushG
2024-10-01 16:02:59 +02:00
parent d018fdbace
commit 8041f58ffd
8 changed files with 556 additions and 47 deletions

View File

@@ -40,22 +40,22 @@ namespace mRemoteNG.Config.Settings.Registry
#region general credential registry settings
/// <summary>
/// Setting that indicates whether exporting passwords is allowed.
/// Specifies whether the export of passwords for saved connections is allowed.
/// </summary>
public static bool AllowExportPasswords { get; }
/// <summary>
/// Setting that indicates whether exporting usernames is allowed.
/// Specifies whether the export of usernames for saved connections is allowed.
/// </summary>
public static bool AllowExportUsernames { get; }
/// <summary>
/// Setting that indicates whether saving passwords in connections is allowed.
/// Specifies whether the saving of usernames for saved connections is allowed.
/// </summary>
public static bool AllowSavePasswords { get; }
/// <summary>
/// Setting that indicates whether saving in connections usernames is allowed.
/// Specifies whether the saving of passwords for saved connections is allowed.
/// </summary>
public static bool AllowSaveUsernames { get; }

View File

@@ -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
{
/// <summary>
/// Specifies whether the complete connections file is encrypted.
/// </summary>
public WinRegistryEntry<bool> EncryptCompleteConnectionsFile { get; private set; }
/// <summary>
/// Specifies the encryption engine used for encryption.
/// </summary>
public WinRegistryEntry<string> EncryptionEngine { get; private set; }
/// <summary>
/// Specifies the block cipher mode used for encryption.
/// </summary>
public WinRegistryEntry<string> EncryptionBlockCipherMode { get; private set; }
/// <summary>
/// Specifies the number of iterations used in the encryption key derivation process.
/// </summary>
public WinRegistryEntry<int> EncryptionKeyDerivationIterations { get; private set; }
public OptRegistrySecurityPage()
{
RegistryHive hive = WindowsRegistryInfo.Hive;
string subKey = WindowsRegistryInfo.SecurityOptions;
EncryptCompleteConnectionsFile = new WinRegistryEntry<bool>(hive, subKey, nameof(EncryptCompleteConnectionsFile)).Read();
EncryptionEngine = new WinRegistryEntry<string>(hive, subKey, nameof(EncryptionEngine)).Read();
EncryptionBlockCipherMode = new WinRegistryEntry<string>(hive, subKey, nameof(EncryptionBlockCipherMode)).Read();
EncryptionKeyDerivationIterations = new WinRegistryEntry<int>(hive, subKey, nameof(EncryptionKeyDerivationIterations)).Read();
SetupValidation();
Apply();
}
/// <summary>
/// Configures validation settings for various parameters
/// </summary>
private void SetupValidation()
{
var SecurityPage = new UI.Forms.OptionsPages.SecurityPage();
EncryptionEngine.SetValidation<BlockCipherEngines>();
EncryptionBlockCipherMode.SetValidation<BlockCipherModes>();
int EncryptionKeyDerivIteraMin = (int)SecurityPage.numberBoxKdfIterations.Minimum;
int EncryptionKeyDerivIteraMax = (int)SecurityPage.numberBoxKdfIterations.Maximum;
EncryptionKeyDerivationIterations.SetValidation(EncryptionKeyDerivIteraMin, EncryptionKeyDerivIteraMax);
}
/// <summary>
/// Applies registry settings and overrides various properties.
/// </summary>
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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="sender">Event source.</param>
/// <param name="e">Event data.</param>
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();
}
/// <summary>
/// Resets the countdown timer and starts it.
/// </summary>
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();
}
/// <summary>
/// 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.
/// </summary>
/// <param name="sender">Event source.</param>
/// <param name="e">Event data.</param>
private void ClipboardClearTimer_Tick(object sender, EventArgs e)
{
if (countdownSeconds > 0)
{
countdownSeconds--;
}
else
{
StopClipboardClearTimer();
ClearClipboard();
}
}
/// <summary>
/// Stops the clipboard clear timer and detaches the event handler.
/// </summary>
private void StopClipboardClearTimer()
{
clipboardClearTimer.Stop();
clipboardClearTimer.Tick -= ClipboardClearTimer_Tick;
}
/// <summary>
/// Clears the clipboard and handles any exceptions that occur.
/// </summary>
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.");
}
}
/// <summary>
/// Handles the TextChanged event for the password generator TextBox.
/// Enables or disables the button depending on whether the TextBox has content.
/// </summary>
/// <param name="sender">Event source.</param>
/// <param name="e">Event data.</param>
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);
}
}
}

View File

@@ -1,4 +1,64 @@
<root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">

View File

@@ -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``

View File

@@ -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 <registry_settings_information>`.
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

View File

@@ -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
registry/updates_settings.rst
registry/security_settings.rst