First, I confirmed that Rfc2898 and PBKDF2 are the same thing. Then, as stated above, the problem appears as .net-ism. I found on msdn
that the implementation of GetBytes inside Rfc2898DeriveBytes changes with every call, i.e. he has a fortune. (see comments about half the page)
An example in Python (pseudo output):
derived_key = PBKDF2(key, salt, 32, 1000) iv = PBKDF2(key, salt, 16, 1000) print(base64.b64encode(derived_key)) print(base64.b64encode(iv)) $123456789101112134== $12345678==
The same (ish) code in .NET (again, pseudo output):
var rfc = new Rfc2898DeriveBytes(key, saltBytes); using (var cryptoProvider = new AesManaged()) {
Subsequent calls to rfc.GetBytes always give different results. MSDN says it combines key call sizes. Therefore, if you call GetBytes (20) twice, it is the same as calling GetBytes (20 + 20) or GetBytes (40). Theoretically, this should simply increase the size of the key, and not completely change it.
There are several solutions to this problem that can generate a longer key on the first call, and then cut it both into the derived key And IV, and randomly generate IV, adding it to the encoded message and decoupling it before decrypting it.
Python output slicing gives the same results as .NET. It looks like this:
derived_key = PBKDF2(key, salt, 32, 1000) iv = PBKDF2(key, salt, 32 + 16, 1000)
Enjoy,