You need an 'Initialization vector'. My method below generates it on
encrypting, and you have to supply the same one back when decrypting, aswell
as the same key.
Encryption basically works on byte streams, so I have to use unicode
encoding to convert it to a string. This is apparently the best encoding in
terms of displayability and round-trip-ability - although I'm not sure how
UTF8 rates. I'm not that hot on my encoding technology, perhaps somebody else
could explain this...
public static string EncryptString(string raw, string key, out string iv)
{
byte[] b_raw = Encoding.Unicode.GetBytes(raw),
b_key = Convert.FromBase64String(key),
b_iv = new byte[16],
b_int = new byte[64];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(b_iv);
MemoryStream ms_raw = new MemoryStream(b_raw, false),
ms_enc = new MemoryStream();
SymmetricAlgorithm sa = SymmetricAlgorithm.Create();
ICryptoTransform ict = sa.CreateEncryptor(b_key, b_iv);
CryptoStream cs = new CryptoStream(ms_enc, ict, CryptoStreamMode.Write);
int totread = 0;
while(totread < ms_raw.Length)
{
int read = ms_raw.Read(b_int, 0, 64);
cs.Write(b_int, 0, read);
totread += read;
}
cs.Close();
iv = Convert.ToBase64String(b_iv);
byte[] b_enc = ms_enc.ToArray();
return Convert.ToBase64String(b_enc);
}
public static string DecryptString(string enc, string key, string iv)
{
byte[] b_enc = Convert.FromBase64String(enc),
b_key = Convert.FromBase64String(key),
b_iv = Convert.FromBase64String(iv),
b_int = new byte[64];
MemoryStream ms_enc = new MemoryStream(b_enc, false),
ms_raw = new MemoryStream();
SymmetricAlgorithm sa = SymmetricAlgorithm.Create();
CryptoStream cs = new CryptoStream(ms_enc, sa.CreateDecryptor(b_key, b_iv),
CryptoStreamMode.Read);
int totread = 0;
while(totread < ms_enc.Length)
{
int read = cs.Read(b_int, 0, 64);
if(read == 0) break;
ms_raw.Write(b_int, 0, read);
totread += read;
}
return Encoding.Unicode.GetString(ms_raw.ToArray());
}