Skip to content

Commit cc758af

Browse files
committed
Enhance password encryption and validation logic
- Added validation to `EncryptPassword` to ensure encrypted passwords can be decrypted and match the original plaintext. - Introduced `SafeEncryptPassword` for safer encryption with comprehensive error handling and optional validation. - Improved error handling in `MainForm` to warn users and handle encryption failures gracefully. - Adjusted UI layout in `TimestampServerManagementForm` for better alignment of controls. - Enhanced logging with detailed messages and unique event codes for better traceability. - Improved code robustness with null/empty checks and enhanced exception handling. - Refactored encryption and validation logic for better maintainability and readability.
1 parent 239b5b6 commit cc758af

3 files changed

Lines changed: 110 additions & 9 deletions

File tree

src/SignToolGUI/Class/SecurePasswordManager.cs

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ private static string GenerateMachineSpecificKey()
7474
}
7575

7676
/// <summary>
77-
/// Encrypts a password using AES with machine-specific key derivation
77+
/// Encrypts a password using AES with machine-specific key derivation and validates the result
7878
/// </summary>
7979
/// <param name="plainText">Password to encrypt</param>
8080
/// <returns>Base64 encoded encrypted password with metadata</returns>
@@ -120,7 +120,17 @@ public static string EncryptPassword(string plainText)
120120
csEncrypt.FlushFinalBlock();
121121
}
122122

123-
return Convert.ToBase64String(msEncrypt.ToArray());
123+
var encryptedResult = Convert.ToBase64String(msEncrypt.ToArray());
124+
125+
// Validate that we can decrypt what we just encrypted on this machine
126+
if (!ValidateEncryptionResult(encryptedResult, plainText))
127+
{
128+
Message("Encryption validation failed - encrypted data cannot be decrypted", EventType.Error, 3039);
129+
throw new InvalidOperationException("Encryption validation failed - the encrypted password cannot be decrypted on this machine");
130+
}
131+
132+
Message("Password encryption and validation successful", EventType.Information, 3040);
133+
return encryptedResult;
124134
}
125135
}
126136
}
@@ -132,6 +142,41 @@ public static string EncryptPassword(string plainText)
132142
}
133143
}
134144

145+
/// <summary>
146+
/// Validates that an encrypted password can be properly decrypted and matches the original
147+
/// </summary>
148+
/// <param name="encryptedPassword">The encrypted password to validate</param>
149+
/// <param name="originalPassword">The original plain text password for comparison</param>
150+
/// <returns>True if the encrypted password can be decrypted and matches the original</returns>
151+
private static bool ValidateEncryptionResult(string encryptedPassword, string originalPassword)
152+
{
153+
try
154+
{
155+
// Test that we can decrypt the password
156+
if (!CanDecryptOnThisMachine(encryptedPassword))
157+
{
158+
Message("Validation failed: Cannot decrypt encrypted password on this machine", EventType.Warning, 3041);
159+
return false;
160+
}
161+
162+
// Test that the decrypted password matches the original
163+
var decryptedPassword = DecryptPassword(encryptedPassword);
164+
if (decryptedPassword != originalPassword)
165+
{
166+
Message("Validation failed: Decrypted password does not match original", EventType.Warning, 3042);
167+
return false;
168+
}
169+
170+
Message("Encryption validation successful: Password can be decrypted and matches original", EventType.Information, 3043);
171+
return true;
172+
}
173+
catch (Exception ex)
174+
{
175+
Message($"Error during encryption validation: {ex.Message}", EventType.Warning, 3044);
176+
return false;
177+
}
178+
}
179+
135180
/// <summary>
136181
/// Decrypts a password using AES with machine-specific key derivation
137182
/// </summary>
@@ -245,15 +290,53 @@ private static byte[] GenerateRandomBytes(int size)
245290
/// <returns>True if the password can be decrypted on this machine</returns>
246291
public static bool CanDecryptOnThisMachine(string encryptedPassword)
247292
{
293+
if (string.IsNullOrEmpty(encryptedPassword))
294+
return false;
295+
248296
try
249297
{
250298
var decrypted = DecryptPassword(encryptedPassword);
251299
return !string.IsNullOrEmpty(decrypted);
252300
}
253-
catch
301+
catch (Exception ex)
254302
{
303+
Message($"Cannot decrypt password on this machine: {ex.Message}", EventType.Information, 3045);
255304
return false;
256305
}
257306
}
307+
308+
/// <summary>
309+
/// Enhanced method to safely encrypt and validate a password with comprehensive error handling
310+
/// </summary>
311+
/// <param name="plainText">Password to encrypt</param>
312+
/// <param name="performValidation">Whether to perform validation test (default: true)</param>
313+
/// <returns>Encrypted password or empty string if encryption/validation fails</returns>
314+
public static string SafeEncryptPassword(string plainText, bool performValidation = true)
315+
{
316+
if (string.IsNullOrEmpty(plainText))
317+
return string.Empty;
318+
319+
try
320+
{
321+
var encrypted = EncryptPassword(plainText);
322+
323+
if (performValidation && !string.IsNullOrEmpty(encrypted))
324+
{
325+
// Additional validation using CanDecryptOnThisMachine
326+
if (!CanDecryptOnThisMachine(encrypted))
327+
{
328+
Message("Safe encryption failed: Encrypted password cannot be validated for decryption", EventType.Error, 3046);
329+
return string.Empty;
330+
}
331+
}
332+
333+
return encrypted;
334+
}
335+
catch (Exception ex)
336+
{
337+
Message($"Safe encryption failed: {ex.Message}", EventType.Error, 3047);
338+
return string.Empty;
339+
}
340+
}
258341
}
259342
}

src/SignToolGUI/Forms/MainForm.cs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,11 +1168,29 @@ private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
11681168
}
11691169
}
11701170

1171-
// Encrypt the certificate password and save it to the configuration file
1172-
var encryptedstring = SecurePasswordManager.EncryptPassword(textBoxPFXPassword.Text);
1171+
// Encrypt the certificate password with validation and save it to the configuration file
1172+
var encryptedstring = SecurePasswordManager.SafeEncryptPassword(textBoxPFXPassword.Text);
11731173

1174-
// Save the encrypted certificate password to the configuration file
1175-
iniFile.WriteValue("Program", "CertificatePassword", encryptedstring);
1174+
if (string.IsNullOrEmpty(encryptedstring) && !string.IsNullOrEmpty(textBoxPFXPassword.Text))
1175+
{
1176+
// Encryption failed, warn the user
1177+
MessageBox.Show("Failed to securely encrypt the certificate password. The password will not be saved.",
1178+
"Encryption Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
1179+
1180+
// Save empty password instead of potentially corrupted data
1181+
iniFile.WriteValue("Program", "CertificatePassword", "");
1182+
Message("Certificate password not saved due to encryption failure", EventType.Warning, 3048);
1183+
}
1184+
else
1185+
{
1186+
// Save the encrypted certificate password to the configuration file
1187+
iniFile.WriteValue("Program", "CertificatePassword", encryptedstring);
1188+
1189+
if (!string.IsNullOrEmpty(encryptedstring))
1190+
{
1191+
Message("Certificate password successfully encrypted and saved", EventType.Information, 3049);
1192+
}
1193+
}
11761194
}
11771195
catch (Exception ex)
11781196
{

src/SignToolGUI/Forms/TimestampServerManagementForm.Designer.cs

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)