added an Auth attribute to the xml cred file to get around an issue when the file contains no passwords

This commit is contained in:
David Sparer
2017-02-14 13:21:54 -07:00
parent cca2052b15
commit 5527ebf085
7 changed files with 79 additions and 23 deletions

View File

@@ -0,0 +1,23 @@
using mRemoteNG.Security;
using NUnit.Framework;
namespace mRemoteNGTests.Security
{
public class RandomGeneratorTests
{
[Test]
public void ProducesStringOfCorrectLength()
{
var text = RandomGenerator.RandomString(8);
Assert.That(text.Length, Is.EqualTo(8));
}
[Test]
public void StringsDiffer()
{
var text1 = RandomGenerator.RandomString(8);
var text2 = RandomGenerator.RandomString(8);
Assert.That(text1, Is.Not.EqualTo(text2));
}
}
}

View File

@@ -145,6 +145,7 @@
<Compile Include="Security\PasswordCreation\PasswordIncludesLowerCaseConstraintTests.cs" />
<Compile Include="Security\PasswordCreation\PasswordIncludesNumbersConstraintTests.cs" />
<Compile Include="Security\PasswordCreation\PasswordLengthConstraintTests.cs" />
<Compile Include="Security\RandomGeneratorTests.cs" />
<Compile Include="Security\SecureStringExtensionsTests.cs" />
<Compile Include="Security\XmlCryptoProviderBuilderTests.cs" />
<Compile Include="Tools\ExternalToolsArgumentParserTests.cs" />

View File

@@ -5,6 +5,7 @@ using System.Security;
using System.Xml.Linq;
using mRemoteNG.Credential;
using mRemoteNG.Security;
using mRemoteNG.Security.Authentication;
namespace mRemoteNG.Config.Serializers
@@ -12,39 +13,42 @@ namespace mRemoteNG.Config.Serializers
public class XmlCredentialDeserializer
{
public string SchemaVersion { get; } = "1.0";
public IAuthenticator Authenticator { get; set; }
public IEnumerable<ICredentialRecord> Deserialize(string xml, SecureString decryptionKey)
{
try
{
var xdoc = XDocument.Parse(xml);
ValidateSchemaVersion(xdoc);
var cryptographyProvider = BuildCryptoProvider(xdoc.Root);
var credentials = from element in xdoc.Descendants("Credential")
select new CredentialRecord(Guid.Parse(element.Attribute("Id")?.Value))
{
Title = element.Attribute("Title")?.Value ?? "",
Username = element.Attribute("Username")?.Value ?? "",
Password =
cryptographyProvider.Decrypt(element.Attribute("Password")?.Value, decryptionKey)
.ConvertToSecureString(),
Domain = element.Attribute("Domain")?.Value ?? ""
};
return credentials;
}
catch
{
return new ICredentialRecord[0];
}
var xdoc = XDocument.Parse(xml);
var rootElement = xdoc.Root;
ValidateSchemaVersion(rootElement);
var cryptographyProvider = BuildCryptoProvider(rootElement);
Authenticate(rootElement, cryptographyProvider, decryptionKey);
var credentials = from element in xdoc.Descendants("Credential")
select new CredentialRecord(Guid.Parse(element.Attribute("Id")?.Value))
{
Title = element.Attribute("Title")?.Value ?? "",
Username = element.Attribute("Username")?.Value ?? "",
Password =
cryptographyProvider.Decrypt(element.Attribute("Password")?.Value, decryptionKey)
.ConvertToSecureString(),
Domain = element.Attribute("Domain")?.Value ?? ""
};
return credentials.ToArray();
}
private void ValidateSchemaVersion(XDocument xdoc)
private void ValidateSchemaVersion(XElement rootElement)
{
var docSchemaVersion = xdoc.Root?.Attribute("SchemaVersion")?.Value;
var docSchemaVersion = rootElement?.Attribute("SchemaVersion")?.Value;
if (docSchemaVersion != SchemaVersion)
throw new Exception($"The schema version of this document is not supported by this class. Document Version: {docSchemaVersion} Supported Version: {SchemaVersion}");
}
private void Authenticate(XElement rootElement, ICryptographyProvider cryptographyProvider, SecureString key)
{
var authString = rootElement.Attribute("Auth")?.Value;
cryptographyProvider.Decrypt(authString, key);
}
private ICryptographyProvider BuildCryptoProvider(XElement rootElement)
{
if (rootElement == null)

View File

@@ -29,6 +29,7 @@ namespace mRemoteNG.Config.Serializers
new XAttribute("EncryptionEngine", _cryptographyProvider.CipherEngine),
new XAttribute("BlockCipherMode", _cryptographyProvider.CipherMode),
new XAttribute("KdfIterations", _cryptographyProvider.KeyDerivationIterations),
new XAttribute("Auth", _cryptographyProvider.Encrypt(RandomGenerator.RandomString(30), encryptionKey)),
new XAttribute("SchemaVersion", SchemaVersion),
from r in credentialRecords
select new XElement("Credential",

View File

@@ -17,6 +17,7 @@
<xs:attribute name="BlockCipherMode" type="xs:string" use="required" />
<xs:attribute name="KdfIterations" type="xs:int" use="optional" />
<xs:attribute name="FullFileEncryption" type="xs:boolean" use="required" />
<xs:attribute name="Auth" type="xs:string" use="required" />
<xs:attribute name="SchemaVersion" type="xs:float" use="required" />
</xs:complexType>
</xs:element>

View File

@@ -0,0 +1,25 @@
using System;
using System.Text;
using Org.BouncyCastle.Security;
namespace mRemoteNG.Security
{
public class RandomGenerator
{
public static string RandomString(int length)
{
if (length < 0)
throw new ArgumentException($"{nameof(length)} must be a positive integer");
var randomGen = new SecureRandom();
var stringBuilder = new StringBuilder();
const string availableChars = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#$%^&*()-_=+|[]{};:',./<>?";
for (var x = 0; x < length; x++)
{
var randomIndex = randomGen.Next(availableChars.Length - 1);
stringBuilder.Append(availableChars[randomIndex]);
}
return stringBuilder.ToString();
}
}
}

View File

@@ -213,6 +213,7 @@
<Compile Include="Credential\CredentialDeletionMsgBoxConfirmer.cs" />
<Compile Include="Credential\CredentialDomainUserComparer.cs" />
<Compile Include="Security\Authentication\IPasswordRequestor.cs" />
<Compile Include="Security\RandomGenerator.cs" />
<Compile Include="Tools\CustomCollections\IFullyNotifiableList.cs" />
<Compile Include="Tools\CustomCollections\FullyObservableCollection.cs" />
<Compile Include="Credential\CredentialRepositoryChangedArgs.cs" />