HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Rijndael for use in production systems

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
productionsystemsrijndaelforuse

Problem

I found an example of how to implement Rijndael.

This class uses a symmetric key algorithm (Rijndael/AES) to encrypt and decrypt data. As long as encryption and decryption routines use the same parameters to generate the keys, the keys are guaranteed to be the same. The class uses static functions with duplicate code to make it easier to demonstrate encryption and decryption logic. In a real-life application, this may not be the most efficient way of handling encryption, so - as soon as you feel comfortable with it - you may want to redesign this class.

Is this code secure enough for production systems?

```
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;

public class RijndaelSimple
{
///
/// Encrypts specified plaintext using Rijndael symmetric key algorithm
/// and returns a base64-encoded result.
///
///
/// Plaintext value to be encrypted.
///
///
/// Passphrase from which a pseudo-random password will be derived. The
/// derived password will be used to generate the encryption key.
/// Passphrase can be any string. In this example we assume that this
/// passphrase is an ASCII string.
///
///
/// Salt value used along with passphrase to generate password. Salt can
/// be any string. In this example we assume that salt is an ASCII string.
///
///
/// Hash algorithm used to generate password. Allowed values are: "MD5" and
/// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
///
///
/// Number of iterations used to generate password. One or two iterations
/// should be enough.
///
///
/// Initialization vector (or IV). This value is required to encrypt the
/// first block of plaintext data. For RijndaelManaged class IV must be
/// exactly 16 ASCII characters long.
///
///
/// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
/// Longer

Solution

This code uses obsolete PasswordDeriveBytes class, use Rfc2898DeriveBytes class instead (Thanks @tom for highlighting this issue):

Rfc2898DeriveBytes password = new Rfc2898DeriveBytes(
    passPhrase,
    saltValueBytes,
    passwordIterations);


Also, even though IV (initVectorBytes) may be publicly stored it should not be reused for different encryptions. You can derive it from pseudo-random bytes:

byte[] initVectorBytes = password.GetBytes(symmetricKey.BlockSize / 8);


Other than that encryption/decryption looks properly implemented, and I completely agree with original code writer that initialization/duplicate steps should be taken to constructor. It will reduce the number of parameters in Encrypt/Decrypt methods to one - actual payload.

Depending on your specifics you can also expose methods accepting and returning encrypting/decrypting streams for large encryption volumes if necessary.

Code Snippets

Rfc2898DeriveBytes password = new Rfc2898DeriveBytes(
    passPhrase,
    saltValueBytes,
    passwordIterations);
byte[] initVectorBytes = password.GetBytes(symmetricKey.BlockSize / 8);

Context

StackExchange Code Review Q#20608, answer score: 3

Revisions (0)

No revisions yet.