可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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)?
回答1:
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.
回答2:
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.
回答3:
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.
回答4:
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.
回答5:
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.