9

Mainly I'm trying to understand how to correctly create the Key and IV for use with the .NET Implementation of AES (AesManaged class).

This encryption code will be used in conjunction with existing customer records in a database.

Here is the process that I've come up with. First, get the key from an encrypted web.config and get a byte array using the Rfc2898DeriveBytes class. The salt is a constant.

public static byte[] GetKey(string key)
{
    var deriveBytes = new Rfc2898DeriveBytes(key, _salt);

    return deriveBytes.GetBytes(32);
}

Next, generate another byte array for the IV given the User's ID and the same salt from above. This method is essentially the same, but returns an array with 16 bytes instead of 32 (and the input is the User ID, not the key).

public static byte[] GetKey(string text)
{
    var deriveBytes = new Rfc2898DeriveBytes(text, _salt);

    return deriveBytes.GetBytes(16);
}

Given the Key and the IV I use a CryptoStream to encrypt the data:

var aesAlg = new AesManaged();

// Create an encryptor to perform the stream transform.
var encryptor = aesAlg.CreateEncryptor(key, iv);

// ... Code that uses the Crypto Stream

Main question(s):

  • Is there a better/different class that I should be using instead of Rfc2898DeriveBytes? It seems funny that the class name references an RFC.
  • Is the use of a constant salt bad? I'm doing this so that I don't need to store any additional information on the User record. Other examples I've seen use a constant IV, but a random Salt. Are those 2 scenarios essentially the same?
John B
  • 193
  • 1
  • 2
  • 7

1 Answers1

10

Cryptographically speaking, AesManaged uses AES in CBC mode. To ensure this operates securely, you need to choose the IV randomly, i.e. it should not be possible to predict the IV between iterations. This question has a discussion of non-random IVs: Using a Non-Random IV with modes other than CBC and this SO question: Why is using a Non-Random IV with CBC Mode a vulnerability? has a discussion about the chosen plaintext vulnerability using non-random IVs.

According to the documentation, Rfc2898DeriveBytes implements PBKDF2, a key stretching function. DeriveBytes is an interesting choice of name, but that's essentially what it'll do - output some bytes from the PBKDF2 algorithm. At its heart, PBKDF2 is a repeated application of SHA1; if you input the same passphrase and IV, you'll end up with the same encryption key.

Unlike a hash, you're not going to be storing this anywhere, as it is your secret key for your symmetric operation, so there's less risk of an attacker trying to find a preimage (recover the passphrase) mostly because they just don't need to. So the uniqueness requirement looks unnecessary - however, hypothetically speaking let us assume for a minute all your users use the same passphrase "I love asking crypto questions on SE". If they do this and you're using a constant salt, they'll have the same key. Non-repeating IVs for our CBC mode will mitigate the problem slightly, but it would be a lot better if the keys weren't all the same in the first place.

So, summary:

  • Constant Salt: bad. Pick a large salt, unique per user. Randomly picking salts will help you achieve this - if you generate a 64-bit salt that gives you a total possible output space of $2^{64} = 18446744073709551616$, or approximately $2635249153$ unique salts per human being right now. So you are not likely to run out, and guarantee that all your user's keys are unique assuming no collisions in PBKDF2.

    Edit thanks to fgrieu - the salt size must be 8-bytes (64-bits) or larger. If you can accommodate larger salts, you should, to avoid birthday attacks. For more information, see the comments.

  • Constant IV: bad. You definitely want a random IV for CBC mode.