private static byte[] EncryptWithHmac(AES256Key encryptionKey, byte[] iv, AES256Key authenticationKey, byte[] plainText, byte[] associatedData = null)
        {
            byte[] cipherText = encryptionKey.Encrypt(plainText, iv);
            byte[] toHash     = (associatedData ?? new byte[1]).Concat(cipherText).ToArray();
            byte[] hash       = authenticationKey.CalculateHmac256Hash(toHash);

            // Appends hash to the encrypted message
            return(cipherText.Concat(hash).ToArray());
        }
        private static byte[] DecryptWithHmac(AES256Key encryptionKey, byte[] iv, AES256Key authenticationKey, byte[] cipherTextWithHmac, byte[] associatedData = null)
        {
            byte[] cipherText = cipherTextWithHmac.Take(cipherTextWithHmac.Length - 256 / 8).ToArray();
            byte[] hash       = new byte[256 / 8];
            Array.Copy(cipherTextWithHmac, cipherTextWithHmac.Length - 256 / 8, hash, 0, hash.Length);

            // The associated data will default to an empty 0x00 byte
            byte[] toHash         = (associatedData ?? new byte[1]).Concat(cipherText).ToArray();
            byte[] hashCalculated = authenticationKey.CalculateHmac256Hash(toHash);

            // if the hashes don't match, return null
            return(!hash.SequenceEqual(hashCalculated) ? null : encryptionKey.Decrypt(cipherText, iv));
        }