Rfc2898DeriveBytes and TripleDes - c#

I have now learnt that PasswordDeriveBytes is deprecated in favor of Rfc2898DeriveBytes.
Looking up Rfc2898DeriveBytes on MSDN. There is a code example that uses TripleDES.
But TripleDes is older and weaker than AES. Why have they seemingly taken one step forward and one step back?
Can one just replace the TripleDes with AES or is Rfc2898DeriveBytes intrinsically linked to TripleDes?

A password based KDF simply turns a password+salt into a sequence of bytes which you can use as key, or store as password hash.
It's in no way linked to your choice of cipher, you can use PBKDF2 together with AES. One minor issue is how much data you read from PBKDF2-HMAC-SHA-1. I recommend only reading 20 bytes, and using a separate hash to increase their size when that's needed.
There is no reason to follow MSDN examples. They often do not follow good coding practices. Just because they use 3DES doesn't mean you should.

PBKDF2 (Rfc2898DeriveBytes) is used to derive a key from a password (Key Derivation Function), the key length it generates and what you do subsequently are your choice, so use PBKDF2 to generate they key and use which ever symmetric cipher you like. To answer your question, there is no intrinsic link.

Related

Security of AES encryption with constant salt

I have an encoding application written in C# where users can optionally encrypt messages. I had been using the class in this answer, and it turns out I'm in good company because I found several places online that use the exact same code (one of which is Netflix's Open Source Platform).
However, comments to that answer (as well as later edits to that answer) led me to believe that this method was insecure. I opted to use the class in this answer to the same question instead.
How secure is AES encryption if you use a constant salt? How easily can this method be broken? I admit that I have very little experience in this area.
AES is a block cipher. A block cipher's input is a key and a block of plaintext. A block cipher is usually used in a block cipher mode of operation. All secure modes of operation use an Initialization Vector or IV. Otherwise identical plaintext would encrypt to identical ciphertext (for the same key), and this is leaking information.
Salt is not used by AES or modes of operation. It's usually used as input for Key Derivation Functions (KDFs), especially Password Based Key Derivation Functions (PBKDFs). Dot NET's Rfc2898DeriveBytes implements the PBKDF2 function as defined in - you'd guess it - RFC 2898: "PKCS #5: Password-Based Cryptography Specification Version 2.0".
If you use a static salt in a PBKDF2 then you would get the same key as output (for the same number of iterations). Now if you would ever leak the resulting key then all your ciphertext would be vulnerable. And if you would use multiple passwords then an attacker would be able to build a rainbow table; the PBKDF2 work factor would become less important; the attacker can simply build one table and then try all the resulting keys on all possible ciphertexts.
So, as the salt is not actually used for AES it doesn't make much of a difference for the security. It is however still a horrible sin, even worse than using the default iteration count for PBKDF2 / Rfc2898DeriveBytes.
Note that horrible security sins are committed by a large number of people on a daily basis. That there are many many many persons that get it wrong doesn't tell you that you are in "good company". That there are 289 upvotes just tells you that SO answers about cryptography should not be trusted based on vote count.
Salt is there for a reason.
This enables same input to be encrypted differently.
If an attacker would really insist, he can find some patterns that repeat themselves in encryption without salt, and eventually can get to your key more easily.
Still the attcker would have to work very hard.
Using constant salt equals to not using salt at all.
And it is highly recommended to use it, as it has no effect on the decryption process.

PasswordDeriveBytes function

I am using AES (Rijndael) symmetric-key algorithm to encrypt-decrypt data.
I am using the System.Security.Cryptography. PasswordDeriveBytes function;
PasswordDeriveBytes password = new PasswordDeriveBytes(
passPhrase,
saltValueBytes,
hashAlgorithm,
passwordIterations);
Looking this function up on MSDN etc, it does not tell you explicitly what parameters ‘hashAlgoritm’ can take.
There are examples on the internet of it taking SHA1 as well as SHA256. I experimented with this and found that it can take SHA512.
But without documentation, I have no idea if SHA512 is really better than SHA256 or SHA1 or even MD5.
Can anybody shed light on this issue?
The security of the hash method is slightly less important for a key derivation function. It's probably best to choose one that matches the required key size, although use of MD5 in general should be discouraged. Other applications may only use SHA-1 .
Note that PasswordDeriveBytes has been deprecated and should certainly not be used for output larger than the hash size. Use PBKDF2 istead, see Rfc2898DeriveBytes.

