private async void EncryptMessageButton_Click(object sender, RoutedEventArgs e)
        {
            StatusImage.Visibility    = Visibility.Hidden;
            ErrorTextBlock.Visibility = Visibility.Hidden;

            if (UserInputRSADetails())
            {
                return;
            }

            // ask user for location to save encrypted message
            string encryptedFile = null;

            SaveFileDialog saveFileDialog = new SaveFileDialog();

            saveFileDialog.Title  = "Save as";
            saveFileDialog.Filter = "Encrypted message (*.crypto)|*.crypto";

            if (saveFileDialog.ShowDialog() == true)
            {
                encryptedFile = saveFileDialog.FileName;
            }

            // only open filestreams if files were selected by user
            if (encryptedFile != null)
            {
                // open streams
                MemoryStream inputStream  = new MemoryStream();
                byte[]       messageBytes = Encoding.UTF8.GetBytes(InputMessageBox.Text);
                inputStream.Write(messageBytes, 0, messageBytes.Length);

                // message requires a minimum length, pad it with 32 0x00 bytes
                if (inputStream.Length < 32)
                {
                    inputStream.Write(new byte[32], 0, 32);
                }

                inputStream.Position = inputStream.Seek(0, SeekOrigin.Begin);
                FileStream outputStream = null;

                try
                {
                    outputStream = File.OpenWrite(encryptedFile);

                    await HybridEncryption.EncryptFile(inputStream, outputStream, AsymmetricEncryption.PublicKeyFromXml(PublicRSAKeyReceiver.Text));

                    MessageBox.Show("Done");
                }
                catch (IOException exception)
                {
                    ErrorTextBlock.Visibility = Visibility.Visible;
                    ErrorTextBlock.Text       = exception.Message;
                }
                finally
                {
                    inputStream?.Close();
                    outputStream?.Close();
                }
            }
        }
        public void Can_Encrypt_Stream_Of_Data()
        {
            byte[] fileBytes = Random.GetNumbers(2048);

            MemoryStream inputStream = new MemoryStream(fileBytes);

            EncryptedPacket encryptedPacket = HybridEncryption.EncryptFile(inputStream, asymmetricPublicKey);

            Assert.NotNull(encryptedPacket);
            CollectionAssert.AreNotEqual(fileBytes, encryptedPacket.EncryptedData);
        }
        public async Task Can_Decrypt_Large_Stream_Of_Data()
        {
            byte[] fileBytes = Random.GetNumbers(128_000_000);

            MemoryStream rawStream = new MemoryStream(fileBytes);

            MemoryStream encryptedBytes = new MemoryStream();
            await HybridEncryption.EncryptFile(rawStream, encryptedBytes, asymmetricPublicKey);

            encryptedBytes.Position = 0;

            MemoryStream decryptedStream = new MemoryStream();
            bool         hashOk          = await HybridEncryption.DecryptFile(encryptedBytes, decryptedStream, asymmetricPublicKey);

            decryptedStream.Position = 0;
            byte[] decryptedBytes = decryptedStream.ToArray();

            Assert.True(hashOk);
            CollectionAssert.IsNotEmpty(decryptedBytes);
            CollectionAssert.AreEqual(fileBytes, decryptedBytes);
        }
        private async void EncryptFileStenographyButton_Click(object sender, RoutedEventArgs e)
        {
            ErrorTextBlock.Visibility = Visibility.Hidden;

            FileStream   baseFile      = null;
            FileStream   saveFile      = null;
            MemoryStream messageData   = null;
            MemoryStream encryptedData = null;

            try
            {
                // put original message into a memory stream
                byte[] messageBytes = Encoding.UTF8.GetBytes(InputMessageBox.Text);
                messageData = new MemoryStream();
                messageData.Write(messageBytes, 0, messageBytes.Length);
                if (messageData.Length < 32) // make sure it's longer than the minimum length
                {
                    messageData.Write(new byte[32], 0, 32);
                }
                messageData.Position = 0;

                // select file to use as base
                OpenFileDialog openFileDialog = new OpenFileDialog();
                openFileDialog.Title = "Choose a file to put encrypted message";

                if (openFileDialog.ShowDialog() == true)
                {
                    baseFile = new FileStream(openFileDialog.FileName, FileMode.Open, FileAccess.Read);
                }
                else
                {
                    return;
                }

                // select file to save
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Title        = "Save as";
                saveFileDialog.DefaultExt   = openFileDialog.SafeFileName.Split('.').Last();
                saveFileDialog.AddExtension = true;

                if (saveFileDialog.ShowDialog() == true)
                {
                    saveFile = new FileStream(saveFileDialog.FileName, FileMode.Create, FileAccess.Write);
                }
                else
                {
                    return;
                }

                // encrypt message into memory stream
                encryptedData = new MemoryStream();
                await HybridEncryption.EncryptFile(messageData, encryptedData, AsymmetricEncryption.PublicKeyFromXml(PublicRSAKeyReceiver.Text)).ConfigureAwait(false);

                encryptedData.Position = 0;

                // write length to output
                byte[] baseFileBuffer = new byte[8];

                byte[] length = BitConverter.GetBytes(encryptedData.Length);
                for (int i = 0; i < 8; i++)
                {
                    await baseFile.ReadAsync(baseFileBuffer, 0, 8); // read 8 bytes of input

                    HideInBytes(baseFileBuffer, length[i]);
                    await saveFile.WriteAsync(baseFileBuffer, 0, 8); // write 8 bytes to output
                }

                // hide message in output
                byte[] encryptedDataBuffer = new byte[1];
                for (int i = 0; i < encryptedData.Length; i++)
                {
                    await encryptedData.ReadAsync(encryptedDataBuffer, 0, 1);

                    await baseFile.ReadAsync(baseFileBuffer, 0, 8); // read 8 bytes of input

                    HideInBytes(baseFileBuffer, encryptedDataBuffer[0]);
                    await saveFile.WriteAsync(baseFileBuffer, 0, 8); // write 8 bytes to output
                }

                // write rest of file to output
                byte[] fileBuffer = new byte[1024];
                while (await baseFile.ReadAsync(fileBuffer, 0, 1024) > 0)
                {
                    await saveFile.WriteAsync(fileBuffer, 0, 1024);
                }

                await saveFile.FlushAsync().ConfigureAwait(false);
            }
            catch (IOException exception)
            {
                ErrorTextBlock.Text       = exception.Message;
                ErrorTextBlock.Visibility = Visibility.Visible;
            }
            catch (CryptoException exception)
            {
                ErrorTextBlock.Text       = exception.Message;
                ErrorTextBlock.Visibility = Visibility.Visible;
            }
            finally
            {
                baseFile?.Close();
                saveFile?.Close();
                messageData?.Close();
                encryptedData?.Close();
            }
        }
        private async void EncryptButton_Click(object sender, RoutedEventArgs e)
        {
            ErrorTextBlock.Visibility = Visibility.Hidden;
            StatusImage.Visibility    = Visibility.Hidden;

            if (UserInputRSADetails())
            {
                return;
            }

            // ask user for file to encrypt
            string originalFile = null;

            OpenFileDialog openFileDialog = new OpenFileDialog();

            openFileDialog.Title = "Choose a file to encrypt";

            if (openFileDialog.ShowDialog() == true)
            {
                originalFile = openFileDialog.FileName;
            }

            // ask user for location to save encrypted file
            string encryptedFile = null;

            SaveFileDialog saveFileDialog = new SaveFileDialog();

            saveFileDialog.Title  = "Save as";
            saveFileDialog.Filter = "Encrypted file (*.crypto)|*.crypto"; // TODO: verzin betere file extensie

            if (saveFileDialog.ShowDialog() == true)
            {
                encryptedFile = saveFileDialog.FileName;
            }

            // only open filestreams if files were selected by user
            if (originalFile != null && encryptedFile != null)
            {
                // open streams
                FileStream inputStream  = null;
                FileStream outputStream = null;

                try
                {
                    inputStream  = File.OpenRead(originalFile);
                    outputStream = File.OpenWrite(encryptedFile);

                    await HybridEncryption.EncryptFile(inputStream, outputStream, AsymmetricEncryption.PublicKeyFromXml(PublicRSAKeyReceiver.Text));

                    MessageBox.Show("Done"); // TODO: tell user their encryption is done
                }
                catch (IOException exception)
                {
                    ErrorTextBlock.Visibility = Visibility.Visible;
                    ErrorTextBlock.Text       = exception.Message;
                }
                finally
                {
                    inputStream?.Close();
                    outputStream?.Close();
                }
            }
        }
        /// <summary>
        /// Send a file to currently selected user
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void SendAttachmentButton_Click(object sender, RoutedEventArgs e)
        {
            // get currently selected contact, do nothing if none is selected
            ContactPerson contact = (ContactPerson)ContactListListView.SelectedItem;

            if (contact == null)
            {
                return;
            }

            // ask user to select file
            OpenFileDialog openFileDialog = new OpenFileDialog();

            openFileDialog.Title       = "Choose a file to encrypt";
            openFileDialog.Multiselect = false;

            if (openFileDialog.ShowDialog() == true)
            {
                FileStream fileStream;
                FileInfo   fileInfo;

                try
                {
                    fileInfo = new FileInfo(openFileDialog.FileName);

                    if (fileInfo.Length > 10_000_000) // only upload files smaller than 10MB
                    {
                        ErrorText = "Due to server limitations, files bigger than 10MB (10 000 000 bytes) are not supported.";
                        return;
                    }

                    fileStream = new FileStream(openFileDialog.FileName, FileMode.Open, FileAccess.Read);

                    // encrypt file for receiver
                    EncryptedPacket packetForReceiver = null;
                    await Task.Run(() =>
                    {
                        try
                        {
                            packetForReceiver = HybridEncryption.EncryptFile(fileStream, AsymmetricEncryption.PublicKeyFromXml(contact.PublicKey));
                        }
                        catch (CryptoException exception)
                        {
                            // show to user
                            ErrorText = exception.Message;
                        }
                    });

                    // send to receiver
                    await Client.SendNewMessage(packetForReceiver, contact.Id);
                }
                catch (IOException exception)
                {
                    // show to user
                    ErrorText = exception.Message;
                }
                catch (ClientException exception)
                {
                    // show to user
                    ErrorText = exception.Message;
                }
            }
        }