SEBWIN-221: Implemented public key hash encryption.
This commit is contained in:
		
							parent
							
								
									ee166796a5
								
							
						
					
					
						commit
						fc179fe47d
					
				
					 6 changed files with 173 additions and 64 deletions
				
			
		| 
						 | 
					@ -31,9 +31,9 @@ namespace SafeExamBrowser.Configuration.Cryptography
 | 
				
			||||||
			this.logger = logger;
 | 
								this.logger = logger;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal LoadStatus Decrypt(Stream data, string password, out Stream decrypted)
 | 
							internal LoadStatus Decrypt(Stream data, string password, out Stream decryptedData)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			decrypted = default(Stream);
 | 
								decryptedData = default(Stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (password == null)
 | 
								if (password == null)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
| 
						 | 
					@ -49,17 +49,17 @@ namespace SafeExamBrowser.Configuration.Cryptography
 | 
				
			||||||
				return FailForInvalidHmac();
 | 
									return FailForInvalidHmac();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			decrypted = Decrypt(data, encryptionKey, originalHmac.Length);
 | 
								decryptedData = Decrypt(data, encryptionKey, originalHmac.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return LoadStatus.Success;
 | 
								return LoadStatus.Success;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal SaveStatus Encrypt(Stream data, string password, out Stream encrypted)
 | 
							internal SaveStatus Encrypt(Stream data, string password, out Stream encryptedData)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var (authKey, authSalt, encrKey, encrSalt) = GenerateKeysForEncryption(password);
 | 
								var (authKey, authSalt, encrKey, encrSalt) = GenerateKeysForEncryption(password);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			encrypted = Encrypt(data, encrKey, out var initVector);
 | 
								encryptedData = Encrypt(data, encrKey, out var initVector);
 | 
				
			||||||
			encrypted = WriteEncryptionParameters(authKey, authSalt, encrSalt, initVector, encrypted);
 | 
								encryptedData = WriteEncryptionParameters(authKey, authSalt, encrSalt, initVector, encryptedData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return SaveStatus.Success;
 | 
								return SaveStatus.Success;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,6 @@
 | 
				
			||||||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
					 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.IO;
 | 
					using System.IO;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Security.Cryptography;
 | 
					using System.Security.Cryptography;
 | 
				
			||||||
| 
						 | 
					@ -27,28 +26,48 @@ namespace SafeExamBrowser.Configuration.Cryptography
 | 
				
			||||||
			this.logger = logger;
 | 
								this.logger = logger;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal virtual LoadStatus Decrypt(Stream data, out Stream decrypted, out X509Certificate2 certificate)
 | 
							internal virtual LoadStatus Decrypt(Stream data, out Stream decryptedData, out X509Certificate2 certificate)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var keyHash = ParsePublicKeyHash(data);
 | 
								var publicKeyHash = ParsePublicKeyHash(data);
 | 
				
			||||||
			var found = TryGetCertificateWith(keyHash, out certificate);
 | 
								var found = TryGetCertificateWith(publicKeyHash, out certificate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			decrypted = default(Stream);
 | 
								decryptedData = default(Stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!found)
 | 
								if (!found)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				return FailForMissingCertificate();
 | 
									return FailForMissingCertificate();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			decrypted = Decrypt(data, PUBLIC_KEY_HASH_SIZE, certificate);
 | 
								decryptedData = Decrypt(data, PUBLIC_KEY_HASH_SIZE, certificate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return LoadStatus.Success;
 | 
								return LoadStatus.Success;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal virtual SaveStatus Encrypt(Stream data, X509Certificate2 certificate, out Stream encrypted)
 | 
							internal virtual SaveStatus Encrypt(Stream data, X509Certificate2 certificate, out Stream encryptedData)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// TODO: Don't forget to write encryption parameters!
 | 
								var publicKeyHash = GeneratePublicKeyHash(certificate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			throw new NotImplementedException();
 | 
								encryptedData = Encrypt(data, certificate);
 | 
				
			||||||
 | 
								encryptedData = WriteEncryptionParameters(encryptedData, publicKeyHash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return SaveStatus.Success;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected LoadStatus FailForMissingCertificate()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								logger.Error($"Could not find certificate which matches the given public key hash!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return LoadStatus.InvalidData;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected byte[] GeneratePublicKeyHash(X509Certificate2 certificate)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var publicKey = certificate.PublicKey.EncodedKeyValue.RawData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								using (var sha = new SHA1CryptoServiceProvider())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return sha.ComputeHash(publicKey);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		protected byte[] ParsePublicKeyHash(Stream data)
 | 
							protected byte[] ParsePublicKeyHash(Stream data)
 | 
				
			||||||
| 
						 | 
					@ -102,42 +121,84 @@ namespace SafeExamBrowser.Configuration.Cryptography
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		protected LoadStatus FailForMissingCertificate()
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			logger.Error($"Could not find certificate which matches the given public key hash!");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return LoadStatus.InvalidData;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		protected MemoryStream Decrypt(Stream data, long offset, X509Certificate2 certificate)
 | 
							protected MemoryStream Decrypt(Stream data, long offset, X509Certificate2 certificate)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var algorithm = certificate.PrivateKey as RSACryptoServiceProvider;
 | 
								var algorithm = certificate.PrivateKey as RSACryptoServiceProvider;
 | 
				
			||||||
			var blockSize = algorithm.KeySize / 8;
 | 
								var blockSize = algorithm.KeySize / 8;
 | 
				
			||||||
			var blockCount = (data.Length - offset) / blockSize;
 | 
								var blockCount = (data.Length - offset) / blockSize;
 | 
				
			||||||
 | 
								var decrypted = new MemoryStream();
 | 
				
			||||||
 | 
								var decryptedBuffer = new byte[blockSize];
 | 
				
			||||||
 | 
								var encryptedBuffer = new byte[blockSize];
 | 
				
			||||||
			var remainingBytes = data.Length - offset - (blockSize * blockCount);
 | 
								var remainingBytes = data.Length - offset - (blockSize * blockCount);
 | 
				
			||||||
			var encrypted = new byte[blockSize];
 | 
					 | 
				
			||||||
			var decrypted = default(byte[]);
 | 
					 | 
				
			||||||
			var decryptedData = new MemoryStream();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			data.Seek(offset, SeekOrigin.Begin);
 | 
								data.Seek(offset, SeekOrigin.Begin);
 | 
				
			||||||
			logger.Debug("Decrypting data...");
 | 
								logger.Debug("Decrypting data...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (int i = 0; i < blockCount; i++)
 | 
								using (algorithm)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				data.Read(encrypted, 0, encrypted.Length);
 | 
									for (var block = 0; block < blockCount; block++)
 | 
				
			||||||
				decrypted = algorithm.Decrypt(encrypted, false);
 | 
									{
 | 
				
			||||||
				decryptedData.Write(decrypted, 0, decrypted.Length);
 | 
										data.Read(encryptedBuffer, 0, encryptedBuffer.Length);
 | 
				
			||||||
 | 
										decryptedBuffer = algorithm.Decrypt(encryptedBuffer, false);
 | 
				
			||||||
 | 
										decrypted.Write(decryptedBuffer, 0, decryptedBuffer.Length);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (remainingBytes > 0)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										encryptedBuffer = new byte[remainingBytes];
 | 
				
			||||||
 | 
										data.Read(encryptedBuffer, 0, encryptedBuffer.Length);
 | 
				
			||||||
 | 
										decryptedBuffer = algorithm.Decrypt(encryptedBuffer, false);
 | 
				
			||||||
 | 
										decrypted.Write(decryptedBuffer, 0, decryptedBuffer.Length);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (remainingBytes > 0)
 | 
								return decrypted;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected Stream Encrypt(Stream data, X509Certificate2 certificate)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var algorithm = certificate.PublicKey.Key as RSACryptoServiceProvider;
 | 
				
			||||||
 | 
								var blockSize = (algorithm.KeySize / 8) - 32;
 | 
				
			||||||
 | 
								var blockCount = data.Length / blockSize;
 | 
				
			||||||
 | 
								var decryptedBuffer = new byte[blockSize];
 | 
				
			||||||
 | 
								var encrypted = new MemoryStream();
 | 
				
			||||||
 | 
								var encryptedBuffer = new byte[blockSize];
 | 
				
			||||||
 | 
								var remainingBytes = data.Length - (blockCount * blockSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								data.Seek(0, SeekOrigin.Begin);
 | 
				
			||||||
 | 
								logger.Debug("Encrypting data...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								using (algorithm)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				encrypted = new byte[remainingBytes];
 | 
									for (var block = 0; block < blockCount; block++)
 | 
				
			||||||
				data.Read(encrypted, 0, encrypted.Length);
 | 
									{
 | 
				
			||||||
				decrypted = algorithm.Decrypt(encrypted, false);
 | 
										data.Read(decryptedBuffer, 0, decryptedBuffer.Length);
 | 
				
			||||||
				decryptedData.Write(decrypted, 0, decrypted.Length);
 | 
										encryptedBuffer = algorithm.Encrypt(decryptedBuffer, false);
 | 
				
			||||||
 | 
										encrypted.Write(encryptedBuffer, 0, encryptedBuffer.Length);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (remainingBytes > 0)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										decryptedBuffer = new byte[remainingBytes];
 | 
				
			||||||
 | 
										data.Read(decryptedBuffer, 0, decryptedBuffer.Length);
 | 
				
			||||||
 | 
										encryptedBuffer = algorithm.Encrypt(decryptedBuffer, false);
 | 
				
			||||||
 | 
										encrypted.Write(encryptedBuffer, 0, encryptedBuffer.Length);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return decryptedData;
 | 
								return encrypted;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private Stream WriteEncryptionParameters(Stream encryptedData, byte[] keyHash)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var data = new MemoryStream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								logger.Debug("Writing encryption parameters...");
 | 
				
			||||||
 | 
								data.Write(keyHash, 0, keyHash.Length);
 | 
				
			||||||
 | 
								encryptedData.Seek(0, SeekOrigin.Begin);
 | 
				
			||||||
 | 
								encryptedData.CopyTo(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return data;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.IO;
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Security.Cryptography;
 | 
				
			||||||
using System.Security.Cryptography.X509Certificates;
 | 
					using System.Security.Cryptography.X509Certificates;
 | 
				
			||||||
using SafeExamBrowser.Contracts.Configuration;
 | 
					using SafeExamBrowser.Contracts.Configuration;
 | 
				
			||||||
using SafeExamBrowser.Contracts.Logging;
 | 
					using SafeExamBrowser.Contracts.Logging;
 | 
				
			||||||
| 
						 | 
					@ -16,6 +17,7 @@ namespace SafeExamBrowser.Configuration.Cryptography
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	internal class PublicKeyHashWithSymmetricKeyEncryption : PublicKeyHashEncryption
 | 
						internal class PublicKeyHashWithSymmetricKeyEncryption : PublicKeyHashEncryption
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							private const int ENCRYPTION_KEY_LENGTH = 32;
 | 
				
			||||||
		private const int KEY_LENGTH_SIZE = 4;
 | 
							private const int KEY_LENGTH_SIZE = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		private PasswordEncryption passwordEncryption;
 | 
							private PasswordEncryption passwordEncryption;
 | 
				
			||||||
| 
						 | 
					@ -25,12 +27,12 @@ namespace SafeExamBrowser.Configuration.Cryptography
 | 
				
			||||||
			this.passwordEncryption = passwordEncryption;
 | 
								this.passwordEncryption = passwordEncryption;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal override LoadStatus Decrypt(Stream data, out Stream decrypted, out X509Certificate2 certificate)
 | 
							internal override LoadStatus Decrypt(Stream data, out Stream decryptedData, out X509Certificate2 certificate)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var keyHash = ParsePublicKeyHash(data);
 | 
								var publicKeyHash = ParsePublicKeyHash(data);
 | 
				
			||||||
			var found = TryGetCertificateWith(keyHash, out certificate);
 | 
								var found = TryGetCertificateWith(publicKeyHash, out certificate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			decrypted = default(Stream);
 | 
								decryptedData = default(Stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!found)
 | 
								if (!found)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
| 
						 | 
					@ -39,16 +41,45 @@ namespace SafeExamBrowser.Configuration.Cryptography
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var symmetricKey = ParseSymmetricKey(data, certificate);
 | 
								var symmetricKey = ParseSymmetricKey(data, certificate);
 | 
				
			||||||
			var stream = new SubStream(data, data.Position, data.Length - data.Position);
 | 
								var stream = new SubStream(data, data.Position, data.Length - data.Position);
 | 
				
			||||||
			var status = passwordEncryption.Decrypt(stream, symmetricKey, out decrypted);
 | 
								var status = passwordEncryption.Decrypt(stream, symmetricKey, out decryptedData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return status;
 | 
								return status;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal override SaveStatus Encrypt(Stream data, X509Certificate2 certificate, out Stream encrypted)
 | 
							internal override SaveStatus Encrypt(Stream data, X509Certificate2 certificate, out Stream encryptedData)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// TODO: Don't forget to write encryption parameters!
 | 
								var publicKeyHash = GeneratePublicKeyHash(certificate);
 | 
				
			||||||
 | 
								var symmetricKey = GenerateSymmetricKey();
 | 
				
			||||||
 | 
								var symmetricKeyString = Convert.ToBase64String(symmetricKey);
 | 
				
			||||||
 | 
								var status = passwordEncryption.Encrypt(data, symmetricKeyString, out encryptedData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			throw new NotImplementedException();
 | 
								if (status != SaveStatus.Success)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return FailForUnsuccessfulPasswordEncryption(status);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								encryptedData = WriteEncryptionParameters(encryptedData, certificate, publicKeyHash, symmetricKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return SaveStatus.Success;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private SaveStatus FailForUnsuccessfulPasswordEncryption(SaveStatus status)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								logger.Error($"Password encryption has failed with status '{status}'!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return SaveStatus.UnexpectedError;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private byte[] GenerateSymmetricKey()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var key = new byte[ENCRYPTION_KEY_LENGTH];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								using (var generator = RandomNumberGenerator.Create())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									generator.GetBytes(key);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return key;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		private string ParseSymmetricKey(Stream data, X509Certificate2 certificate)
 | 
							private string ParseSymmetricKey(Stream data, X509Certificate2 certificate)
 | 
				
			||||||
| 
						 | 
					@ -60,16 +91,38 @@ namespace SafeExamBrowser.Configuration.Cryptography
 | 
				
			||||||
			data.Seek(PUBLIC_KEY_HASH_SIZE, SeekOrigin.Begin);
 | 
								data.Seek(PUBLIC_KEY_HASH_SIZE, SeekOrigin.Begin);
 | 
				
			||||||
			data.Read(keyLengthData, 0, keyLengthData.Length);
 | 
								data.Read(keyLengthData, 0, keyLengthData.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var keyLength = BitConverter.ToInt32(keyLengthData, 0);
 | 
								var encryptedKeyLength = BitConverter.ToInt32(keyLengthData, 0);
 | 
				
			||||||
			var encryptedKey = new byte[keyLength];
 | 
								var encryptedKey = new byte[encryptedKeyLength];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			data.Read(encryptedKey, 0, encryptedKey.Length);
 | 
								data.Read(encryptedKey, 0, encryptedKey.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var stream = new SubStream(data, PUBLIC_KEY_HASH_SIZE + KEY_LENGTH_SIZE, keyLength);
 | 
								var stream = new SubStream(data, PUBLIC_KEY_HASH_SIZE + KEY_LENGTH_SIZE, encryptedKeyLength);
 | 
				
			||||||
			var decryptedKey = Decrypt(stream, 0, certificate);
 | 
								var decryptedKey = Decrypt(stream, 0, certificate);
 | 
				
			||||||
			var symmetricKey = Convert.ToBase64String(decryptedKey.ToArray());
 | 
								var symmetricKey = Convert.ToBase64String(decryptedKey.ToArray());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return symmetricKey;
 | 
								return symmetricKey;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private Stream WriteEncryptionParameters(Stream encryptedData, X509Certificate2 certificate, byte[] publicKeyHash, byte[] symmetricKey)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var data = new MemoryStream();
 | 
				
			||||||
 | 
								var symmetricKeyData = new MemoryStream(symmetricKey);
 | 
				
			||||||
 | 
								var encryptedKey = Encrypt(symmetricKeyData, certificate);
 | 
				
			||||||
 | 
								// IMPORTANT: The key length must be exactly 4 Bytes, thus the cast to integer!
 | 
				
			||||||
 | 
								var encryptedKeyLength = BitConverter.GetBytes((int) encryptedKey.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								logger.Debug("Writing encryption parameters...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								data.Write(publicKeyHash, 0, publicKeyHash.Length);
 | 
				
			||||||
 | 
								data.Write(encryptedKeyLength, 0, encryptedKeyLength.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								encryptedKey.Seek(0, SeekOrigin.Begin);
 | 
				
			||||||
 | 
								encryptedKey.CopyTo(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								encryptedData.Seek(0, SeekOrigin.Begin);
 | 
				
			||||||
 | 
								encryptedData.CopyTo(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return data;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ namespace SafeExamBrowser.Configuration.DataFormats
 | 
				
			||||||
					var prefix = ReadPrefix(data);
 | 
										var prefix = ReadPrefix(data);
 | 
				
			||||||
					var isValid = IsValid(prefix);
 | 
										var isValid = IsValid(prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					logger.Debug($"'{data}' starting with '{prefix}' does {(isValid ? string.Empty : "not ")}match the {FormatType.Binary} format.");
 | 
										logger.Debug($"'{data}' starting with '{prefix}' {(isValid ? "matches" : "does not match")} the {FormatType.Binary} format.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					return isValid;
 | 
										return isValid;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,25 +105,20 @@ namespace SafeExamBrowser.Configuration.DataFormats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		private SerializeResult SerializePublicKeyHashBlock(IDictionary<string, object> data, PublicKeyHashParameters parameters)
 | 
							private SerializeResult SerializePublicKeyHashBlock(IDictionary<string, object> data, PublicKeyHashParameters parameters)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var result = SerializePlainDataBlock(data);
 | 
								var result = SerializePublicKeyHashInnerBlock(data, parameters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (result.Status == SaveStatus.Success)
 | 
								if (result.Status == SaveStatus.Success)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				result = SerializePublicKeyHashInnerBlock(data, parameters);
 | 
									var encryption = DetermineEncryptionForPublicKeyHashBlock(parameters);
 | 
				
			||||||
 | 
									var prefix = parameters.SymmetricEncryption ? BinaryBlock.PublicKeyHashWithSymmetricKey : BinaryBlock.PublicKeyHash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (result.Status == SaveStatus.Success)
 | 
									logger.Debug("Attempting to serialize public key hash block...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									var status = encryption.Encrypt(result.Data, parameters.Certificate, out var encrypted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (status == SaveStatus.Success)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					var encryption = DetermineEncryptionForPublicKeyHashBlock(parameters);
 | 
										result.Data = WritePrefix(prefix, encrypted);
 | 
				
			||||||
					var prefix = parameters.SymmetricEncryption ? BinaryBlock.PublicKeyHashWithSymmetricKey : BinaryBlock.PublicKeyHash;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					logger.Debug("Attempting to serialize public key hash block...");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					var status = encryption.Encrypt(result.Data, parameters.Certificate, out var encrypted);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if (status == SaveStatus.Success)
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						result.Data = WritePrefix(prefix, encrypted);
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,11 +43,11 @@ namespace SafeExamBrowser.Configuration.DataFormats
 | 
				
			||||||
					data.Read(prefixData, 0, prefixData.Length);
 | 
										data.Read(prefixData, 0, prefixData.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					var prefix = Encoding.UTF8.GetString(prefixData);
 | 
										var prefix = Encoding.UTF8.GetString(prefixData);
 | 
				
			||||||
					var success = prefix == XML_PREFIX;
 | 
										var isXml = prefix == XML_PREFIX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					logger.Debug($"'{data}' starting with '{prefix}' does {(success ? string.Empty : "not ")}match the {FormatType.Xml} format.");
 | 
										logger.Debug($"'{data}' starting with '{prefix}' {(isXml ? "matches" : "does not match")} the {FormatType.Xml} format.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					return success;
 | 
										return isXml;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				logger.Debug($"'{data}' is not long enough ({data.Length} bytes) to match the {FormatType.Xml} format.");
 | 
									logger.Debug($"'{data}' is not long enough ({data.Length} bytes) to match the {FormatType.Xml} format.");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue