mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
credential deserializer now supports variable decryption parameters
This commit is contained in:
@@ -18,14 +18,14 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void Setup()
|
||||
{
|
||||
_cryptographyProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_deserializer = new XmlCredentialDeserializer(_cryptographyProvider);
|
||||
_deserializer = new XmlCredentialDeserializer();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasCorrectId()
|
||||
{
|
||||
var id = Guid.NewGuid();
|
||||
var xml = $"<Credentials>\r\n <Credential Id=\"{id}\" Name=\"testcred\" Username=\"myuser\" Password=\"{GeneratePass("abc")}\" />\r\n</Credentials>";
|
||||
var xml = $"<Credentials EncryptionEngine=\"AES\" BlockCipherMode=\"GCM\" KdfIterations=\"1000\" SchemaVersion=\"1.0\">\r\n <Credential Id=\"{id}\" Name=\"testcred\" Username=\"myuser\" Password=\"{GeneratePass("abc")}\" />\r\n</Credentials>";
|
||||
var creds = _deserializer.Deserialize(xml, _key);
|
||||
Assert.That(creds.First().Id, Is.EqualTo(id));
|
||||
}
|
||||
@@ -34,7 +34,7 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void HasCorrectTitle()
|
||||
{
|
||||
const string title = "testtitle";
|
||||
var xml = $"<Credentials>\r\n <Credential Id=\"256f4c8c-5819-4226-ad55-6f1f341b5449\" Name=\"{title}\" Username=\"myuser\" Password=\"{GeneratePass("abc")}\" />\r\n</Credentials>";
|
||||
var xml = $"<Credentials EncryptionEngine=\"AES\" BlockCipherMode=\"GCM\" KdfIterations=\"1000\" SchemaVersion=\"1.0\">\r\n <Credential Id=\"256f4c8c-5819-4226-ad55-6f1f341b5449\" Name=\"{title}\" Username=\"myuser\" Password=\"{GeneratePass("abc")}\" />\r\n</Credentials>";
|
||||
var creds = _deserializer.Deserialize(xml, _key);
|
||||
Assert.That(creds.First().Name, Is.EqualTo(title));
|
||||
}
|
||||
@@ -43,7 +43,7 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void HasCorrectUsername()
|
||||
{
|
||||
const string username = "myuser";
|
||||
var xml = $"<Credentials>\r\n <Credential Id=\"256f4c8c-5819-4226-ad55-6f1f341b5449\" Name=\"testtitle\" Username=\"{username}\" Password=\"{GeneratePass("abc")}\" />\r\n</Credentials>";
|
||||
var xml = $"<Credentials EncryptionEngine=\"AES\" BlockCipherMode=\"GCM\" KdfIterations=\"1000\" SchemaVersion=\"1.0\">\r\n <Credential Id=\"256f4c8c-5819-4226-ad55-6f1f341b5449\" Name=\"testtitle\" Username=\"{username}\" Password=\"{GeneratePass("abc")}\" />\r\n</Credentials>";
|
||||
var creds = _deserializer.Deserialize(xml, _key);
|
||||
Assert.That(creds.First().Username, Is.EqualTo(username));
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void HasCorrectPassword()
|
||||
{
|
||||
const string plaintextPassword = "mypassword";
|
||||
var xml = $"<Credentials>\r\n <Credential Id=\"256f4c8c-5819-4226-ad55-6f1f341b5449\" Name=\"testtitle\" Username=\"myuser\" Password=\"{GeneratePass(plaintextPassword)}\" />\r\n</Credentials>";
|
||||
var xml = $"<Credentials EncryptionEngine=\"AES\" BlockCipherMode=\"GCM\" KdfIterations=\"1000\" SchemaVersion=\"1.0\">\r\n <Credential Id=\"256f4c8c-5819-4226-ad55-6f1f341b5449\" Name=\"testtitle\" Username=\"myuser\" Password=\"{GeneratePass(plaintextPassword)}\" />\r\n</Credentials>";
|
||||
var creds = _deserializer.Deserialize(xml, _key);
|
||||
Assert.That(creds.First().Password.ConvertToUnsecureString(), Is.EqualTo(plaintextPassword));
|
||||
}
|
||||
@@ -60,11 +60,24 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
[Test]
|
||||
public void DeserializesAllCredentials()
|
||||
{
|
||||
var xml = $"<Credentials>\r\n <Credential Id=\"256f4c8c-5819-4226-ad55-6f1f341b5449\" Name=\"testtitle\" Username=\"myuser\" Password=\"{GeneratePass("abc")}\" />\r\n <Credential Id=\"356f4c8c-5819-4226-ad55-6f1f341b5449\" Name=\"othertitle\" Username=\"someuser\" Password=\"{GeneratePass("abc")}\" />\r\n</Credentials>";
|
||||
var xml = $"<Credentials EncryptionEngine=\"AES\" BlockCipherMode=\"GCM\" KdfIterations=\"1000\" SchemaVersion=\"1.0\">\r\n <Credential Id=\"256f4c8c-5819-4226-ad55-6f1f341b5449\" Name=\"testtitle\" Username=\"myuser\" Password=\"{GeneratePass("abc")}\" />\r\n <Credential Id=\"356f4c8c-5819-4226-ad55-6f1f341b5449\" Name=\"othertitle\" Username=\"someuser\" Password=\"{GeneratePass("abc")}\" />\r\n</Credentials>";
|
||||
var creds = _deserializer.Deserialize(xml, _key);
|
||||
Assert.That(creds.Count(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanDecryptNonStandardEncryptions()
|
||||
{
|
||||
var otherCryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.Serpent, BlockCipherModes.CCM);
|
||||
otherCryptoProvider.KeyDerivationIterations = 2000;
|
||||
const string plaintextPassword = "mypassword";
|
||||
var encryptedPassword = otherCryptoProvider.Encrypt(plaintextPassword, _key);
|
||||
var xml =
|
||||
$"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Credentials EncryptionEngine=\"Serpent\" BlockCipherMode=\"CCM\" KdfIterations=\"2000\" SchemaVersion=\"1.0\">\r\n <Credential Id=\"faadd345-6c68-4891-9897-d22525ec7c58\" Name=\"testcred\" Username=\"davids\" Password=\"{encryptedPassword}\" />\r\n</Credentials>";
|
||||
var creds = _deserializer.Deserialize(xml, _key);
|
||||
Assert.That(creds.First().Password.ConvertToUnsecureString(), Is.EqualTo(plaintextPassword));
|
||||
}
|
||||
|
||||
private string GeneratePass(string plaintext)
|
||||
{
|
||||
return _cryptographyProvider.Encrypt(plaintext, _key);
|
||||
|
||||
@@ -11,27 +11,49 @@ namespace mRemoteNG.Config.Serializers
|
||||
{
|
||||
public class XmlCredentialDeserializer
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
|
||||
public XmlCredentialDeserializer(ICryptographyProvider cryptographyProvider)
|
||||
{
|
||||
if (cryptographyProvider == null)
|
||||
throw new ArgumentNullException(nameof(cryptographyProvider));
|
||||
_cryptographyProvider = cryptographyProvider;
|
||||
}
|
||||
public string SchemaVersion { get; } = "1.0";
|
||||
|
||||
public IEnumerable<ICredentialRecord> Deserialize(string xml, SecureString decryptionKey)
|
||||
{
|
||||
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))
|
||||
{
|
||||
Name = element.Attribute("Name")?.Value,
|
||||
Username = element.Attribute("Username")?.Value,
|
||||
Password = _cryptographyProvider.Decrypt(element.Attribute("Password")?.Value, decryptionKey).ConvertToSecureString(),
|
||||
Password = cryptographyProvider.Decrypt(element.Attribute("Password")?.Value, decryptionKey).ConvertToSecureString(),
|
||||
Domain = element.Attribute("Domain")?.Value
|
||||
};
|
||||
return credentials;
|
||||
}
|
||||
|
||||
private void ValidateSchemaVersion(XDocument xdoc)
|
||||
{
|
||||
var docSchemaVersion = xdoc.Root?.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 ICryptographyProvider BuildCryptoProvider(XElement rootElement)
|
||||
{
|
||||
if (rootElement == null)
|
||||
throw new ArgumentNullException(nameof(rootElement));
|
||||
|
||||
BlockCipherEngines engine;
|
||||
Enum.TryParse(rootElement.Attribute("EncryptionEngine")?.Value, true, out engine);
|
||||
|
||||
BlockCipherModes mode;
|
||||
Enum.TryParse(rootElement.Attribute("BlockCipherMode")?.Value, true, out mode);
|
||||
|
||||
int kdfIterations;
|
||||
int.TryParse(rootElement.Attribute("KdfIterations")?.Value, out kdfIterations);
|
||||
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(engine, mode);
|
||||
cryptoProvider.KeyDerivationIterations = kdfIterations;
|
||||
|
||||
return cryptoProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user