sql now encrypts and decrypts passwords

This commit is contained in:
David Sparer
2018-11-03 18:28:53 -05:00
parent 19bb8f7595
commit abcab2aadf
10 changed files with 108 additions and 26 deletions

View File

@@ -1,11 +1,12 @@
using System.Data;
using System.Linq;
using mRemoteNG.Config.Serializers;
using System.Security;
using mRemoteNG.Config.Serializers.MsSql;
using mRemoteNG.Connection;
using mRemoteNG.Security;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tree;
using mRemoteNGTests.TestHelpers;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Config.Serializers
@@ -13,30 +14,37 @@ namespace mRemoteNGTests.Config.Serializers
public class DataTableDeserializerTests
{
private DataTableDeserializer _deserializer;
private ICryptographyProvider _cryptographyProvider;
[SetUp]
public void Setup()
{
_cryptographyProvider = new LegacyRijndaelCryptographyProvider();
}
[Test]
public void WeCanDeserializeATree()
{
var model = CreateConnectionTreeModel();
var dataTable = CreateDataTable(model.RootNodes[0]);
_deserializer = new DataTableDeserializer();
_deserializer = new DataTableDeserializer(_cryptographyProvider, new SecureString());
var output = _deserializer.Deserialize(dataTable);
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(model.GetRecursiveChildList().Count()));
Assert.That(output.GetRecursiveChildList().Count, Is.EqualTo(model.GetRecursiveChildList().Count));
}
[Test]
public void WeCanDeserializeASingleEntry()
{
var dataTable = CreateDataTable(new ConnectionInfo());
_deserializer = new DataTableDeserializer();
_deserializer = new DataTableDeserializer(_cryptographyProvider, new SecureString());
var output = _deserializer.Deserialize(dataTable);
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(1));
Assert.That(output.GetRecursiveChildList().Count, Is.EqualTo(1));
}
private DataTable CreateDataTable(ConnectionInfo tableContent)
{
var serializer = new DataTableSerializer(new SaveFilter());
var serializer = new DataTableSerializer(new SaveFilter(), _cryptographyProvider, new SecureString());
return serializer.Serialize(tableContent);
}

View File

@@ -1,12 +1,15 @@
using System.Linq;
using System.Security;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.MsSql;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Security;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNGTests.TestHelpers;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Config.Serializers
@@ -20,7 +23,10 @@ namespace mRemoteNGTests.Config.Serializers
public void Setup()
{
_saveFilter = new SaveFilter();
_dataTableSerializer = new DataTableSerializer(_saveFilter);
_dataTableSerializer = new DataTableSerializer(
_saveFilter,
new LegacyRijndaelCryptographyProvider(),
new SecureString());
}
[Test]

View File

