While playing with some AES C# wrappers found on SO and msdn (most notable here and here and here) I wrote the following code and I made the mistake of writing the IV to the CryptoStream.
What I noticed is that the output byte array contains the same values when the IV is written to the CryptoStream. If I comment out the line cryptoStream.Write(aes.IV, 0, aes.IV.Length);, it's fine, the output will be different.
My question is why in this case the output is the same? I realize that writing the IV to the CryptoStream is not what I am supposed to do but I find it odd especially given that the IV is different every time the function executes.
TestEncryption.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
  public class TestEncryption
  {
    public static readonly int KeyBitSize = 256;
    private static readonly int BlockBitSize = 128;
    public static readonly byte[] _salt = new byte[] { 23, 13, 23, 213, 15, 193, 134, 147, 223, 151 };
    const int Iterations = 10000;
    public static string Encrypt(byte[] inputBytes, string password)
    {
      using (var aes = new AesManaged
      {
        KeySize = KeyBitSize,
        BlockSize = BlockBitSize,
        Mode = CipherMode.CBC,
        Padding = PaddingMode.PKCS7,
      })
      {
        var cryptKey = CreateKey(password);
        aes.GenerateIV();
        Console.WriteLine("IV={0}", string.Join(", ", aes.IV.Select(b => b.ToString())));
        using (var encrypter = aes.CreateEncryptor(cryptKey, aes.IV))
        using (var output = new MemoryStream())
        {
          using (var cryptoStream = new CryptoStream(output, encrypter, CryptoStreamMode.Write))
          {
            cryptoStream.Write(aes.IV, 0, aes.IV.Length);
            cryptoStream.Write(inputBytes, 0, inputBytes.Length);
            cryptoStream.FlushFinalBlock();
          }
          Console.WriteLine("Output={0}", string.Join(", ", output.ToArray().Select(b => b.ToString())));
          return Convert.ToBase64String(output.ToArray());
        }
      }
    }
    public static string Encrypt(string input, string password)
    {
      return Encrypt(Encoding.UTF8.GetBytes(input), password);
    }
    public static byte[] CreateKey(string password)
    {
      using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, _salt, Iterations))
        return rfc2898DeriveBytes.GetBytes(32);
    }
  }
}
Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
  class Program
  {
    static void Main(string[] args)
    { 
      //Test1();
      Test2();
      Console.ReadLine();
    }
    private static void Test2()
    {
      string text = "some longer text";
      string pwd = "test2";
      String encrypt1 = TestEncryption.Encrypt(text, pwd);
      String encrypt2 = TestEncryption.Encrypt(text, pwd);
      Console.WriteLine(encrypt1 == encrypt2);
    }
 }
}
 
    