I am trying to make sense of how to handle and manage an initilization vector and salt (when applicable) when encrypting and decrypting data using a symmetric encryption algorithm, in this case AES.
I have deduced from different SO threads and various other websites that neither the IV or salt need to be secret, only unique in order to defend against cryptanalytic attacks such as a brute-force attack. With this in mind I figured that it would be viable to store my pseudo random IV with the encrypted data. I am asking if the method I am using is proper and furthermore, should I be treating my currently hard coded salt in the same manner? That being writing it to the memory stream along side the IV
My code:
private const ushort ITERATIONS = 300;
private static readonly byte[] SALT = new byte[] { 0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c };
private static byte[] CreateKey(string password, int keySize)
{
DeriveBytes derivedKey = new Rfc2898DeriveBytes(password, SALT, ITERATIONS);
return derivedKey.GetBytes(keySize >> 3);
}
public static byte[] Encrypt(byte[] data, string password)
{
byte[] encryptedData = null;
using (AesCryptoServiceProvider provider = new AesCryptoServiceProvider())
{
provider.GenerateIV();
provider.Key = CreateKey(password, provider.KeySize);
provider.Mode = CipherMode.CBC;
provider.Padding = PaddingMode.PKCS7;
using (MemoryStream memStream = new MemoryStream(data.Length))
{
memStream.Write(provider.IV, 0, 16);
using (ICryptoTransform encryptor = provider.CreateEncryptor(provider.Key, provider.IV))
{
using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
}
}
encryptedData = memStream.ToArray();
}
}
return encryptedData;
}
public static byte[] Decrypt(byte[] data, string password)
{
byte[] decryptedData = new byte[data.Length];
using (AesCryptoServiceProvider provider = new AesCryptoServiceProvider())
{
provider.Key = CreateKey(password, provider.KeySize);
provider.Mode = CipherMode.CBC;
provider.Padding = PaddingMode.PKCS7;
using (MemoryStream memStream = new MemoryStream(data))
{
byte[] iv = new byte[16];
memStream.Read(iv, 0, 16);
using (ICryptoTransform decryptor = provider.CreateDecryptor(provider.Key, iv))
{
using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read))
{
cryptoStream.Read(decryptedData, 0, decryptedData.Length);
}
}
}
}
return decryptedData;
}
I am also open to any other information about symmetric encryption with regards to proper practice.