Securing users passwords using c# - Rfc2898DeriveBytes vs SHA512 - c#

I've been reading about securing users passwords in the database (https://crackstation.net/hashing-security.htm). The basic idea is understood - generate a random Salt, append it to the password and hash the password.
So here's what I did (I didn't put here some methods that do conversion to strings):
RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create();
byte[] rndBytes = new byte[512];
randomNumberGenerator.GetBytes(rndBytes);
string salt = ToHexString(rndBytes);
var sha512Hasher = SHA512.Create();
string hashedPwd = ToHexString(sha512Hasher.ComputeHash(GetBytes(pwd + salt)))
According to the article this is secured but can be even more secured by using "key stretching" which for my understanding is hashing that done slower (using a parameter) to make brute-force the password harder.
So here's what I did:
RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create();
byte[] salt = new byte[512];
randomNumberGenerator.GetBytes(salt);
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(user.Password, salt, 1000);
byte[] hashBytes = k1.GetBytes(512);
string hash = ToHexString(hashBytes);
Now here are my questions:
What is the difference between SHA512 and Rfc2898DeriveBytes? which is more secure?
Should I have smaller salt with more iterations? Will it make it more secure?
On a 1000 iterations it runs very fast - how slow should it be? half a second? a second? What is the rule of thumb here?
On the database - should I convert the byte array to string and store strings or should I store the byte array in a binary data field?
Edit (another questions)
If I iterate a 1000 times over rehashing SHA512 - does it give the same security?

What is the difference between SHA512 and Rfc2898DeriveBytes?
SHA512 is a cryptographic hash function, while Rfc2898DeriveBytes is a key-derivation function. As you already wrote, hash functions are too fast and can be brute-forced too easily, that's why we need functions with a cost factor like BCrypt, SCrypt, PBKDF2 or Argon2. As far as i know, Rfc2898DeriveBytes implements the PBKDF2 using a HMAC with SHA1. This answers your other question that an iterated SHA is less secure than Rfc2898DeriveBytes.
Should I have smaller salt with more iterations?
Salt and cost factor are not related and have different purposes. The salt prevents the usage of rainbow tables, the iterations are a counter measure for brute-force attacks. More infos you can get from my tutorial about safe password storage. So no, don't make the salt shorter.
how slow should it be?
Of course this depends on your server and your requirements for security, slower means harder to brute-force. A rule of thumb is about 50 milliseconds for a single hash.
On the database - should I convert the byte array to string?
This is up to you. Strings are easier to handle for backups, migration and debugging, while byte arrays need less space in the database. Maybe you should also have a look at BCrypt.Net, it generates strings as output which contain the salt and are easy to store in a single database field [string].

Related

Password hashing different salt with same username

We introduced password encryption to our site.
The salt is calculated as shown below:
Rfc2898DeriveBytes hasher = new Rfc2898DeriveBytes(Username.ToLowerInvariant(),
System.Text.Encoding.Default.GetBytes("Wn.,G38uI{~6y8G-FA4);UD~7u75%6"), 10000);
string salt = Convert.ToBase64String(hasher.GetBytes(25));
For most usernames the salt is always the same.
But for some usernames it changes at every call.
Can someone tell me what we are doing wrong?
Assuming you're using RFC2898DeriveBytes to hash the password itself as well, then #CodesInChaos is correct, what you're doing wrong is:
Building the salt based off the username, instead of using a cryptographic PRNG to generate a fresh salt for each user.
You should use something like the .NET RNGCryptoServiceProvider Class to generate 8 to 16 (binary) bytes of random salt
For instance, from Rfc2898DeriveBytes Example 1
byte[] salt1 = new byte[8];
using (RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with a random value.
rngCsp.GetBytes(salt1);
}
The salt should then be stored in the clear in your database alongside the password hash and iteration count (so you can change it), and probably a version code too (so you can change it again, i.e. your current calculated salt method is version 1, and the random salt is version 2).
Spending 20,000 iterations of PBKDF2 on the salt, rather than spending it on the actual password hash!
10,000 iterations for the first 20 bytes, since RFC2898DeriveBytes is PBKDF2-HMAC-SHA-1, and SHA-1 has a native 20 byte output
10,000 more iteration for the next 20 bytes, which is then truncated to only the 5 you need to get to a 25 byte output.
This is a weakness, as the defender has to spend the time on the salt on every login, whether it's spent on the salt, or the password hashing. The attacker has to spent that time once for each username, and then they are going to store the results and try _illions (where _ is very large) of password guesses.
Thus, the attacker has a greater than normal marginal advantage because they can precalculate the salt, while you have to calculate it on the fly.
If you aren't using RFC2898DeriveBytes, another PBKDF2 implementation, BCrypt, or SCrypt to do the actual password hashing, then that's what you're doing wrong.
Trimming the username some, but not all of the time is entirely incidential; just make sure not to trim passwords before they're hashed.

