What is the difference between using Rfc2898DeriveBytes and just using Encoding.ASCII.GetBytes(string object);
?
I have had relative success with either approach, the former is a more long winded approach where as the latter is simple and to the point. Both seem to allow you to do the same thing eventually but I am struggling to the see the point in using the former over the latter.
The basic concept I have been able to grasp is that you can convert string passwords into
byte arrays to be used for e.g a symmetric encryption class, AesManaged
. Via the RFC class but you get to use salt values and password when creating your rfc object. I assume its more secure but still thats an uneducated guess at best! Also that it allows you to return byte arrays of a certain size, well something like that.
Here are a few examples to show you where I am coming from:
byte[] myPassinBytes = Encoding.ASCII.GetBytes("some password");
or
string password = "P@%5w0r]>";
byte[] saltArray = Encoding.ASCII.GetBytes("this is my salt");
Rfc2898DeriveBytes rfcKey = new Rfc2898DeriveBytes(password, saltArray);
The 'rfcKey' object can now be used towards setting up the the .Key or .IV properties
on a symmetric encryption algorithm class.
ie.
RijndaelManaged rj = new RijndaelManaged ();
rj.Key = rfcKey.Getbytes(rj.KeySize / 8);
rj.IV = rfcKey.Getbytes(rj.Blocksize / 8);
'rj' should be ready to go !
The confusing part ... so rather than using the 'rfcKey' object can I not just use my
'myPassInBytes' array to help set-up my 'rj' object?
I have tried doing this in VS2008 and the immediate answer is NO. But have you guys got a better educated answer as to why the RFC class is used over the other alternative I have mentioned above?
You really, really do not want to use a user password directly as a crypto key, especially with AES.
Rfc2898DeriveBytes is an implementation of PBKDF2. What it does is repeatedly hash the user password along with the salt. This has multiple benefits:
Firstly, you can use arbitrarily sized passwords - AES only supports specific key sizes.
Secondly, the addition of the salt means that you can use the same passphrase to generate multiple different keys (assuming the salt is not a constant, as it is in your example). This is important for key separation; reusing keys in different contexts is one of the most common ways cryptographic systems are broken.
The multiple iterations (1000 by default) slow down password guessing attacks. Consider someone who is trying to guess your AES key. If you just used the password, this would be straightforward - just try each possible password as the key. On the other hand, with PBKDF2, the attacker first has to perform 1000 hash iterations for each password guess. So while it slows down a user only slightly, it has a disproportionate effect on an attacker. (In fact it's quite common to use much higher iteration counts; 10000 is commonly recommended).
It also means the final output key is uniformly distributed. If you used the password, for instance, typically 16 out of 128 bits of the key would be 0 (the high ASCII bit). That right there immediately makes keysearch 65536 times easier than it should be, even ignoring the password guessing.
Finally, AES has specific vulnerabilities with related key attacks. Related key attacks are possible when an attacker knows some data encrypted with several keys, and there is some known (or guessed) relation between them. For instance, if you encrypted data with both a password-key of "My AES key sucks" (16 bytes, for AES-128) and with "MY AES KEY SUCKS", a related key attack might be possible. The currently best known attacks do not actually allow breaking the full AES in this way, but they have been getting progressively better over time - just last week a new attack was published that breaks 13 rounds (out of 14 total) of AES-256 using a related key attack. It would be profoundly unwise to rely on such attacks not getting better over time.