While we have left much about the field of cryptography unsaid, I hope that you've gained a good understanding of the basics of using the FCL classes for encryption. In summary, remember the following points:
- Always use proven, public technology
- Use Rijndael, if possible
- Use 256-bit keys and blocks
- Take care how you derive keys
- Use PKCS7 padding in .NET 1.1, ISO10126 in .NET 2.0
- Don't use ECB mode unless you have a good reason and know what you're doing
- Always use a unique IV for each message
- Take the time to be explicit in your code for important details, even when you're using defaults
Finally, here is the complete text of the CipherWrapper
class we developed in this article. Keep in mind that this code is provided for demonstration purposes only. I designed the code for simplicity and illustration foremost and I typically write more complex crypto code to accomplish such goals as to make the classes thread safe and useable from multiple sessions. These details, in my view, do not contribute to the subject at hand, so they were omitted. That stated, this class puts to work all the principles covered by this article. Take some time to study the documentation for the SymmetricAlgorithm
class, from which all the FCL ciphers derive, and the ICryptoTransform
interface, particularly the overloads for the CreateEncryptor
/Decryptor
methods.
class CipherWrapper
{
RijndaelManaged _cipher = null;
public CipherWrapper()
{
_cipher = InitCipher();
}
public CipherWrapper(byte[] key)
{
_cipher = InitCipher(key);
}
public byte[] Key
{
get { return _cipher.Key; }
set { _cipher.Key = value; }
}
public byte[] EncryptMessage(byte[] plainText, out byte[] iv)
{
_cipher.GenerateIV();
iv = _cipher.IV;
ICryptoTransform transform = _cipher.CreateEncryptor();
byte[] cipherText = transform.TransformFinalBlock(plainText, 0, plainText.Length);
return cipherText;
}
public byte[] DecryptMessage(byte[] cipherText, byte[] iv)
{
_cipher.IV = iv;
ICryptoTransform transform = _cipher.CreateDecryptor();
byte[] plainText = transform.TransformFinalBlock(cipherText, 0, cipherText.Length);
return plainText;
}
private RijndaelManaged InitCipher()
{
RijndaelManaged cipher = CreateCipher();
cipher.GenerateKey();
return cipher;
}
private RijndaelManaged InitCipher(byte[] key)
{
RijndaelManaged cipher = CreateCipher();
cipher.Key = key;
return cipher;
}
private RijndaelManaged CreateCipher()
{
RijndaelManaged cipher = new RijndaelManaged();
cipher.KeySize = 256;
cipher.BlockSize = 256;
cipher.Mode = CipherMode.CBC;
cipher.Padding = PaddingMode.PKCS7;
return cipher;
}
}
Kudos
Many thanks to Keith Brown for his review of this article. Keith provided many helpful suggestions and corrections.
This article was originally published at DotNetDevs.com
Comments