.NET: Difference between PasswordDeriveBytes and Rfc2898DeriveBytes

I'm trying to understand some C#-code, I have been handed, which deals with cryptography, and specifically uses PasswordDeriveBytes from System.Security.Cryptography.
In the .NET docs , it says that PasswordDeriveBytes uses "an extension of the PBKDF1 algorithm" which is later in the document specified as "the PKCS#5 v2.0 standard", which is PBKDF2 (as far as I can tell). Everywhere on the net I've found (including here on Stack Exchange), though, everyone says "use Rfc2898DeriveBytes, cause Password* is deprecated and uses PBKDF1". But the only difference in the docs at msdn.microsoft.com seems to be that the Rfc*-version specifically mentions PBKDF2, where Password* says "extension of PBKDF1" and "PKCS#5 v 2.0".
So, can anyone tell me what the difference is between the two classes (if any) and why I should use one rather than the other for PBKDF2 password key derivation?
Now, other code, that deals with the same data, explicitly uses PBKDF2, and works, so that would suggest that indeed PasswordDeriveBytes also uses PBKDF2, or that PBKDF2 is simply compatible with PBKDF1 under certain circumstances, but I want to know for sure that it's not some side effect of some random thing, and that things just magically works (and eventually probably will magically and spectacularly break) without anyone really understanding why.
If you instantiate PasswordDeriveBytes and make a single call to the GetBytes method passing a value which is smaller than the output size of the underlying digest algorithm then you get back a value from the PBKDF1 algorithm.
If you make two calls to GetBytes for the same object you may encounter a counting bug in the implementation.
PBKDF1 is only described to output up to the size of the hash algorithm (e.g. 20 bytes for SHA-1), but the PasswordDeriveBytes class has made up a formula to support up to 1000 times the hash output size. So a large value produced by this class may not be easily attainable in another platform.
If you instantiate Rfc2898DeriveBytes you get a streaming implementation of the PBKDF2 algorithm. The most obvious difference of PBKDF2 over PBKDF1 is that PBKDF2 allows the generation of an arbitrary amount of data (the limit is (2^32-1)*hashOutputSize; or for SHA-1 85,899,345,900 bytes). PBKDF2 also uses a more complex construction (in particular, HMAC over direct digest) to make recovering the input password from an output value more difficult.
The "streaming" in the implementation is that the concatenation of GetBytes(5) and GetBytes(3) is the same as GetBytes(8). Unlike in PasswordDeriveBytes, this works correctly in Rfc2898DeriveBytes.
PBKDF1 was originally created to generate DES keys, published in PKCS #5 v1.5 in 1993.
PBKDF2 was published in PKCS #5 v2.0 (which was republished as RFC2898) in 1999. A slide deck which should be found at ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-5v2/pkcs5v2-0.pdf (but seems to be having issues so ftp://ftp.dfn-cert.de/pub/pca/docs/PKCS/ftp.rsa.com/99workshop/pkcs5_v2.0.ppt may hve to do) further summarizes differences. (The slide deck was written by RSA Security, the creators of PBKDF1 and PBKDF2, and they are the people who recommend PBKDF2 over PBKDF1).
I think a great answer to this would be found here:
C# PasswordDeriveBytes Confusion
But to sumup:
Microsoft's implementation of original PKCS#5 (aka PBKDF1) include insecure extensions to provide more bytes than the hash function can provide (see bug reports here and here).
Even if it was not buggy you should avoid undocumented, proprietary extensions to standards (or you might never be able to decrypt your data in the future - at least not outside Windows.)
I strongly suggest you to use the newer Rfc2898DeriveBytes which implements PBKDF2 (PKCS#5 v2) which is available since .NET 2.0.
Here's a blog post detailing the differences:
http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/generating-a-key-from-a-password.aspx
PBKDF2 can be used to generate keys of any length, which is very useful for password-based encryption (it can generate any key length as required by the symmetric cipher) but means less for secure password storage. It also applies the salt using HMAC instead of concatenation like PBKDF1, which has better security properties in cases of weak salts.
PKCS#5 v2.0 defines both PBKDF1 and PBKDF2, the former for reasons of backwards compatibility and also recommends you use PBKDF2 for new applications. I've no idea why the latter is better than the former, but the two .NET classes do seem to use different but interoperable algorithms. (Possibly because only the resulting key is being exchanged, not the inputs + KDF.)

RNGCryptoServiceProvider and Rfc2898DeriveBytes

Does it make sense to run a encryption key (2048 bit) generated with the RNGCryptoServiceProvider through Rfc2898DeriveBytes.GetBytes() or is Rfc2898DeriveBytes more geared toward generating encryption keys from shorter keys like passphrases?
Rfc2898DeriveBytes.GetBytes() is mainly used for getting a key of the right size with your encryption chipper size. If you're sure that your key is secure this is not needed (and of course if the key sizes match). If it's a user input (i.e. a passkey), than definitely use Rfc2898DeriveBytes class to derive a proper key (or use hashing with salt).
If you already have something suitable for a key, which it appears you have, why would you use it to generate another key? Personally I don't see any benefit putting it through derived bytes as you already have a cryptographically secure random number.

C# and Delphi. Read a XML Encrypted and zipped in Delphi with C#

We have an encryped, and then zipped file of a XML document. This file is encrypted in Delphi with a package called 'DcpCrypt', using Rijndael and SHA256:
fRijndael:=TDCP_rijndael.Create(nil);
fRijndael.BlockSize:=16;
fRijndael.CipherMode:=cmCBC;
fSHA256:=TDCP_sha256.Create(nil);
fSHA256.HashSize:=256;
Is C# capable of uncrypting this? I've googled a lot and it seems that DcpCrypt calculates his Keys different than the .NET lib does.
Many thanks in advance
The short answer is yes. The long answer is "it depends".
By the words "calculates his keys", I assume you mean generate the encryption keys. How the keys are generated is completely irrelevant to the process of using thos keys for encryption and decryption.
DcpCrypt was written before Rijndael became the AES standard (that's a long time ago). Assuming that the pre-standard Rijndael implementation is the same as AES (it probably is), AES encryption/decryption interoperability should be language and implementation neutral, only dependant on the implementation options.
But here is the rub ... identifying those options and setting them to be the same on both the encryption codec and the decryption codec can be tricky.
What are the options?
Chaining mode;
IV
How is the message salted? if at all?
Termination: AES does not specify the blocking scheme for non-key-streaming chaining modes.
In general, with ciphers other than AES, you may also have an issue with specifying how the keys are encoded - but this shouldn't be a problem with AES.
Once you identify all the options that the encryptor uses, you must apply those same options to the decryptor. This problem is not specific to Rijndael/AES but is universal to all ciphers.
By the way, if you are zipping for the purposes of compression, encryption following by zipping is pointless. Zip will not compress any file whose contents are already maximally random, such as ciphertext.
I recommend you use TurboPower LockBox 3 to encrypt in AES, rather than DcpCrypt. Dave Barton's DCPcrypt was good in it day, but it's not up to date with standards, and it doesn't manage IV's safely.
What are the options if you use LockBox? If you use LockBox 3's AES codec with CBC mode, salting and IV are managed by setting the IV to a nonce and pre-emitting it. For messages longer than one block, blocking is achieved by ciphertext stealing. For messages shorter than one block, the chaining mode is forced to 8-bit CFB, which is key-streaming.
Also your comment about encrypting the file with SHA256 doesnt make sense. SHA is a hash, not a cipher.

Categories