@@ -2,12 +2,13 @@
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using mRemoteNG.Connection;
namespace mRemoteNG.App.Info
{
public static class SettingsFileInfo
{
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location);
public static string SettingsPath => Runtime.IsPortableEdition ? ExePath : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName;
public static string LayoutFileName { get; } = "pnlLayout.xml";

View File

@@ -1,4 +1,5 @@
using mRemoteNG.Config.DatabaseConnectors;
using System;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.MsSql;
@@ -9,6 +10,10 @@ using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using mRemoteNG.Security;
using mRemoteNG.Security.Authentication;
using mRemoteNG.Security.SymmetricEncryption;
namespace mRemoteNG.Config.Connections
{
@@ -17,6 +22,9 @@ namespace mRemoteNG.Config.Connections
private readonly IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> _localConnectionPropertiesDeserializer;
private readonly IDataProvider<string> _dataProvider;
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; } =
() => MiscTools.PasswordDialog("", false);
public SqlConnectionsLoader(
IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> localConnectionPropertiesDeserializer,
IDataProvider<string> dataProvider)
@@ -31,16 +39,34 @@ namespace mRemoteNG.Config.Connections
var dataProvider = new SqlDataProvider(connector);
var metaDataRetriever = new SqlDatabaseMetaDataRetriever();
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(connector);
var deserializer = new DataTableDeserializer();
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
var metaData = metaDataRetriever.GetDatabaseMetaData(connector);
var decryptionKey = GetDecryptionKey(metaData);
if (!decryptionKey.Any())
throw new Exception("Could not load SQL connections");
databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion);
var dataTable = dataProvider.Load();
var deserializer = new DataTableDeserializer(cryptoProvider, decryptionKey.First());
var connectionTree = deserializer.Deserialize(dataTable);
ApplyLocalConnectionProperties(connectionTree.RootNodes.First(i => i is RootNodeInfo));
return connectionTree;
}
private Optional<SecureString> GetDecryptionKey(SqlConnectionListMetaData metaData)
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
var cipherText = metaData.Protected;
var authenticator = new PasswordAuthenticator(cryptographyProvider, cipherText, AuthenticationRequestor);
var authenticated = authenticator.Authenticate(new RootNodeInfo(RootNodeType.Connection).DefaultPassword.ConvertToSecureString());
if (authenticated)
return authenticator.LastAuthenticatedPassword;
return Optional<SecureString>.Empty;
}
private void ApplyLocalConnectionProperties(ContainerInfo rootNode)
{
var localPropertiesXml = _dataProvider.Load();

View File

@@ -149,13 +149,15 @@ namespace mRemoteNG.Config.Connections
}
}
private void UpdateConnectionsTable(ContainerInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
private void UpdateConnectionsTable(RootNodeInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
{
var sqlQuery = new SqlCommand("DELETE FROM tblCons", sqlDatabaseConnector.SqlConnection);
sqlQuery.ExecuteNonQuery();
var serializer = new DataTableSerializer(_saveFilter);
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
var serializer = new DataTableSerializer(_saveFilter, cryptoProvider, rootTreeNode.PasswordString.ConvertToSecureString());
var dataTable = serializer.Serialize(rootTreeNode);
var dataProvider = new SqlDataProvider(sqlDatabaseConnector);
var sqlQuery = new SqlCommand("DELETE FROM tblCons", sqlDatabaseConnector.SqlConnection);
sqlQuery.ExecuteNonQuery();
dataProvider.Save(dataTable);
}

View File

@@ -12,11 +12,24 @@ using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security;
using mRemoteNG.Security;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
namespace mRemoteNG.Config.Serializers.MsSql
{
public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel>
{
private readonly ICryptographyProvider _cryptographyProvider;
private readonly SecureString _decryptionKey;
public DataTableDeserializer(ICryptographyProvider cryptographyProvider, SecureString decryptionKey)
{
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
_decryptionKey = decryptionKey.ThrowIfNull(nameof(decryptionKey));
}
public ConnectionTreeModel Deserialize(DataTable table)
{
var connectionList = CreateNodesFromTable(table);
@@ -73,7 +86,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.Panel = (string)dataRow["Panel"];
connectionInfo.Username = (string)dataRow["Username"];
connectionInfo.Domain = (string)dataRow["DomainName"];
connectionInfo.Password = (string)dataRow["Password"];
connectionInfo.Password = DecryptValue((string)dataRow["Password"]);
connectionInfo.Hostname = (string)dataRow["Hostname"];
connectionInfo.Protocol = (ProtocolType)Enum.Parse(typeof(ProtocolType), (string)dataRow["Protocol"]);
connectionInfo.PuttySession = (string)dataRow["PuttySession"];
@@ -113,7 +126,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.VNCProxyIP = (string)dataRow["VNCProxyIP"];
connectionInfo.VNCProxyPort = (int)dataRow["VNCProxyPort"];
connectionInfo.VNCProxyUsername = (string)dataRow["VNCProxyUsername"];
connectionInfo.VNCProxyPassword = (string)dataRow["VNCProxyPassword"];
connectionInfo.VNCProxyPassword = DecryptValue((string)dataRow["VNCProxyPassword"]);
connectionInfo.VNCColors = (ProtocolVNC.Colors)Enum.Parse(typeof(ProtocolVNC.Colors), (string)dataRow["VNCColors"]);
connectionInfo.VNCSmartSizeMode = (ProtocolVNC.SmartSizeMode)Enum.Parse(typeof(ProtocolVNC.SmartSizeMode), (string)dataRow["VNCSmartSizeMode"]);
connectionInfo.VNCViewOnly = (bool)dataRow["VNCViewOnly"];
@@ -121,7 +134,7 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.RDGatewayHostname = (string)dataRow["RDGatewayHostname"];
connectionInfo.RDGatewayUseConnectionCredentials = (RdpProtocol.RDGatewayUseConnectionCredentials)Enum.Parse(typeof(RdpProtocol.RDGatewayUseConnectionCredentials), (string)dataRow["RDGatewayUseConnectionCredentials"]);
connectionInfo.RDGatewayUsername = (string)dataRow["RDGatewayUsername"];
connectionInfo.RDGatewayPassword = (string)dataRow["RDGatewayPassword"];
connectionInfo.RDGatewayPassword = DecryptValue((string)dataRow["RDGatewayPassword"]);
connectionInfo.RDGatewayDomain = (string)dataRow["RDGatewayDomain"];
connectionInfo.Inheritance.CacheBitmaps = (bool)dataRow["InheritCacheBitmaps"];
@@ -180,10 +193,26 @@ namespace mRemoteNG.Config.Serializers.MsSql
connectionInfo.Inheritance.RDGatewayDomain = (bool)dataRow["InheritRDGatewayDomain"];
}
private string DecryptValue(string cipherText)
{
try
{
return _cryptographyProvider.Decrypt(cipherText, _decryptionKey);
}
catch (EncryptionException)
{
// value may not be encrypted
return cipherText;
}
}
private ConnectionTreeModel CreateNodeHierarchy(List<ConnectionInfo> connectionList, DataTable dataTable)
{
var connectionTreeModel = new ConnectionTreeModel();
var rootNode = new RootNodeInfo(RootNodeType.Connection, "0");
var rootNode = new RootNodeInfo(RootNodeType.Connection, "0")
{
PasswordString = _decryptionKey.ConvertToUnsecureString()
};
connectionTreeModel.AddRootNode(rootNode);
foreach (DataRow row in dataTable.Rows)

View File

@@ -7,19 +7,25 @@ using System;
using System.Data;
using System.Data.SqlTypes;
using System.Linq;
using System.Security;
using mRemoteNG.Tools;
namespace mRemoteNG.Config.Serializers.MsSql
{
public class DataTableSerializer : ISerializer<ConnectionInfo,DataTable>
{
private readonly ICryptographyProvider _cryptographyProvider;
private readonly SecureString _encryptionKey;
private DataTable _dataTable;
private const string TableName = "tblCons";
private readonly SaveFilter _saveFilter;
private int _currentNodeIndex;
public DataTableSerializer(SaveFilter saveFilter)
public DataTableSerializer(SaveFilter saveFilter, ICryptographyProvider cryptographyProvider, SecureString encryptionKey)
{
_saveFilter = saveFilter;
_saveFilter = saveFilter.ThrowIfNull(nameof(saveFilter));
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
_encryptionKey = encryptionKey.ThrowIfNull(nameof(encryptionKey));
}
@@ -210,7 +216,9 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataRow["Panel"] = connectionInfo.Panel;
dataRow["Username"] = _saveFilter.SaveUsername ? connectionInfo.Username : "";
dataRow["DomainName"] = _saveFilter.SaveDomain ? connectionInfo.Domain : "";
dataRow["Password"] = _saveFilter.SavePassword ? connectionInfo.Password : "";
dataRow["Password"] = _saveFilter.SavePassword
? _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey)
: "";
dataRow["Hostname"] = connectionInfo.Hostname;
dataRow["Protocol"] = connectionInfo.Protocol;
dataRow["PuttySession"] = connectionInfo.PuttySession;
@@ -251,14 +259,14 @@ namespace mRemoteNG.Config.Serializers.MsSql
dataRow["VNCProxyIP"] = connectionInfo.VNCProxyIP;
dataRow["VNCProxyPort"] = connectionInfo.VNCProxyPort;
dataRow["VNCProxyUsername"] = connectionInfo.VNCProxyUsername;
dataRow["VNCProxyPassword"] = connectionInfo.VNCProxyPassword;
dataRow["VNCProxyPassword"] = _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey);
dataRow["VNCColors"] = connectionInfo.VNCColors;
dataRow["VNCSmartSizeMode"] = connectionInfo.VNCSmartSizeMode;
dataRow["VNCViewOnly"] = connectionInfo.VNCViewOnly;
dataRow["RDGatewayUsageMethod"] = connectionInfo.RDGatewayUsageMethod;
dataRow["RDGatewayHostname"] = connectionInfo.RDGatewayHostname;
dataRow["RDGatewayUseConnectionCredentials"] = connectionInfo.RDGatewayUseConnectionCredentials;
dataRow["RDGatewayUsername"] = connectionInfo.RDGatewayUsername;
dataRow["RDGatewayUsername"] = _cryptographyProvider.Encrypt(connectionInfo.RDGatewayUsername, _encryptionKey);
dataRow["RDGatewayPassword"] = connectionInfo.RDGatewayPassword;
dataRow["RDGatewayDomain"] = connectionInfo.RDGatewayDomain;
if (_saveFilter.SaveInheritance)

View File

@@ -1,4 +1,5 @@
using System;
using System.Security;
namespace mRemoteNG.Config.Serializers.MsSql
{

View File

@@ -44,7 +44,8 @@ namespace mRemoteNG.Connection
throw new ArgumentNullException(nameof(puttySessionsManager));
_puttySessionsManager = puttySessionsManager;
_localConnectionPropertiesDataProvider = new FileDataProvider(Path.Combine(SettingsFileInfo.SettingsPath, "LocalConnectionProperties.xml"));
var path = SettingsFileInfo.SettingsPath;
_localConnectionPropertiesDataProvider = new FileDataProvider(Path.Combine(path, "LocalConnectionProperties.xml"));
_localConnectionPropertiesSerializer = new LocalConnectionPropertiesXmlSerializer();
}

View File

@@ -180,7 +180,7 @@
<Compile Include="Config\Serializers\MiscSerializers\RemoteDesktopConnectionDeserializer.cs" />
<Compile Include="Config\Serializers\MiscSerializers\RemoteDesktopConnectionManagerDeserializer.cs" />
<Compile Include="Config\Serializers\ConnectionSerializers\Xml\XmlConnectionNodeSerializer26.cs" />
<Compile Include="Config\Serializers\Versioning\SqlDatabaseMetaDataRetriever.cs" />
<Compile Include="Config\Serializers\ConnectionSerializers\MsSql\SqlDatabaseMetaDataRetriever.cs" />
<Compile Include="Config\Serializers\Versioning\IVersionUpgrader.cs" />
<Compile Include="Config\Serializers\Versioning\SqlVersion22To23Upgrader.cs" />
<Compile Include="Config\Serializers\Versioning\SqlVersion23To24Upgrader.cs" />