diff --git a/mRemoteNGTests/Security/LegacyRijndaelCryptographyProviderTests.cs b/mRemoteNGTests/Security/LegacyRijndaelCryptographyProviderTests.cs new file mode 100644 index 000000000..2d34f871f --- /dev/null +++ b/mRemoteNGTests/Security/LegacyRijndaelCryptographyProviderTests.cs @@ -0,0 +1,58 @@ +using System.Security; +using mRemoteNG.Security; +using NUnit.Framework; + + +namespace mRemoteNGTests.Security +{ + [TestFixture()] + public class LegacyRijndaelCryptographyProviderTests + { + private ICryptographyProvider _rijndaelCryptographyProvider; + private SecureString _encryptionKey; + private string _plainText; + + [SetUp] + public void SetUp() + { + _rijndaelCryptographyProvider = new LegacyRijndaelCryptographyProvider(); + _encryptionKey = "mR3m".ConvertToSecureString(); + _plainText = "MySecret!"; + } + + [TearDown] + public void Teardown() + { + _rijndaelCryptographyProvider = null; + } + + [Test] + public void GetBlockSizeReturnsProperValueForRijndael() + { + Assert.That(_rijndaelCryptographyProvider.BlockSizeInBytes, Is.EqualTo(16)); + } + + [Test] + public void EncryptionOutputsBase64String() + { + var cipherText = _rijndaelCryptographyProvider.Encrypt(_plainText, _encryptionKey); + Assert.That(cipherText.IsBase64String, Is.True); + } + + [Test] + public void DecryptedTextIsEqualToOriginalPlainText() + { + var cipherText = _rijndaelCryptographyProvider.Encrypt(_plainText, _encryptionKey); + var decryptedCipherText = _rijndaelCryptographyProvider.Decrypt(cipherText, _encryptionKey); + Assert.That(decryptedCipherText, Is.EqualTo(_plainText)); + } + + [Test] + public void EncryptingTheSameValueReturnsNewCipherTextEachTime() + { + var cipherText1 = _rijndaelCryptographyProvider.Encrypt(_plainText, _encryptionKey); + var cipherText2 = _rijndaelCryptographyProvider.Encrypt(_plainText, _encryptionKey); + Assert.That(cipherText1, Is.Not.EqualTo(cipherText2)); + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/mRemoteNGTests.csproj b/mRemoteNGTests/mRemoteNGTests.csproj index acb911769..1d7a1b822 100644 --- a/mRemoteNGTests/mRemoteNGTests.csproj +++ b/mRemoteNGTests/mRemoteNGTests.csproj @@ -107,6 +107,7 @@ + Form diff --git a/mRemoteV1/App/Info/GeneralAppInfo.cs b/mRemoteV1/App/Info/GeneralAppInfo.cs index e4aa01a05..538f74e0f 100644 --- a/mRemoteV1/App/Info/GeneralAppInfo.cs +++ b/mRemoteV1/App/Info/GeneralAppInfo.cs @@ -2,8 +2,10 @@ using System.Collections.Generic; using System; using System.IO; using System.Reflection; +using System.Security; using System.Threading; using System.Windows.Forms; +using mRemoteNG.Security; using static System.Environment; @@ -19,7 +21,7 @@ namespace mRemoteNG.App.Info public static readonly string ProdName = Application.ProductName; public static readonly string copyright = ((AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyCopyrightAttribute), false)).Copyright; public static readonly string HomePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - public static readonly string EncryptionKey = "mR3m"; + public static readonly SecureString EncryptionKey = "mR3m".ConvertToSecureString(); public static string ReportingFilePath = ""; public static readonly string PuttyPath = HomePath + "\\PuTTYNG.exe"; public static string UserAgent diff --git a/mRemoteV1/Config/Connections/ConnectionsLoader.cs b/mRemoteV1/Config/Connections/ConnectionsLoader.cs index e2645f653..406cfd924 100644 --- a/mRemoteV1/Config/Connections/ConnectionsLoader.cs +++ b/mRemoteV1/Config/Connections/ConnectionsLoader.cs @@ -8,8 +8,10 @@ using System.Data; using System.Data.SqlClient; using System.Globalization; using System.IO; +using System.Security; using System.Windows.Forms; using System.Xml; +using mRemoteNG.App.Info; using mRemoteNG.Tree; using mRemoteNG.Connection; using mRemoteNG.Container; @@ -26,7 +28,7 @@ namespace mRemoteNG.Config.Connections #region Private Properties private XmlDocument xDom; private double confVersion; - private string pW = "mR3m"; + private SecureString pW = GeneralAppInfo.EncryptionKey; private SqlConnection sqlCon; private SqlCommand sqlQuery; private SqlDataReader sqlRd; @@ -1252,7 +1254,7 @@ namespace mRemoteNG.Config.Connections { pW = Tools.MiscTools.PasswordDialog(passwordName, false); - if (string.IsNullOrEmpty(pW)) + if (pW.Length == 0) { return false; } @@ -1264,7 +1266,7 @@ namespace mRemoteNG.Config.Connections { pW = Tools.MiscTools.PasswordDialog(passwordName, false); - if (string.IsNullOrEmpty(pW)) + if (pW.Length == 0) { return false; } @@ -1273,7 +1275,7 @@ namespace mRemoteNG.Config.Connections if (rootInfo != null) { rootInfo.Password = true; - rootInfo.PasswordString = pW; + rootInfo.PasswordString = pW.ConvertToUnsecureString(); } } diff --git a/mRemoteV1/Config/Connections/ConnectionsSaver.cs b/mRemoteV1/Config/Connections/ConnectionsSaver.cs index 5c5b509e8..eb97b9924 100644 --- a/mRemoteV1/Config/Connections/ConnectionsSaver.cs +++ b/mRemoteV1/Config/Connections/ConnectionsSaver.cs @@ -3,6 +3,7 @@ using System.Data.SqlClient; using System.Drawing; using System.Globalization; using System.IO; +using System.Security; using System.Text; using System.Windows.Forms; using System.Xml; @@ -37,7 +38,7 @@ namespace mRemoteNG.Config.Connections #region Private Properties private XmlTextWriter _xmlTextWriter; - private string _password = "mR3m"; + private SecureString _password = GeneralAppInfo.EncryptionKey; private SqlConnection _sqlConnection; private SqlCommand _sqlQuery; @@ -192,7 +193,7 @@ namespace mRemoteNG.Config.Connections { if (((RootNodeInfo) tN.Tag).Password) { - _password = Convert.ToString(((RootNodeInfo) tN.Tag).PasswordString); + _password = Convert.ToString(((RootNodeInfo) tN.Tag).PasswordString).ConvertToSecureString(); strProtected = cryptographyProvider.Encrypt("ThisIsProtected", _password); } else @@ -593,7 +594,7 @@ namespace mRemoteNG.Config.Connections { if (((RootNodeInfo) treeNode.Tag).Password) { - _password = Convert.ToString(((RootNodeInfo) treeNode.Tag).PasswordString); + _password = Convert.ToString(((RootNodeInfo) treeNode.Tag).PasswordString).ConvertToSecureString(); _xmlTextWriter.WriteAttributeString("Protected", "", cryptographyProvider.Encrypt("ThisIsProtected", _password)); } else diff --git a/mRemoteV1/Security/LegacyRijndaelCryptographyProvider.cs b/mRemoteV1/Security/LegacyRijndaelCryptographyProvider.cs index 6814fadd5..e865fbd4f 100644 --- a/mRemoteV1/Security/LegacyRijndaelCryptographyProvider.cs +++ b/mRemoteV1/Security/LegacyRijndaelCryptographyProvider.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Security; using System.Security.Cryptography; using System.Text; using mRemoteNG.App; @@ -8,21 +9,30 @@ using mRemoteNG.Messages; namespace mRemoteNG.Security { - public class LegacyRijndaelCryptographyProvider + public class LegacyRijndaelCryptographyProvider : ICryptographyProvider { - public string Encrypt(string strToEncrypt, string strSecret) + public int BlockSizeInBytes { get; } + + public string CipherEngine { get; } + + public LegacyRijndaelCryptographyProvider() + { + CipherEngine = "Rijndael"; + BlockSizeInBytes = 16; + } + + + public string Encrypt(string strToEncrypt, SecureString strSecret) { - if (strToEncrypt == "" || strSecret == "") - { + if (strToEncrypt == "" || strSecret.Length == 0) return strToEncrypt; - } try { var rd = new RijndaelManaged(); var md5 = new MD5CryptoServiceProvider(); - var key = md5.ComputeHash(Encoding.UTF8.GetBytes(strSecret)); + var key = md5.ComputeHash(Encoding.UTF8.GetBytes(strSecret.ConvertToUnsecureString())); md5.Clear(); rd.Key = key; @@ -53,9 +63,9 @@ namespace mRemoteNG.Security return strToEncrypt; } - public string Decrypt(string ciphertextBase64, string password) + public string Decrypt(string ciphertextBase64, SecureString password) { - if (string.IsNullOrEmpty(ciphertextBase64) || string.IsNullOrEmpty(password)) + if (string.IsNullOrEmpty(ciphertextBase64) || password.Length == 0) return ciphertextBase64; try @@ -65,7 +75,7 @@ namespace mRemoteNG.Security using (var rijndaelManaged = new RijndaelManaged()) using (var md5 = new MD5CryptoServiceProvider()) { - var key = md5.ComputeHash(Encoding.UTF8.GetBytes(password)); + var key = md5.ComputeHash(Encoding.UTF8.GetBytes(password.ConvertToUnsecureString())); rijndaelManaged.Key = key; var ciphertext = Convert.FromBase64String(ciphertextBase64); @@ -73,9 +83,8 @@ namespace mRemoteNG.Security using (var cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateDecryptor(), CryptoStreamMode.Read)) using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8, true)) { - const int ivLength = 16; - var iv = new byte[ivLength - 1 + 1]; - memoryStream.Read(iv, 0, ivLength); + var iv = new byte[BlockSizeInBytes]; + memoryStream.Read(iv, 0, BlockSizeInBytes); rijndaelManaged.IV = iv; plaintext = streamReader.ReadToEnd(); rijndaelManaged.Clear(); diff --git a/mRemoteV1/Tools/MiscTools.cs b/mRemoteV1/Tools/MiscTools.cs index 08f44b3f5..f8b9a487c 100644 --- a/mRemoteV1/Tools/MiscTools.cs +++ b/mRemoteV1/Tools/MiscTools.cs @@ -5,10 +5,12 @@ using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.InteropServices; +using System.Security; using System.Windows.Forms; using mRemoteNG.App; using mRemoteNG.Forms; using mRemoteNG.Messages; +using mRemoteNG.Security; using mRemoteNG.UI.Window; using static System.String; @@ -58,11 +60,11 @@ namespace mRemoteNG.Tools - public static string PasswordDialog(string passwordName = null, bool verify = true) + public static SecureString PasswordDialog(string passwordName = null, bool verify = true) { PasswordForm passwordForm = new PasswordForm(passwordName, verify); - return passwordForm.ShowDialog() == DialogResult.OK ? passwordForm.Password : ""; + return passwordForm.ShowDialog() == DialogResult.OK ? passwordForm.Password.ConvertToSecureString() : "".ConvertToSecureString(); } diff --git a/mRemoteV1/UI/Window/ConfigWindow.cs b/mRemoteV1/UI/Window/ConfigWindow.cs index 5f1ba9bfc..800cf2ea1 100644 --- a/mRemoteV1/UI/Window/ConfigWindow.cs +++ b/mRemoteV1/UI/Window/ConfigWindow.cs @@ -12,6 +12,7 @@ using System.Drawing; using System.IO; using System.Net.NetworkInformation; using System.Windows.Forms; +using mRemoteNG.Security; using mRemoteNG.UI.Controls.FilteredPropertyGrid; using WeifenLuo.WinFormsUI.Docking; @@ -775,10 +776,10 @@ namespace mRemoteNG.UI.Window passwordName = Path.GetFileName(Runtime.GetStartupConnectionFileName()); var password = MiscTools.PasswordDialog(passwordName); - if (string.IsNullOrEmpty(password)) + if (password.Length == 0) rootInfo.Password = false; else - rootInfo.PasswordString = password; + rootInfo.PasswordString = password.ConvertToUnsecureString(); } break; case "Name":