Salted hash algorithm - c#

I am using salted hash algorithm to secure the password. RNGCryptoServiceProvider is used to create the salt. Is it possible to create salt based on the user name? Please help me

You should first of all look into what Salt is then you could revise this greate code-chunk to see how you use Cryptography with Salt in unfortunatly VB.
Now that you are familiar with how Salt works and have some knowledge of the C# implementation. You see that it actually is possible to do some modifications with the salting. For instance the computeHash takes a byte[] for salting, maybe you could try
System.Text.ASCIIEncoding encoding=new System.Text.ASCIIEncoding();
encoding.GetBytes(str);
There is a world of possibilites for you, but to simply answer your question without spoiling the ending, yes, you can create a salt based on the username.

Related

Securing users passwords using c# - Rfc2898DeriveBytes vs SHA512

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].

C# sha256 into PHP

I've got a table of hashes and salts previously created by by another company. The hash was done in C# and the hash method is sha256. The logic behind this is sha256(password+salt).
An example of inputs:
password = 'rosnicka'
salt = 'zxwqTy+XjaY='
hash = '3jdt1+JL3MPmjYr2OoXdoUwNfuweuDCZa8/3g7SfsNg='
When I tried to run a hashing function in PHP
the output of this is
"1125ed47a7aa11bc1c54c841b5eb7a6e72aa8ad27e010e6e25baa5b2a86cffb3"
I get the same results using only hashing calculators
I contacted them to find out what I'm doing wrong. They told me, that are storing ASCII version of the hash in the database. What should I do in order to get the same hash in PHP or what to do in order to convert their hash to the original sha256 hash?
thanks a lot!
As alex K said:
base64_encode(hash('sha256', 'rosnicka'.base64_decode('zxwqTy+XjaY='), true));
will do the trick

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.

How to hash a password with SHA512

In my previous question I was told to hash passwords instead of encrypt, and that turned out to be correct. Problem is, I've never dealt with hashing passwords before and all the docs say SHA512 which I've tried to use on a test account to no avail. I'm not sure where to go from here. The code comments give me the example "encrypted" string as they call it, and it's "FA35A0194E3BE7024CEFB1839CBFC922" which I'm not sure how to format it like that with SHA512 since all it takes and gives back is a byte array or stream from the ComputeHash() method:
byte[] hashedPassword = HashAlgorithm.Create("SHA512").ComputeHash( ??? );
UPDATE
I've tried printing out the UTF8Encoding.GetString on the bytes, but it just displays a bunch of bullshit characters that look nothing like the one in the example docs.
Hashing with plain SHA-512 is still wrong. Use PBKDF2 which is exposed via Rfc2898DeriveBytes.
It returns raw bytes, which you should encode with either hex or base64.
You can do hex encoding with:
BitConverter.ToString(bytes).Replace("-","")
You sure it said 512 because that's 128, but anyway you could use something like
System.String Hashed = System.BitConverter.ToString(((System.Security.Cryptography.SHA512)new System.Security.Cryptography.SHA512Managed()).ComputeHash(System.Text.Encoding.ASCII.GetBytes("NotHashedPass"))).Replace("-","");
MessageBox.Show(Hashed);
but id recommend at least using a salt.
Please see tutorial here:
http://www.obviex.com/samples/hash.aspx
From the tutorial:
"These code samples demonstrate how to hash data and verify hashes. It supports several hashing algorithms. To help reduce the risk of dictionary attacks, the code prepends random bytes (so-called salt) to the original plain text before generating hashes and appends them to the generated ciphertext (original salt value will be needed for hash verification). The resulting ciphertext is base64-encoded. IMPORTANT: DATA HASHES CANNOT BE DECRYPTED BACK TO PLAIN TEXT"

Categories

Resources