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.)
Related
In most cases I need to encrypt a string with a password and then send/save it somewhere. Later I want do decrypt it with the password. I am not encrypting nuclear missile codes or medical patient data! The ideal would be 2 functions:
string Encrypt(string plainText, string password);
string Decrypt(string cipherText, string password);
I had a look at the crypto documentation... Oh boy! So I try to code the above calls myself (see a proof of concept using AES Managed and Base64 encoded payload). I am no crypto expert, why do I have to code that? I probably did somethings wrong...
To derive the key from the password the interface requires a salt. Can I use the password as salt? Can I re-use the IV as salt? Maybe not, but I don't want to add another parameter.
Can I use a fixed IV? Same plaintext and password should result in different cipher text, so I have to supply the IV for decryption in the payload.
Can I use a salt for the key and keep the IV constant instead? Feels wrong.
Creating a nonce and deriving IV and key salt from it is a valid approach?
If .Net would support the GCM mode would I still have this problems?
The .NET crypto API exposes a general purpose encryption library, containing object oriented approaches to implement cryptographic algorithms. Of course, to use these algorithms and algorithm implementations you need to have a good grasp on cryptography, which you currently lack.
This general purpose library is required to implement the various protocols that exist out there. Usually a single algorithm doesn't fulfill a specific use case (encrypt a string using a password, returning a different string, in your case). So a protocol needs to be chosen or devised that does fulfill that use case. This protocol may e.g. define a container format such as CMS or PGP, which can for instance be used to encrypt emails (the use case).
You're directly trying to apply cryptographic algorithms to solve your use case. That's not going to work. You need a pre-made protocol, preferably with a pre-made API.
Note that there are many different use cases, many different protocols and even more opinions on how to create and implement those correctly. Libsodium / NaCl for instance defines a small container format called SecretBox that does take some of the work from you.
However, it would of course be rather impossible to implement TLS on top of NaCl, as the functionality / algorithms are just not there. Again, .NET needs a generic crypto library like the .NET API for others to implement their protocols.
So either you'll have to byte the bullet and try to create your own protocol or you take an existing one and take an educated guess if it is secure (hopefully the protocol has been reviewed / updated a few times). Stay away from single person projects without additional contributors (like the many sample codes out there without review).
For your own protocol, yes, there are mistakes such as not storing the salt with the ciphertext. You need a random - or at least unique - salt to be secure, reusing the password for that is certainly not secure. Don't let it become a single person project itself and either borrow a protocol or have it reviewed.
OK, quickly then:
To derive the key from the password the interface requires a salt. Can I use the password as salt? Can I re-use the IV as salt? Maybe not, but I don't want to add another parameter.
No, the salt needs to be unique and preferably random; the password / salt combination should be unique (it should not repeat, not even in time, or over different domains).
Can I use a fixed IV? Same plaintext and password should result in different cipher text, so I have to supply the IV for decryption in the payload.
No, unless the key changes value each time (see above). For CBC the IV should be unpredictable unless you use a fresh key each time.
Can I use a salt for the key and keep the IV constant instead? Feels wrong.
That's possible, as long as you don't repeat the salt.
Creating a nonce and deriving IV and key salt from it is a valid approach?
That depends on very specific details. In other words, I would not try it if you don't exactly know what you're doing.
If .Net would support the GCM mode would I still have this problems?
Absolutely, and in a sense your problems would be worse if you'd use GCM, as using GCM with the same key and IV is completely broken.
Remember, GCM is just an algorithm, not a protocol, it cannot solve your use case by itself.
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.
I need to port MACTripleDes functionality to another programming language and want to know what it really does.
So I have data and a keypharse given.
Is it right, to just TripleDes the data with an IV=0 and the keyphrase, and then take the last 8 byte as the MAC ?
Ciao
Ephraim
DO NOT WRITE YOUR OWN CRYPTOGRAPHIC FUNCTIONS! Not even a direct port of an existing function.
If your language has any maturity, it will have an open source implementation that you can use. If it does not, DO NOT PORT ONE! Find one in another language and write a wrapper for it that you can call (like the C# implementation that you want to port).
Any existing open source implementation will be tested and verified for correctness by people who know far more about cryptography than me, you and over 99% of the global developer population.
If you really cannot find an open source implementation, write a simple .exe using C# that calls the C# implementation and returns the result. Not including setup and boilerplate, that's basically one line of code.
Again, if you write your own implementation, you will inevitably fail to account for some edge case or not understand the algorithm enough, resulting in a dangerous piece of code with exploitable flaws. Unless you are one of the original developers of 3DES or have many years of experience developing currently used encryption standards, you simply do not have the technical skill to port an implementation.
Again, if you write your own implementation, something goes wrong and your data gets leaked, you can and will be held personally accountable. Linkedin was recently sued for $ 5 million because they didn't implement proper security. This is something that can break your career.
DO NOT MAKE THE SAME MISTAKE AS LINKEDIN!
Apparently, the MACTripleDES class implements CBC-MAC using Triple DES as the underlying block cipher. If you have access to a crypto library that implements CBC-MAC and Triple DES (and lets you use the latter as the block cipher in the former, as any generic CBC-MAC implementation should), you should be able to combine them to obtain an equivalent MAC.
Alternatively, if your crypto library does not directly implement CBC-MAC, but does implement CBC mode encryption, you can indeed implement CBC-MAC yourself by encrypting the message in CBC mode, using an all-zero IV, and taking the last block of the resulting ciphertext as the MAC value. (This is simply the definition of CBC-MAC.) It is also not particularly difficult or tricky to implement CBC mode (or CBC-MAC) yourself, using just the raw block cipher. But really, any decent crypto library should already provide CBC-MAC, or at least CBC mode encryption, built in.
What you should not try is implementing Triple DES, or any other block cipher, yourself! It's very hard to implement low-level crypto algorithms like Triple DES securely, since you have to pay attention to things like side-channel attacks, and any such implementation should be thoroughly tested and scrutinized by professional cryptographers before being used for anything serious.
(One specific exception here is that, if you only have access to the plain DES block cipher, you may reasonably safely implement Triple DES on top of that. This is because Triple DES is not actually a separate low-level cipher, but simply a method of expanding the keyspace of DES, at the expense of performance, by encrypting each block several times with independent keys. But again, any decent crypto library written in the last 20 years should support Triple DES if it supports DES at all.)
Of course, even when only implementing high-level crypto algorithms like CBC-MAC, it's still possible to make mistakes, and such mistakes can have security consequences. But at this level, the difficulty and the risk are not significantly greater than those inherent in simply using crypto (and therefore, by implication, working with security-critical data like encryption keys) in the first place. Even so, it's always a good idea to have someone (or, preferably, several someones) with crypto experience review your code before it's deployed. This holds even if you're a crypto expert yourself; anybody can make mistakes, and the more eyeballs you can get on your code, the more likely it is that any mistakes are found before someone exploits them.
Finally, note that, if you don't specifically need compatibility with Microsoft's MACTripleDES class, there are better choices for MAC algorithms than CBC-MAC (such as CMAC), and better choices for ciphers than Triple DES (such as AES). The specific combination of AES and CMAC is even standardized in RFC 4493, which provides detailed implementation instructions and test vectors to verify correctness.
In particular, plain CBC-MAC is not secure for variable-length messages, if the message length is not authenticated. While there are ways to fix this vulnerability, e.g. by prepending the length to the message before computing the MAC, it's generally preferable to use an algorithm that is secure "out of the box", like CMAC.
(Also, since you mention a "keyphrase" in your question, I hope you're actually feeding it through a proper key derivation function before using it as a key for Triple DES (or any other block cipher). In particular, if the keyphrase is user-supplied, and thus likely to have low entropy, you really should be using a key-stretching KDF like PBKDF2, scrypt or Argon2.)
I have a password hashing mechanism based upon Rfc2898DeriveBytes (based on code detailed here: http://crackstation.net/hashing-security.htm). Internally, this class utilizes SHA1 which - the CrackStation link does indicate the SHA1 is "old", but also states that, although Rfc2898DeriveBytes uses it internally, Rfc2898DeriveBytes is still a good mechanism.
The security department of a customer of mine has heard that that "SHA1 has been compromised" (specifically, that, for purposes of signing a document for transmission across the internet, SHA1 has been defeated, under certain circumstances - the fact that this "vulnerability" does not apply to a password hash is immaterial to the security department). As a result, they have demanded that we alter our password hashing mechanism to employ SHA2.
Currently, the .Net framework has no equivalent of Rfc2898DeriveBytes that employs SHA2 (or SHA256, etc.) internally. I know that I can use reflection to get at the source code for this class and change it, but I've always been told that the first rule of encryption is "don't grow your own".
This is principally a political demand by my customer, not a technical one, which could be easily satisfied by running the password through a SHA2 hash prior to running it through Rfc2898DeriveBytes. However, I am not sufficiently knowledgeable about cryptography to know if this might be bad - might in fact result in an objectively less secure password hash.
Does anyone know of an Rfc2898DeriveBytes equivalent class that employs SHA2? Or, does anyone know if running the password through a SHA2 hash prior to Rfc2898DeriveBytes would be perfectly safe?
Download the free code samples from "SecurityDriven.NET" book. Find the PBKDF2 class which takes an HMAC factory. Available factories include SHA2 (256, 384, 512).
Running the password through SHA2 hash prior to Rfc2898DeriveBytes is not the right thing to do, even if this is unlikely to be the weakest part of whatever you're doing (you'd be losing password entropy).
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.