SEBWIN-296: Decoupled cryptographic implementations from data formats to be able to unit test the latter.

This commit is contained in:
dbuechel 2019-02-19 15:54:11 +01:00
parent f817f31f2d
commit cf7d6c4d3e
20 changed files with 392 additions and 81 deletions

View file

@ -21,13 +21,13 @@ using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Configuration.UnitTests.Cryptography
{
[TestClass]
public class PublicKeyHashEncryptionTests
public class PublicKeyEncryptionTests
{
private Mock<ILogger> logger;
private Mock<ICertificateStore> store;
private X509Certificate2 certificate;
private PublicKeyHashEncryption sut;
private PublicKeyEncryption sut;
[TestInitialize]
public void Initialize()
@ -38,7 +38,7 @@ namespace SafeExamBrowser.Configuration.UnitTests.Cryptography
LoadCertificate();
store.Setup(s => s.TryGetCertificateWith(It.IsAny<byte[]>(), out certificate)).Returns(true);
sut = new PublicKeyHashEncryption(store.Object, logger.Object);
sut = new PublicKeyEncryption(store.Object, logger.Object);
}
[TestMethod]

View file

@ -21,13 +21,13 @@ using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Configuration.UnitTests.Cryptography
{
[TestClass]
public class PublicKeyHashWithSymmetricKeyEncryptionTests
public class PublicKeySymmetricEncryptionTests
{
private Mock<ILogger> logger;
private PasswordEncryption passwordEncryption;
private Mock<ICertificateStore> store;
private PublicKeyHashWithSymmetricKeyEncryption sut;
private PublicKeySymmetricEncryption sut;
private X509Certificate2 certificate;
[TestInitialize]
@ -40,7 +40,7 @@ namespace SafeExamBrowser.Configuration.UnitTests.Cryptography
LoadCertificate();
store.Setup(s => s.TryGetCertificateWith(It.IsAny<byte[]>(), out certificate)).Returns(true);
sut = new PublicKeyHashWithSymmetricKeyEncryption(store.Object, logger.Object, passwordEncryption);
sut = new PublicKeySymmetricEncryption(store.Object, logger.Object, passwordEncryption);
}
[TestMethod]

View file

@ -0,0 +1,168 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SafeExamBrowser.Configuration.DataFormats;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Cryptography;
using SafeExamBrowser.Contracts.Configuration.DataCompression;
using SafeExamBrowser.Contracts.Configuration.DataFormats;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Configuration.UnitTests.DataFormats
{
[TestClass]
public class BinaryParserTests
{
private Mock<IDataCompressor> compressor;
private Mock<IHashAlgorithm> hashAlgorithm;
private Mock<ILogger> logger;
private Mock<IPasswordEncryption> passwordEncryption;
private Mock<IPublicKeyEncryption> publicKeyEncryption;
private Mock<IPublicKeyEncryption> symmetricEncryption;
private Mock<IDataParser> xmlParser;
private BinaryParser sut;
[TestInitialize]
public void Initialize()
{
compressor = new Mock<IDataCompressor>();
hashAlgorithm = new Mock<IHashAlgorithm>();
logger = new Mock<ILogger>();
passwordEncryption = new Mock<IPasswordEncryption>();
publicKeyEncryption = new Mock<IPublicKeyEncryption>();
symmetricEncryption = new Mock<IPublicKeyEncryption>();
xmlParser = new Mock<IDataParser>();
xmlParser.Setup(p => p.TryParse(It.IsAny<Stream>(), It.IsAny<PasswordParameters>())).Returns(new ParseResult { Status = LoadStatus.Success });
sut = new BinaryParser(compressor.Object, hashAlgorithm.Object, logger.Object, passwordEncryption.Object, publicKeyEncryption.Object, symmetricEncryption.Object, xmlParser.Object);
}
[TestMethod]
public void MustCorrectlyDetectValidPrefixes()
{
var data = new byte[123];
var pswd = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.Password).Concat(data).ToArray());
var pwcc = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.PasswordConfigureClient).Concat(data).ToArray());
var plnd = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.PlainData).Concat(data).ToArray());
var pkhs = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.PublicKey).Concat(data).ToArray());
var phsk = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.PublicKeySymmetric).Concat(data).ToArray());
Assert.IsFalse(sut.CanParse(null));
Assert.IsFalse(sut.CanParse(new MemoryStream()));
Assert.IsFalse(sut.CanParse(new MemoryStream(data)));
Assert.IsTrue(sut.CanParse(pswd));
Assert.IsTrue(sut.CanParse(pwcc));
Assert.IsTrue(sut.CanParse(plnd));
Assert.IsTrue(sut.CanParse(pkhs));
Assert.IsTrue(sut.CanParse(phsk));
}
[TestMethod]
public void MustCorrectlyParsePasswordBlock()
{
var data = new byte[123];
var decrypted = default(Stream);
var pswd = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.Password).Concat(data).ToArray()) as Stream;
passwordEncryption.Setup(p => p.Decrypt(It.IsAny<Stream>(), It.Is<string>(s => s == "wrong"), out decrypted)).Returns(LoadStatus.PasswordNeeded);
passwordEncryption.Setup(p => p.Decrypt(It.IsAny<Stream>(), It.Is<string>(s => s == "correct"), out decrypted)).Returns(LoadStatus.Success);
var result = sut.TryParse(pswd);
Assert.AreEqual(LoadStatus.PasswordNeeded, result.Status);
result = sut.TryParse(pswd, new PasswordParameters { Password = "wrong" });
Assert.AreEqual(LoadStatus.PasswordNeeded, result.Status);
result = sut.TryParse(pswd, new PasswordParameters { Password = "correct" });
passwordEncryption.Verify(p => p.Decrypt(It.IsAny<Stream>(), It.IsAny<string>(), out decrypted), Times.AtLeastOnce);
xmlParser.Verify(p => p.TryParse(It.Is<Stream>(s => s == decrypted), It.IsAny<PasswordParameters>()), Times.Once);
publicKeyEncryption.VerifyNoOtherCalls();
symmetricEncryption.VerifyNoOtherCalls();
}
[TestMethod]
public void MustCorrectlyParsePlainDataBlock()
{
var data = new byte[123];
var plnd = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.PlainData).Concat(data).ToArray());
compressor.Setup(c => c.Decompress(It.IsAny<Stream>())).Returns(plnd);
compressor.Setup(c => c.Peek(It.IsAny<Stream>(), It.IsAny<int>())).Returns(Encoding.UTF8.GetBytes(BinaryBlock.PlainData));
compressor.Setup(c => c.IsCompressed(It.IsAny<Stream>())).Returns(true);
var result = sut.TryParse(plnd);
compressor.Verify(c => c.IsCompressed(It.IsAny<Stream>()), Times.AtLeastOnce);
compressor.Verify(c => c.Decompress(It.IsAny<Stream>()), Times.AtLeastOnce);
xmlParser.Verify(x => x.TryParse(It.IsAny<Stream>(), It.IsAny<PasswordParameters>()), Times.Once);
passwordEncryption.VerifyNoOtherCalls();
publicKeyEncryption.VerifyNoOtherCalls();
symmetricEncryption.VerifyNoOtherCalls();
Assert.AreEqual(LoadStatus.Success, result.Status);
}
[TestMethod]
public void MustCorrectlyParsePublicKeyBlock()
{
var data = new byte[123];
var certificate = default(X509Certificate2);
var decrypted = default(Stream);
var pswd = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.Password).Concat(data).ToArray()) as Stream;
var pkhs = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.PublicKey).Concat(data).ToArray());
passwordEncryption.Setup(p => p.Decrypt(It.IsAny<Stream>(), It.IsAny<string>(), out decrypted)).Returns(LoadStatus.Success);
publicKeyEncryption.Setup(p => p.Decrypt(It.IsAny<Stream>(), out pswd, out certificate)).Returns(LoadStatus.Success);
var result = sut.TryParse(pkhs, new PasswordParameters { Password = "blubb" });
publicKeyEncryption.Verify(p => p.Decrypt(It.IsAny<Stream>(), out decrypted, out certificate), Times.Once);
passwordEncryption.Verify(p => p.Decrypt(It.IsAny<Stream>(), It.Is<string>(s => s == "blubb"), out decrypted), Times.Once);
symmetricEncryption.VerifyNoOtherCalls();
Assert.AreEqual(LoadStatus.Success, result.Status);
}
[TestMethod]
public void MustOnlyParseIfFormatSupported()
{
var data = new byte[123];
var certificate = default(X509Certificate2);
var decrypted = default(Stream);
var pswd = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.Password).Concat(data).ToArray()) as Stream;
var pwcc = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.PasswordConfigureClient).Concat(data).ToArray());
var plnd = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.PlainData).Concat(data).ToArray());
var pkhs = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.PublicKey).Concat(data).ToArray());
var phsk = new MemoryStream(Encoding.UTF8.GetBytes(BinaryBlock.PublicKeySymmetric).Concat(data).ToArray());
passwordEncryption.Setup(p => p.Decrypt(It.IsAny<Stream>(), It.IsAny<string>(), out decrypted)).Returns(LoadStatus.Success);
publicKeyEncryption.Setup(p => p.Decrypt(It.IsAny<Stream>(), out pswd, out certificate)).Returns(LoadStatus.Success);
symmetricEncryption.Setup(p => p.Decrypt(It.IsAny<Stream>(), out pswd, out certificate)).Returns(LoadStatus.Success);
Assert.AreEqual(LoadStatus.InvalidData, sut.TryParse(new MemoryStream(data)).Status);
Assert.AreEqual(LoadStatus.Success, sut.TryParse(pswd, new PasswordParameters { Password = "blubb" })?.Status);
Assert.AreEqual(LoadStatus.Success, sut.TryParse(pwcc, new PasswordParameters { Password = "blubb" })?.Status);
Assert.AreEqual(LoadStatus.Success, sut.TryParse(plnd).Status);
Assert.AreEqual(LoadStatus.Success, sut.TryParse(pkhs, new PasswordParameters { Password = "blubb" }).Status);
Assert.AreEqual(LoadStatus.Success, sut.TryParse(phsk, new PasswordParameters { Password = "blubb" }).Status);
}
}
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace SafeExamBrowser.Configuration.UnitTests.DataFormats
{
[TestClass]
public class BinarySerializerTests
{
[TestInitialize]
public void Initialize()
{
}
}
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace SafeExamBrowser.Configuration.UnitTests.DataFormats
{
[TestClass]
public class XmlParserTests
{
[TestInitialize]
public void Initialize()
{
}
}
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace SafeExamBrowser.Configuration.UnitTests.DataFormats
{
[TestClass]
public class XmlSerializerTests
{
[TestInitialize]
public void Initialize()
{
}
}
}

View file

@ -86,9 +86,13 @@
<Compile Include="ConfigurationRepositoryTests.cs" />
<Compile Include="Cryptography\HashAlgorithmTests.cs" />
<Compile Include="Cryptography\PasswordEncryptionTests.cs" />
<Compile Include="Cryptography\PublicKeyHashEncryptionTests.cs" />
<Compile Include="Cryptography\PublicKeyHashWithSymmetricKeyEncryptionTests.cs" />
<Compile Include="Cryptography\PublicKeyEncryptionTests.cs" />
<Compile Include="Cryptography\PublicKeySymmetricEncryptionTests.cs" />
<Compile Include="DataCompression\GZipCompressorTests.cs" />
<Compile Include="DataFormats\BinaryParserTests.cs" />
<Compile Include="DataFormats\BinarySerializerTests.cs" />
<Compile Include="DataFormats\XmlParserTests.cs" />
<Compile Include="DataFormats\XmlSerializerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View file

@ -13,7 +13,7 @@ using SafeExamBrowser.Contracts.Configuration.Cryptography;
namespace SafeExamBrowser.Configuration.Cryptography
{
internal class CertificateStore : ICertificateStore
public class CertificateStore : ICertificateStore
{
private readonly X509Store[] stores = new[]
{

View file

@ -10,11 +10,12 @@ using System.IO;
using System.Linq;
using System.Security.Cryptography;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Cryptography;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Configuration.Cryptography
{
internal class PasswordEncryption
public class PasswordEncryption : IPasswordEncryption
{
private const int BLOCK_SIZE = 16;
private const int HEADER_SIZE = 2;
@ -26,14 +27,14 @@ namespace SafeExamBrowser.Configuration.Cryptography
private ILogger logger;
internal PasswordEncryption(ILogger logger)
public PasswordEncryption(ILogger logger)
{
this.logger = logger;
}
internal LoadStatus Decrypt(Stream data, string password, out Stream decryptedData)
public LoadStatus Decrypt(Stream data, string password, out Stream decrypted)
{
decryptedData = default(Stream);
decrypted = default(Stream);
if (password == null)
{
@ -49,17 +50,17 @@ namespace SafeExamBrowser.Configuration.Cryptography
return FailForInvalidHmac();
}
decryptedData = Decrypt(data, encryptionKey, originalHmac.Length);
decrypted = Decrypt(data, encryptionKey, originalHmac.Length);
return LoadStatus.Success;
}
internal SaveStatus Encrypt(Stream data, string password, out Stream encryptedData)
public SaveStatus Encrypt(Stream data, string password, out Stream encrypted)
{
var (authKey, authSalt, encrKey, encrSalt) = GenerateKeysForEncryption(password);
encryptedData = Encrypt(data, encrKey, out var initVector);
encryptedData = WriteEncryptionParameters(authKey, authSalt, encrSalt, initVector, encryptedData);
encrypted = Encrypt(data, encrKey, out var initVector);
encrypted = WriteEncryptionParameters(authKey, authSalt, encrSalt, initVector, encrypted);
return SaveStatus.Success;
}

View file

@ -15,20 +15,20 @@ using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Configuration.Cryptography
{
internal class PublicKeyHashEncryption
public class PublicKeyEncryption : IPublicKeyEncryption
{
protected const int PUBLIC_KEY_HASH_SIZE = 20;
protected ICertificateStore store;
protected ILogger logger;
internal PublicKeyHashEncryption(ICertificateStore store, ILogger logger)
public PublicKeyEncryption(ICertificateStore store, ILogger logger)
{
this.logger = logger;
this.store = store;
}
internal virtual LoadStatus Decrypt(Stream data, out Stream decryptedData, out X509Certificate2 certificate)
public virtual LoadStatus Decrypt(Stream data, out Stream decryptedData, out X509Certificate2 certificate)
{
var publicKeyHash = ParsePublicKeyHash(data);
var found = store.TryGetCertificateWith(publicKeyHash, out certificate);
@ -45,7 +45,7 @@ namespace SafeExamBrowser.Configuration.Cryptography
return LoadStatus.Success;
}
internal virtual SaveStatus Encrypt(Stream data, X509Certificate2 certificate, out Stream encryptedData)
public virtual SaveStatus Encrypt(Stream data, X509Certificate2 certificate, out Stream encryptedData)
{
var publicKeyHash = GeneratePublicKeyHash(certificate);

View file

@ -16,19 +16,19 @@ using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Configuration.Cryptography
{
internal class PublicKeyHashWithSymmetricKeyEncryption : PublicKeyHashEncryption
public class PublicKeySymmetricEncryption : PublicKeyEncryption
{
private const int ENCRYPTION_KEY_LENGTH = 32;
private const int KEY_LENGTH_SIZE = 4;
private PasswordEncryption passwordEncryption;
internal PublicKeyHashWithSymmetricKeyEncryption(ICertificateStore store, ILogger logger, PasswordEncryption passwordEncryption) : base(store, logger)
public PublicKeySymmetricEncryption(ICertificateStore store, ILogger logger, PasswordEncryption passwordEncryption) : base(store, logger)
{
this.passwordEncryption = passwordEncryption;
}
internal override LoadStatus Decrypt(Stream data, out Stream decryptedData, out X509Certificate2 certificate)
public override LoadStatus Decrypt(Stream data, out Stream decryptedData, out X509Certificate2 certificate)
{
var publicKeyHash = ParsePublicKeyHash(data);
var found = store.TryGetCertificateWith(publicKeyHash, out certificate);
@ -47,7 +47,7 @@ namespace SafeExamBrowser.Configuration.Cryptography
return status;
}
internal override SaveStatus Encrypt(Stream data, X509Certificate2 certificate, out Stream encryptedData)
public override SaveStatus Encrypt(Stream data, X509Certificate2 certificate, out Stream encryptedData)
{
var publicKeyHash = GeneratePublicKeyHash(certificate);
var symmetricKey = GenerateSymmetricKey();

View file

@ -13,7 +13,7 @@ namespace SafeExamBrowser.Configuration.DataFormats
internal const string Password = "pswd";
internal const string PasswordConfigureClient = "pwcc";
internal const string PlainData = "plnd";
internal const string PublicKeyHash = "pkhs";
internal const string PublicKeyHashWithSymmetricKey = "phsk";
internal const string PublicKey = "pkhs";
internal const string PublicKeySymmetric = "phsk";
}
}

View file

@ -11,7 +11,6 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using SafeExamBrowser.Configuration.Cryptography;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Cryptography;
using SafeExamBrowser.Contracts.Configuration.DataCompression;
@ -26,13 +25,28 @@ namespace SafeExamBrowser.Configuration.DataFormats
private IDataCompressor compressor;
private IHashAlgorithm hashAlgorithm;
private IModuleLogger logger;
private ILogger logger;
private IPasswordEncryption passwordEncryption;
private IPublicKeyEncryption publicKeyEncryption;
private IPublicKeyEncryption publicKeySymmetricEncryption;
private readonly IDataParser xmlParser;
public BinaryParser(IDataCompressor compressor, IHashAlgorithm hashAlgorithm, IModuleLogger logger)
public BinaryParser(
IDataCompressor compressor,
IHashAlgorithm hashAlgorithm,
ILogger logger,
IPasswordEncryption passwordEncryption,
IPublicKeyEncryption publicKeyEncryption,
IPublicKeyEncryption publicKeySymmetricEncryption,
IDataParser xmlParser)
{
this.compressor = compressor;
this.hashAlgorithm = hashAlgorithm;
this.logger = logger;
this.passwordEncryption = passwordEncryption;
this.publicKeyEncryption = publicKeyEncryption;
this.publicKeySymmetricEncryption = publicKeySymmetricEncryption;
this.xmlParser = xmlParser;
}
public bool CanParse(Stream data)
@ -55,7 +69,7 @@ namespace SafeExamBrowser.Configuration.DataFormats
}
catch (Exception e)
{
logger.Error($"Failed to determine whether '{data}' with {data.Length / 1000.0} KB data matches the {FormatType.Binary} format!", e);
logger.Error($"Failed to determine whether '{data}' with {data?.Length / 1000.0} KB data matches the {FormatType.Binary} format!", e);
}
return false;
@ -78,9 +92,9 @@ namespace SafeExamBrowser.Configuration.DataFormats
return ParsePasswordBlock(data, prefix, password);
case BinaryBlock.PlainData:
return ParsePlainDataBlock(data);
case BinaryBlock.PublicKeyHash:
case BinaryBlock.PublicKeyHashWithSymmetricKey:
return ParsePublicKeyHashBlock(data, prefix, password);
case BinaryBlock.PublicKey:
case BinaryBlock.PublicKeySymmetric:
return ParsePublicKeyBlock(data, prefix, password);
}
}
@ -91,20 +105,19 @@ namespace SafeExamBrowser.Configuration.DataFormats
private ParseResult ParsePasswordBlock(Stream data, string prefix, PasswordParameters password = null)
{
var encryption = new PasswordEncryption(logger.CloneFor(nameof(PasswordEncryption)));
var result = new ParseResult();
if (password != null)
{
var encryptionParameters = DetermineEncryptionParametersFor(prefix, password);
var parameters = DetermineEncryptionParametersFor(prefix, password);
logger.Debug($"Attempting to parse password block with prefix '{prefix}'...");
result.Status = encryption.Decrypt(data, encryptionParameters.Password, out var decrypted);
result.Status = passwordEncryption.Decrypt(data, parameters.Password, out var decrypted);
if (result.Status == LoadStatus.Success)
{
result = ParsePlainDataBlock(decrypted);
result.Encryption = encryptionParameters;
result.Encryption = parameters;
}
}
else
@ -117,20 +130,18 @@ namespace SafeExamBrowser.Configuration.DataFormats
private ParseResult ParsePlainDataBlock(Stream data)
{
var xmlFormat = new XmlParser(logger.CloneFor(nameof(XmlParser)));
data = compressor.IsCompressed(data) ? compressor.Decompress(data) : data;
logger.Debug("Attempting to parse plain data block...");
var result = xmlFormat.TryParse(data);
var result = xmlParser.TryParse(data);
result.Format = FormatType.Binary;
return result;
}
private ParseResult ParsePublicKeyHashBlock(Stream data, string prefix, PasswordParameters password = null)
private ParseResult ParsePublicKeyBlock(Stream data, string prefix, PasswordParameters password = null)
{
var encryption = DetermineEncryptionForPublicKeyHashBlock(prefix);
var encryption = prefix == BinaryBlock.PublicKey ? publicKeyEncryption : publicKeySymmetricEncryption;
var result = new ParseResult();
logger.Debug($"Attempting to parse public key hash block with prefix '{prefix}'...");
@ -139,29 +150,17 @@ namespace SafeExamBrowser.Configuration.DataFormats
if (result.Status == LoadStatus.Success)
{
result = TryParse(decrypted, password);
result.Encryption = new PublicKeyHashParameters
result.Encryption = new PublicKeyParameters
{
Certificate = certificate,
InnerEncryption = result.Encryption as PasswordParameters,
SymmetricEncryption = prefix == BinaryBlock.PublicKeyHashWithSymmetricKey
SymmetricEncryption = prefix == BinaryBlock.PublicKeySymmetric
};
}
return result;
}
private PublicKeyHashEncryption DetermineEncryptionForPublicKeyHashBlock(string prefix)
{
var passwordEncryption = new PasswordEncryption(logger.CloneFor(nameof(PasswordEncryption)));
if (prefix == BinaryBlock.PublicKeyHash)
{
return new PublicKeyHashEncryption(new CertificateStore(), logger.CloneFor(nameof(PublicKeyHashEncryption)));
}
return new PublicKeyHashWithSymmetricKeyEncryption(new CertificateStore(), logger.CloneFor(nameof(PublicKeyHashWithSymmetricKeyEncryption)), passwordEncryption);
}
private PasswordParameters DetermineEncryptionParametersFor(string prefix, PasswordParameters password)
{
var parameters = new PasswordParameters();

View file

@ -43,7 +43,7 @@ namespace SafeExamBrowser.Configuration.DataFormats
case PasswordParameters p:
result = SerializePasswordBlock(data, p);
break;
case PublicKeyHashParameters p:
case PublicKeyParameters p:
result = SerializePublicKeyHashBlock(data, p);
break;
default:
@ -103,14 +103,14 @@ namespace SafeExamBrowser.Configuration.DataFormats
return result;
}
private SerializeResult SerializePublicKeyHashBlock(IDictionary<string, object> data, PublicKeyHashParameters parameters)
private SerializeResult SerializePublicKeyHashBlock(IDictionary<string, object> data, PublicKeyParameters parameters)
{
var result = SerializePublicKeyHashInnerBlock(data, parameters);
if (result.Status == SaveStatus.Success)
{
var encryption = DetermineEncryptionForPublicKeyHashBlock(parameters);
var prefix = parameters.SymmetricEncryption ? BinaryBlock.PublicKeyHashWithSymmetricKey : BinaryBlock.PublicKeyHash;
var prefix = parameters.SymmetricEncryption ? BinaryBlock.PublicKeySymmetric : BinaryBlock.PublicKey;
logger.Debug("Attempting to serialize public key hash block...");
@ -125,7 +125,7 @@ namespace SafeExamBrowser.Configuration.DataFormats
return result;
}
private SerializeResult SerializePublicKeyHashInnerBlock(IDictionary<string, object> data, PublicKeyHashParameters parameters)
private SerializeResult SerializePublicKeyHashInnerBlock(IDictionary<string, object> data, PublicKeyParameters parameters)
{
if (parameters.InnerEncryption is PasswordParameters password)
{
@ -135,16 +135,16 @@ namespace SafeExamBrowser.Configuration.DataFormats
return SerializePlainDataBlock(data, true);
}
private PublicKeyHashEncryption DetermineEncryptionForPublicKeyHashBlock(PublicKeyHashParameters parameters)
private PublicKeyEncryption DetermineEncryptionForPublicKeyHashBlock(PublicKeyParameters parameters)
{
var passwordEncryption = new PasswordEncryption(logger.CloneFor(nameof(PasswordEncryption)));
if (parameters.SymmetricEncryption)
{
return new PublicKeyHashWithSymmetricKeyEncryption(new CertificateStore(), logger.CloneFor(nameof(PublicKeyHashWithSymmetricKeyEncryption)), passwordEncryption);
return new PublicKeySymmetricEncryption(new CertificateStore(), logger.CloneFor(nameof(PublicKeySymmetricEncryption)), passwordEncryption);
}
return new PublicKeyHashEncryption(new CertificateStore(), logger.CloneFor(nameof(PublicKeyHashEncryption)));
return new PublicKeyEncryption(new CertificateStore(), logger.CloneFor(nameof(PublicKeyEncryption)));
}
private Stream WritePrefix(string prefix, Stream data)

View file

@ -64,8 +64,8 @@
<Compile Include="Cryptography\CertificateStore.cs" />
<Compile Include="DataCompression\GZipCompressor.cs" />
<Compile Include="Cryptography\PasswordEncryption.cs" />
<Compile Include="Cryptography\PublicKeyHashEncryption.cs" />
<Compile Include="Cryptography\PublicKeyHashWithSymmetricKeyEncryption.cs" />
<Compile Include="Cryptography\PublicKeyEncryption.cs" />
<Compile Include="Cryptography\PublicKeySymmetricEncryption.cs" />
<Compile Include="DataFormats\BinaryParser.cs" />
<Compile Include="DataFormats\BinarySerializer.cs" />
<Compile Include="DataFormats\BinaryBlock.cs" />

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.IO;
namespace SafeExamBrowser.Contracts.Configuration.Cryptography
{
/// <summary>
/// Encrypts and decrypts data with a password.
/// </summary>
public interface IPasswordEncryption
{
/// <summary>
/// Attempts to decrypt the given data. The decrypted data stream can only be considered valid if <see cref="LoadStatus.Success"/>
/// is returned!
/// </summary>
LoadStatus Decrypt(Stream data, string password, out Stream decrypted);
/// <summary>
/// Attempts to encrypt the given data. The encrypted data stream can only be considered valid if <see cref="SaveStatus.Success"/>
/// is returned.
/// </summary>
SaveStatus Encrypt(Stream data, string password, out Stream encrypted);
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace SafeExamBrowser.Contracts.Configuration.Cryptography
{
/// <summary>
/// Encrypts and decrypts data with a certificate.
/// </summary>
public interface IPublicKeyEncryption
{
/// <summary>
/// Attempts to decrypt the given data. The decrypted data stream and the certificate can only be considered valid if
/// <see cref="LoadStatus.Success"/> is returned!
/// </summary>
LoadStatus Decrypt(Stream data, out Stream decrypted, out X509Certificate2 certificate);
/// <summary>
/// Attempts to encrypt the given data. The encrypted data stream can only be considered valid if <see cref="SaveStatus.Success"/>
/// is returned.
/// </summary>
SaveStatus Encrypt(Stream data, X509Certificate2 certificate, out Stream encrypted);
}
}

View file

@ -13,7 +13,7 @@ namespace SafeExamBrowser.Contracts.Configuration.Cryptography
/// <summary>
/// Holds all parameters for data encryption by certificate.
/// </summary>
public class PublicKeyHashParameters : EncryptionParameters
public class PublicKeyParameters : EncryptionParameters
{
/// <summary>
/// The certificate holding the public key used for encryption.

View file

@ -59,8 +59,10 @@
<Compile Include="Communication\Events\MessageBoxRequestEventArgs.cs" />
<Compile Include="Configuration\Cryptography\EncryptionParameters.cs" />
<Compile Include="Configuration\Cryptography\ICertificateStore.cs" />
<Compile Include="Configuration\Cryptography\IPasswordEncryption.cs" />
<Compile Include="Configuration\Cryptography\IPublicKeyEncryption.cs" />
<Compile Include="Configuration\Cryptography\PasswordParameters.cs" />
<Compile Include="Configuration\Cryptography\PublicKeyHashParameters.cs" />
<Compile Include="Configuration\Cryptography\PublicKeyParameters.cs" />
<Compile Include="Configuration\DataFormats\FormatType.cs" />
<Compile Include="Configuration\DataCompression\IDataCompressor.cs" />
<Compile Include="Configuration\Cryptography\IHashAlgorithm.cs" />

View file

@ -62,12 +62,12 @@ namespace SafeExamBrowser.Runtime
InitializeText();
var messageBox = new MessageBox(text);
var desktopFactory = new DesktopFactory(new ModuleLogger(logger, nameof(DesktopFactory)));
var explorerShell = new ExplorerShell(new ModuleLogger(logger, nameof(ExplorerShell)), nativeMethods);
var processFactory = new ProcessFactory(new ModuleLogger(logger, nameof(ProcessFactory)));
var desktopFactory = new DesktopFactory(ModuleLogger(nameof(DesktopFactory)));
var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods);
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger);
var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), new ModuleLogger(logger, nameof(RuntimeHost)), FIVE_SECONDS);
var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(ServiceProxy)));
var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), ModuleLogger(nameof(RuntimeHost)), FIVE_SECONDS);
var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), ModuleLogger(nameof(ServiceProxy)));
var sessionContext = new SessionContext();
var uiFactory = new UserInterfaceFactory(text);
@ -116,18 +116,23 @@ namespace SafeExamBrowser.Runtime
var programCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright;
var programTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title;
var programVersion = executable.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
var compressor = new GZipCompressor(new ModuleLogger(logger, nameof(GZipCompressor)));
var repositoryLogger = new ModuleLogger(logger, nameof(ConfigurationRepository));
var compressor = new GZipCompressor(ModuleLogger(nameof(GZipCompressor)));
var passwordEncryption = new PasswordEncryption(ModuleLogger(nameof(PasswordEncryption)));
var publicKeyEncryption = new PublicKeyEncryption(new CertificateStore(), ModuleLogger(nameof(PublicKeyEncryption)));
var symmetricInnerEncryption = new PasswordEncryption(ModuleLogger(nameof(PasswordEncryption)));
var symmetricEncryption = new PublicKeySymmetricEncryption(new CertificateStore(), ModuleLogger(nameof(PublicKeySymmetricEncryption)), symmetricInnerEncryption);
var repositoryLogger = ModuleLogger(nameof(ConfigurationRepository));
var xmlParser = new XmlParser(ModuleLogger(nameof(XmlParser)));
configuration = new ConfigurationRepository(new HashAlgorithm(), repositoryLogger, executable.Location, programCopyright, programTitle, programVersion);
appConfig = configuration.InitializeAppConfig();
configuration.Register(new BinaryParser(compressor, new HashAlgorithm(), new ModuleLogger(logger, nameof(BinaryParser))));
configuration.Register(new BinarySerializer(compressor, new ModuleLogger(logger, nameof(BinarySerializer))));
configuration.Register(new XmlParser(new ModuleLogger(logger, nameof(XmlParser))));
configuration.Register(new XmlSerializer(new ModuleLogger(logger, nameof(XmlSerializer))));
configuration.Register(new FileResourceLoader(new ModuleLogger(logger, nameof(FileResourceLoader))));
configuration.Register(new FileResourceSaver(new ModuleLogger(logger, nameof(FileResourceSaver))));
configuration.Register(new BinaryParser(compressor, new HashAlgorithm(), ModuleLogger(nameof(BinaryParser)), passwordEncryption, publicKeyEncryption, symmetricEncryption, xmlParser));
configuration.Register(new BinarySerializer(compressor, ModuleLogger(nameof(BinarySerializer))));
configuration.Register(new XmlParser(ModuleLogger(nameof(XmlParser))));
configuration.Register(new XmlSerializer(ModuleLogger(nameof(XmlSerializer))));
configuration.Register(new FileResourceLoader(ModuleLogger(nameof(FileResourceLoader))));
configuration.Register(new FileResourceSaver(ModuleLogger(nameof(FileResourceSaver))));
configuration.Register(new NetworkResourceLoader(appConfig, new ModuleLogger(logger, nameof(NetworkResourceLoader))));
}
@ -148,5 +153,10 @@ namespace SafeExamBrowser.Runtime
text = new Text(logger);
textResource = new XmlTextResource(path);
}
private IModuleLogger ModuleLogger(string moduleInfo)
{
return new ModuleLogger(logger, moduleInfo);
}
}
}