Find one at the bottom. The "MyChoiceOf..." functions reflect more or
less arbitrary choices which I have made for the test -- the choices
taken should be sufficient for most applications.
Note that a more proper use of IV would be to generate it randomly and
include the IV in clear in the encrypted text.
Beware that cryptography is really hard to get right and the sligtest
error often results in a complete compromise of the data thought to be
protected.
There are several things I am not too happy about in that code:
- It uses DES-encryption
- It is designed with the keys in the code
- It uses a constant IV
- It doesn't come with a test (I know, that's a cheap-shot

- It converts data, to and from Base64
- It duplicates the code for creating the en/de-cryption keys
- It only works for strings with a valid ASCII-encoding
- It only works for keys with a valid ASCII-encoding
- It uses the ascii-encoding of key-strings as keys
- It uses a MemoryStream where it's not required
Here is my shot at how to do it. note that it copies the IV and
encrypted-string into a new byte[]. If you are reading/writing to a
stream you can remove that, but you explicitly requested simplicity and
the interface would be much more complicated if the cipher-text and IV
is returned/passed seperatly.
using System.Security.Cryptography;
using System.Text;
class CryptExample
{
public static void InitializeAlgorithm(string secret, HashAlgorithm h,
SymmetricAlgorithm a)
{
byte[] b = System.Text.Encoding.UTF8.GetBytes(secret);
h.TransformFinalBlock(b, 0, b.Length);
byte[] secret_hashed = h.Hash;
byte[] key = new byte[a.KeySize/8];
System.Array.Copy(secret_hashed, 0, key, 0, key.Length);
a.Key = key;
}
public static byte[] Encrypt(string s, SymmetricAlgorithm a)
{
byte[] b = Encoding.UTF8.GetBytes(s);
a.GenerateIV();
byte[] iv = a.IV;
byte[] enc;
using ( ICryptoTransform c = a.CreateEncryptor() )
enc = c.TransformFinalBlock(b, 0, b.Length);
byte[] all = new byte[iv.Length+enc.Length];
System.Array.Copy(iv, 0, all, 0, iv.Length);
System.Array.Copy(enc, 0, all, iv.Length, enc.Length);
return all;
}
public static string Decrypt(byte[] bytes, int offset, int length,
SymmetricAlgorithm a)
{
byte[] iv = new byte[a.BlockSize/8];
System.Array.Copy(bytes, offset, iv, 0, iv.Length);
a.IV = iv;
using ( ICryptoTransform c = a.CreateDecryptor() )
return Encoding.UTF8.GetString(c.TransformFinalBlock(bytes, offset
+ iv.Length, length - iv.Length));
}
public static SymmetricAlgorithm MyChoiceOfEncryptionAlgo()
{
SymmetricAlgorithm alg = Rijndael.Create();
alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.PKCS7;
alg.KeySize = 256;
return alg;
}
public static HashAlgorithm MyChoiceOfHashAlgo() { return
SHA512.Create(); }
public static void Main()
{
string secret = "password";
SymmetricAlgorithm enc_algo = MyChoiceOfEncryptionAlgo();
SymmetricAlgorithm dec_algo = MyChoiceOfEncryptionAlgo();
InitializeAlgorithm(secret, MyChoiceOfHashAlgo(), enc_algo);
InitializeAlgorithm(secret, MyChoiceOfHashAlgo(), dec_algo);
for ( int i = 0; i < 1000000; i = (3*i + 1) )
{
string msg = new string('a', i);
byte[] enc = Encrypt(msg, enc_algo);
string dec = Decrypt(enc, 0, enc.Length, dec_algo);
if ( msg != dec )
throw new CryptographicException(string.Format("Plain and
decrypted did not match: {0}!={1}", msg, dec));
}
}
}