Passwords hash protection against "Rainbow tables" reverse engineering with password padding

I've come across this article describing the dangers of storing "unsalted" password hashes in the database that could be subject to reverse engineering with the use of so-called "Rainbow tables".
It also comes with this C# code sample that basically requires storing two hash columns in your user passwords database table (instead of a traditional - one.) The issue of such approach for me is that I already have an established database table with unsalted user password hashes, and adding a new column will require restructuring of the database. So before I do that, I was looking for a different alternative and here's what I came up with.
Here's the function that instead of plainly calculating the SHA1 hash on a password pads it with a long sequence of pseudo-random (but consistent) data and then calculates the hash:
byte[] computeSecureHash(string strUserPassword)
{
//RETURN: = SHA1 byte array on the 'strUserPassword'
//Make simple junk array based on the password
ushort v = 117;
byte[] arrJunk = new byte[24];
for (int c = 0, i = 0; i < arrJunk.Length; i++)
{
v ^= strUserPassword[c++];
v *= 7;
arrJunk[i] = (byte)v;
if (c >= strUserPassword.Length)
c = 0;
}
//Make crypto byte array based on the password
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(strUserPassword, arrJunk);
pbkdf2.IterationCount = 1000;
byte[] arrCrypto = pbkdf2.GetBytes(128);
//Pad actual password
string strUserPassword_Padded = "";
const string strChars2Use = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`-=[]\\;',./~!##$%^&*()_+{}|:\"<>?";
int nHalfArrCrypto = arrCrypto.Length / 2;
//Left side
for (int i = 0; i < nHalfArrCrypto; i++)
{
strUserPassword_Padded += strChars2Use[arrCrypto[i] % strChars2Use.Length];
}
strUserPassword_Padded += strUserPassword;
//Right side
for (int i = nHalfArrCrypto; i < arrCrypto.Length; i++)
{
strUserPassword_Padded += strChars2Use[arrCrypto[i] % strChars2Use.Length];
}
//For user's password "123"
//the 'strUserPassword_Padded' becomes:
//"bwDR]_B>H5t-k:eIq?r_wGBWqWfs#tcAE~DQ5?(Pbj#<+Cw:9(r!B[f_.S<pCjn-123b9l3<Sz^D~>G}v)?NuHT4BZ-pI2$W[kW1e4KO\"`rTg3H`}&jmtrFh1J5c72:})tQ"
//And now compuse SHA1 on the padded password
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] bytesInputData = System.Text.Encoding.UTF8.GetBytes(strUserPassword_Padded);
return sha1.ComputeHash(bytesInputData);
}
So my question is, can someone review this code and tell me what are the dangers of doing it this way vs. what the author suggested in his code? In case of my code sample, I'll have to store only one hash in the database instead of two (password hash + salt hash.)
A salt that's solely derived from the password is close to pointless; you've just created a slightly different (but constant) hash function overall. A single rainbow table (albeit a custom one) could be used to target your entire database.
Furthermore, if a salt is derived from the password then identical passwords show up as identical "password hashes". Easy passwords will likely show up as duplicates - in effect you are generating your own rainbow table.
The whole point of storing a unique, independently-generated salt for each password is so that every single password is hashed with a unique hash function. Therefore there would be no single rainbow table that could be used across your entire database.
This will only partially mitigate the problem. What you have done is essentially created a keyed hash function.
With such a function general rainbow tables will no longer be applicable, but you are still in danger if an attacker gets ahold of your entire database. In this case, he can create a new rainbow table based around this random string. Using this new table he has a high chance of breaking into at least one account in your system.
Adding a separate salt is the equivalent of using a different hash function for each password, thus you would need a separate rainbow table for each possible salt, making the attack extremely expensive. If an attacker creates a rainbow table for one salt he only can break passwords that salt.
Also, I wanted to point out that it doesn't matter how much "static" randomness you add if the randomness remains constant.
The junk is derived from password so it doesn't have a salting effect, a rainbow table can still be generated that could be applied to your entire table.
But if you want to use just one column the answer is simpler:
Just use pbkdf2 to make your hash directly, make a 64 bit (8 byte) random salt, Use a higher iteration count (4000-10000). If you column can only hold 160 bits (20 bytes) then generate 12 bytes (if your column can hold more i'd up it more to 24 bytes) and store in your column salt + hash concatenated.
Thus when you are comparing you just read out the first 8 bytes to get your salt.
You can always take the current databases hashed passwords and hash them again with a different hash algo+salt, just as if they were the original password. It is perfectly safe to layer hashing on top of hashing, in fact it's often more safe this way. Keep in mind though that you also have to be able to reverse the process or you will break things.
restructuring of the database to just add an salt field is better option (or the only one really if your going to do it properly, but you could use your currant hash field to store the salt, as other person posted)
when they next log in with an valid user name and password (as this is only when the password hash should change or you do mass force change password on every one) if there is no Salt data then generate large random salt save it and regenerate the hash from the password+salt (ideally using something better then SHA1, pbkdf2 needs to be set higher then 10,000 but depends on your server resources)

Is it ok to derive initialization vector from password (as with key), given the salt will be random?

Cryptography gurus please help.
I've learned that encryption key with symmetric algorithms (e.g. AES) should be derived from password via the PBKDF2 function, using the random salt in each encryption. I've also learned that IV should not be hard-coded, or directly bound to (derived from) password string or encryption key. Until now I was generating both key derivation salt and IV randomly, 16 bytes each for my AES-256 encryption, and storing them along with encrypted payload.
Now I'm thinking random-generation of IV is redundant, if I use random salt, as I can derive both key and IV from password string with that salt. Or maybe I shouldn't?
So my question is ultimately this:
Can I derive initialization vector from password (as I do with key), or should I generate random IV each time, given the fact that I use random salt in each encryption?
So can I use the below C# code?
// Derive key and initialization vector from password:
// ---> NOTE: _salt is random 16 bytes in each encryption.
byte[] key, iv;
using (Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(password, _salt, _iterations))
{
key = derivedBytes.GetBytes(32);
iv = derivedBytes.GetBytes(16);
}
Yes you can use it that way, as long as you never ever use the same salt for the same password (even in time) to calculate the key and IV. The IV only has to be unique when you encrypt with the same key, and you would calculate a new key each time. In principle you could even use an all zero IV, as the key is never repeated, but you are better off using a derived one.
Note that if one of your colleagues decides that PasswordDeriveBytes - the broken implementation of PBKDF1 from Microsoft - would be better suited for the task, then you may very well be vulnerable to all kinds of attacks. This is just an example what can go wrong if your security margins are tight...
Fully random IV's should certainly be preferred.
What do you mean " using the random salt in each encryption"? It is best to derive the salt and IV randomly, such as the output from a cryptography standard random number generator and store it with the derived bytes. Generate a new IV and salt for each password.
Why from a cryptography standard RNG? Deriving from the password means any weakness in the derive bytes function is reflected in both the bytes and the IV. It is not difficult in modern programming languages to generate it from a RNG and using a RNG ensures the IV for new passwords encrypted is not predictable. There are probably better reasons but I am drawing a blank.
The more links there are between different parts of any crypto system then the easier it will be for any attacker to use those links as a back door from one part of the system to another. Remember that the IV is sent in the clear while the key must be kept secret, so any sort of link between them is a huge risk to take.
Use Rfc2898DeriveBytes to generate your key and use a good crypto RNG to generate the IV. Remember that the attacker will see the IV so there is no need to go through the full RFC 2898 process. Use the standard crypto RNG for the IV that will probably be faster than the RFC 2898 process because it does not have the iterations.
The most important part of semantic security for the initialization vector when using AES-CBC is that it should not be predictable.
With your suggested implementation a given key will always have the same initialization vector, but you wouldn't be using the same keys because of your 128 bit salt. Seems pretty unpredictable, that said, it's not a best practice, and generally when you do something clever to save 16 bytes of space your are losing some security of some sort or opening yourself up to some unknown attack vector.
I think you should use RNG and take the space 16 byte hit, being conservative is the name of the game when dealing with encryption. There are other things such as authenticated encryption that you should probably look into as well, I have an example implementation on codereview.
Ultimately there are other things that are important that provide additional overhead beyond the iv for security such as authenticated encryption, versioning, and keyrotation, and there really haven't been any high level encryption frameworks for C#. I've been working a C# implemenation of Google's Keyczar framework. You can follow it, if you like, on github Keyczar-dotnet. It's pretty much feature complete, and has 90% test coverage, but conservatively, I wouldn't recommend using it until it gets officially accepted as part of the project, and then will likely have a larger group of eyes on it in the future.

Is it ok to use SHA1 hash of password as a salt when deriving encryption key and IV from password string?

I'm using Rfc2898DeriveBytes to securely generate encryption key and initialization vector from user-supplied string password, to use with symmetric encryption (e.g. AesManaged).
I'm taking the SHA1 hash of password as a salt parameter to Rfc2898DeriveBytes. Is that ok? If not, then where should I get the salt from? I will need the same salt when decrypting, right? So I have to store it somewhere unencrypted - unsecured. If I have to store it securely, then it just becomes another "password", isn't it?
void SecureDeriveKeyAndIvFromPassword(string password, int iterations,
int keySize, int ivSize, out byte[] key, out byte[] iv)
{
// Generate the salt from password:
byte[] salt = (new SHA1Managed()).ComputeHash(Encoding.UTF8.GetBytes(password));
// Derive key and IV bytes from password:
Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(password, salt, iterations);
key = derivedBytes.GetBytes(keySize);
iv = derivedBytes.GetBytes(ivSize);
}
I've seen using the constant (hard-coded) salt, and I've seen people complaining about it. I thought deriving salt from password would be the better idea, but I'm not sure this is an optimal solution.
Shortly, I have a file that needs to be encrypted, and password string input by user. How do I properly use Rfc2898DeriveBytes to derive secure encryption key and IV?
Thanks.
EDIT:
Thanks for your answers. I now understand that the main (maybe only?) purpose of salt is to make generation of rainbow tables impossible - you can't pre-generate the hash of "P#$$w0rd" because it will have a different hash for each possible salt value. I understand this perfectly, BUT... Is this really relevant to symmetric encryption? I'm not storing the hash anywhere right? So even if the attacker has the rainbow table for all possible password combinations, he can't do much, right?
So, my question now is: Is there any advantage of using the random salt in each encryption operation, compared to using password-derived (or even hard-coded) salt, when used with symmetric encryption algorithms (like AesManaged of .NET)?
A salt should be unique for each password, that means create a random password for every password you want to hash. The salt is not a secret and can be stored plain text with your calculated hash-value.
The idea of the salt is, that an attacker cannot use a prebuilt rainbowtable, to get the passwords. He would have to build such a rainbowtable for every password separately, and this doesn't make sense. It's easier to brute-force, until you found a match.
There is an example in MSDN where the salt is gotten from the random source of the operating system. This is the best you can do, to get a safe salt, do not derrive it from your password.
A salt is designed to protect against multi-target attacks by making each target behave differently. Rainbow tables are just one particular incarnation of multi-target attacks, where the computational effort is expended before you obtain the targets.
There are situations where multi-target attacks are applicable, but rainbow tables are not.
One example of this: Assume you're using an authenticated encryption scheme with semantic security, such as AES-GCM with unique nonces. Now you've obtained a million different messages encrypted using different password.
If you use no salt, to check if a password applies to any one of these, the attacker needs one KDF operation, and one million decryption operations. If you use a salt, the attacker needs one million KDF operations and one million decryption operations. Since the KDF is slow compared to the decryption, an attack against the first scheme is much faster than an attack on the second scheme.
I don't really know what is Rfc2898DeriveBytes but I can tell you the following: salt doesn't has to be secured. Now, you said you have seen people complaining about hard-coded, constant values for salt, and whoever said that is right. Salt should be a random value, never a constant one, otherwise its purpose is defeated.
Do you understand what salt is used for? You clearly don't. Using the hash as salt is a bad idea because password X will always be salted with the same value Y, again, defeating its purpose.
People dislike hard-coded salts as they are accessible to all developers of the project (and possibly the public in the case of open source projects or reverse engineering). Attackers can then compute rainbow tables for your particular salt and start attacking your system.
A good choice of salt value is something that:
Is available each time you check the password
Doesn't change between password checks
Differs for each (or most) password calculations
A username would then be a decent choice, provided it cannot change. Or, generate a completely random value when you first create the user and store that as the salt, along with the user data in your database.
Others already explained the purpose of the salt, and why it can be public information.
One additional part of the answer to your question: do not derive the salt from the password itself. That would be very similar to the programming blunder that ended up exposing millions of passwords after the Ashley Madison hack.
The problem is that when you use the password to generate the salt, you are essentially making the password available in a second, and much-easier-to-crack, form. The attacker can completely ignore the output of the PBKDF2, and simply reverse the salt itself. That is only protected with SHA1, which is already broken.
At Ashley Madison, the error was similar. The passwords were stored in the main database using bcrypt, and thought to be secure. But then somebody discovered that the passwords for many accounts were actually stored twice, and the second copy was only protected with MD5.

Encrypt login and password in sqlite database - SHA 256 in C#

I want to store login and password in sqlite database. This database in encrypted using SQLCipher library. But password to encrypt database is separate issue. This password is stored in code of application. Login and password are provided by user to login to application. In C# there is the SHA256 class. If I use this class if it is enough ? Or rather I should use hash and salt or other methods ?
Thanks
To store a user password in a database for login matters, you should use a hash function with a salt.
SHA 256 is one of them, but there are better ones existing. I recommend you using the PBKDF2 derivative function. You can implement your own PBKDF2 hashing method using the Rfc2898DeriveBytes class provided in the .NET framework.
Here is a quick how-to-do-it:
int saltSize = 256; // Number of bytes of the salt
int iterations = 1000; // Number of times we iterate the function
// The more we iterate, the more it is gonna take time.
// The advantage of a great iterations number is to
// make brutforce attack more painful.
int hashSize = 20; // Number of bytes of the hash (the output)
var deriveBytes = new Rfc2898DeriveBytes("mypassword", saltSize, iterations);
byte[] salt = deriveBytes.Salt;
byte[] hash = deriveBytes.GetBytes(hashSize);
You just have now to store the salt and the hash in your database. Use Convert.FromBase64String and Convert.ToBase64String to get a string from a byte[] and vice-versa.
Another alternative is to use bcrypt. See this interesting article.

Categories

Resources