I use a symmetric algorithm because key is defined with passphrase for both encoding and decoding operations. Creating key from passphrase is based on hashing. We are required to have keys with fixed length and character sets, thus hashing goes a long way here:
var bytes = Encoding.Unicode.GetBytes(passphrase); var key = SHA256Managed.Create().ComputeHash(bytes); var iv = MD5.Create().ComputeHash(bytes);Key and vector may have different requirements regarding length of byte arrays. For the RijndaelManaged class they are 32 and 16 respectively. Thus I use SHA256 and MD5 algorithms to get keys with the appropriate length.
var alg = SymmetricAlgorithm.Create(); var ms = new MemoryStream(); var buffer = Encoding.Unicode.GetBytes(text); using (var enc = new CryptoStream( ms, alg.CreateEncryptor(key, iv), CryptoStreamMode.Write )) { enc.Write(buffer, 0, buffer.Length); }The code above feeds the entire text to the CryptoStream. For passwords encoding it shouldn't be a perfomance issue. Decoding has quite similar implementation. Rather than using alg.CreateEncryptor it should use alg.CreateDecryptor there.
Additionally I use a couple of extention methods to format byte array to hexadecimal string and vice versa. Here are the entire Encode/Decode methods implementation and the helper methods:
private static string Encode(string text, string passphrase) { var bytes = Encoding.Unicode.GetBytes(passphrase); var key = SHA256Managed.Create().ComputeHash(bytes); var iv = MD5.Create().ComputeHash(bytes); var alg = SymmetricAlgorithm.Create(); var ms = new MemoryStream(); var buffer = Encoding.Unicode.GetBytes(text); using(var enc = new CryptoStream( ms, alg.CreateEncryptor(key, iv), CryptoStreamMode.Write )) enc.Write(buffer, 0, buffer.Length); return ms.ToArray().ToHexString(); } private static string Decode(string text, string passphrase) { var bytes = Encoding.Unicode.GetBytes(passphrase); var key = SHA256Managed.Create().ComputeHash(bytes); var iv = MD5.Create().ComputeHash(bytes); var alg = SymmetricAlgorithm.Create(); var ms = new MemoryStream(); var buffer = text.ToByteArray(); try { using (var enc = new CryptoStream( ms, alg.CreateDecryptor(key, iv), CryptoStreamMode.Write )) enc.Write(buffer, 0, buffer.Length); } catch (Exception) { Console.Error.WriteLine("Error: wrong passphrase."); Environment.Exit(2); } return Encoding.Unicode.GetString(ms.ToArray()); } ... internal static string ToHexString(this byte[] bytes) { StringBuilder builder = new StringBuilder(3 * bytes.Length); for (int i = 0; i < bytes.Length; i++) { builder.AppendFormat("{0:x2}", bytes[i]); } return builder.ToString().ToLowerInvariant(); } internal static byte[] ToByteArray(this string hexString) { byte[] buffer = new byte[hexString.Length / 2]; for (int i = 0; i < hexString.Length; i += 2) { buffer[i / 2] = byte.Parse(hexString.Substring(i, 2), NumberStyles.HexNumber); } return buffer; }