My application needs to implement authenticated encryption using C#. There is a .NET class called encryptAndAuthenticate, but it is only supported on windows 8 or later, and I need the code to also work on windows 7. I created a class for internal use in my app that uses the encrypt-then-authenticate model.  I use AES and HMAC-SHA256.The code was borrowed heavily from two sites:Microsoft AES C# code sampleJay Tuley's AES / HMAC implementationIf you see mistakes in my use of the .NET crypto functions or general mistakes please let me know!Note: I didn't add the XML comment blocks to my functions because in my opinion (you may disagree) they take up extra space and don't provide much benefit if your class is only used inside your own app.internal static class CryptoLayer{    private const int saltSizeBytes = 32;    private const int aesKeySizeBytes = 32;    private const int aesIVSizeBytes = 16;    private const int hmacKeySizeBytes = 32;    private const int hmacTagSizeBytes = 32;    // 3 values must be derived (aes key, aes iv, and hmac key).    // Number of total iterations is 3 * keyDerivationIterations.    // Takes about 500 ms total.    private const int keyDerivationIterations = 20000;    // This is called to generate a random byte array of size saltSizeBytes.    public static byte[] GenerateSalt()    {        using (var randomGenerator = new RNGCryptoServiceProvider())        {            var salt = new byte[saltSizeBytes];            randomGenerator.GetBytes(salt);            return salt;        }    }    // Take in password and salt and derive the key and IV for the aes encryption and the key for hmac.    private static void DeriveKeys(string password, byte[] salt, out byte[] aesKey, out byte[] aesIV, out byte[] hmacKey)    {        // Derive the key, IV, and mac key using the password and the salt.        using (var derivedKey = new Rfc2898DeriveBytes(password, salt, keyDerivationIterations))        {            aesKey = derivedKey.GetBytes(aesKeySizeBytes);            aesIV = derivedKey.GetBytes(aesIVSizeBytes);            hmacKey = derivedKey.GetBytes(hmacKeySizeBytes);        }    }    // Takes in plain text, password, and salt. Populates output parameters cipherText and macTag.    public static void EncryptThenAuthenicate(string plainText, string password, byte[] salt, out byte[] cipherText, out byte[] macTag)    {        // Default output params to null        cipherText = null;        macTag = null;        try        {            // Populate aesKey, aesIV, and hmacKey via key derivation function            byte[] aesKey, aesIV, hmacKey;            DeriveKeys(password, salt, out aesKey, out aesIV, out hmacKey);            // Set up AES encryption provider object.            using (var aesAlg = new AesCryptoServiceProvider())            {                aesAlg.Key = aesKey;                aesAlg.IV = aesIV;                // Create an encrytor to perform the stream transform.                var encryptor = aesAlg.CreateEncryptor(aesKey, aesIV);                // Create the streams used for encryption.                using (var msEncrypt = new MemoryStream())                {                    using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))                    {                        using (var swEncrypt = new StreamWriter(csEncrypt))                        {                            //Write all data to the stream.                            swEncrypt.Write(plainText);                        }                        cipherText = msEncrypt.ToArray();                    }                }            }            // Generate mac tag using by using hmac function on IV||cipherText.            using (var hmac = new HMACSHA256(hmacKey))            {                using (var msEncrypt = new MemoryStream())                {                    using (var binaryWriter = new BinaryWriter(msEncrypt))                    {                        // Prepend IV                        binaryWriter.Write(aesIV);                        // Write cipher text                        binaryWriter.Write(cipherText);                        binaryWriter.Flush();                        //Authenticate IV||cipherText and create mac tag                        macTag = hmac.ComputeHash(msEncrypt.ToArray());                    }                }            }        }        catch (Exception ex)        {            MessageBox.Show(String.Format(Encryption failed. {0}, ex.Message), Encryption Error!, MessageBoxButtons.OK, MessageBoxIcon.Error);        }    }    // Takes in cipherText, password, salt, and mac tag.    // First, authenticates aesIV||cipherText using mac tag.    // Then, if that succeeds, decrypts and returns plainText.    public static string AuthenticateThenDecrypt(byte[] cipherText, string password, byte[] salt, byte[] macTag)    {        try        {            // Populate aesKey, aesIV, and hmacKey via key derivation function            byte[] aesKey, aesIV, hmacKey;            DeriveKeys(password, salt, out aesKey, out aesIV, out hmacKey);            // Create byte array to store IV||cipherText            byte[] ivAndCipherText = new byte[aesIV.Length + cipherText.Length];            aesIV.CopyTo(ivAndCipherText, 0);            cipherText.CopyTo(ivAndCipherText, aesIV.Length);            // Calculate if stored macTag matches calcuated macTag.  If not, return error.            using (var hmac = new HMACSHA256(hmacKey))            {                // Calculate what mac tag should be.                var calcTag = hmac.ComputeHash(ivAndCipherText);                // Compare with constant time comparison to prevent timing attacks.                var mismatch = 0;                for (var i = 0; i < macTag.Length; i++)                    mismatch |= macTag[i] ^ calcTag[i];                // If message doesn't authenticate, return error and exit routine.                if (mismatch != 0)                    throw new Exception(Incorrect password or corrupted data.);                // Authentication suceeded, now decrypt...                // Set up AES encryption provider object.                using (var aesAlg = new AesCryptoServiceProvider())                {                    aesAlg.Key = aesKey;                    aesAlg.IV = aesIV;                    // Create a decrytor to perform the stream transform.                    var decryptor = aesAlg.CreateDecryptor(aesKey, aesIV);                    // Create the streams used for decryption.                    using (var msDecrypt = new MemoryStream(cipherText))                    {                        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))                        {                            using (var srDecrypt = new StreamReader(csDecrypt))                            {                                // Read the decrypted bytes from the decrypting stream and return as string.                                return srDecrypt.ReadToEnd();                            }                        }                    }                }            }        }        catch (Exception ex)        {            MessageBox.Show(String.Format(Decryption failed. {0}, ex.Message),Decryption Error!, MessageBoxButtons.OK, MessageBoxIcon.Error);            return string.Empty;        }    }}
Implementation of authenticated encryption
c#;cryptography