可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
How does ASP.NET membership generate their salt key and then how do they encode it (that is, is it salt + password or password + salt)?
I am using SHA-1 with my membership, but I would like to recreate the same salts so the built-in membership stuff could hash the stuff the same way as my stuff can.
Edit 2: Never mind. I misread it and was thinking it said bytes, not bits. So I was passing in 128 bytes, not 128 bits.
Edit: I been trying to make it so. This is what I have,
public string EncodePassword(string password, string salt)
{
byte[] bytes = Encoding.Unicode.GetBytes(password);
byte[] src = Encoding.Unicode.GetBytes(salt);
byte[] dst = new byte[src.Length + bytes.Length];
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
byte[] inArray = algorithm.ComputeHash(dst);
return Convert.ToBase64String(inArray);
}
private byte[] createSalt(byte[] saltSize)
{
byte[] saltBytes = saltSize;
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetNonZeroBytes(saltBytes);
return saltBytes;
}
So I have not tried to see if the ASP.NET membership will recognize this yet the hashed password looks close. I just don't know how to convert it to base64 for the salt.
I did this
byte[] storeSalt = createSalt(new byte[128]);
string salt = Encoding.Unicode.GetString(storeSalt);
string base64Salt = Convert.ToBase64String(storeSalt);
int test = base64Salt.Length;
Test length is 172 which is well over the 128 bits so what am I doing wrong?
This is what their salt looks like
vkNj4EvbEPbk1HHW+K8y/A==
This is what my salt looks like
E9oEtqo0livLke9+csUkf2AOLzFsOvhkB/NocSQm33aySyNOphplx9yH2bgsHoEeR/aw/pMe4SkeDvNVfnemoB4PDNRUB9drFhzXOW5jypF9NQmBZaJDvJ+uK3mPXsWkEcxANn9mdRzYCEYCaVhgAZ5oQRnnT721mbFKpfc4kpI=
回答1:
What is default hash algorithm that ASP.NET membership uses? has a good discussion of their default algorithm.
I hope that helps!
Edit-
The answer I was referring to is the code in the top post,
public string EncodePassword(string pass, string salt)
{
byte[] bytes = Encoding.Unicode.GetBytes(pass);
//byte[] src = Encoding.Unicode.GetBytes(salt); Corrected 5/15/2013
byte[] src = Convert.FromBase64String(salt);
byte[] dst = new byte[src.Length + bytes.Length];
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
byte[] inArray = algorithm.ComputeHash(dst);
return Convert.ToBase64String(inArray);
}
They are combining Unicode Salt + Pass using BlockCopy
-- In response to your question:
Both algorithms are necessary and fulfill different roles...
RNG Crypto is used to generate the salt. It is basically a long string of random data. This is generated and stored on a per user basis. Typically this is done when a user is created or a password is changed.
BlockCopy is just the method they use to combine the salt with the password. The above code essentially equates to salt + password.
You aren't going to be able to recreate a salt value as it is completely random. It is, however, stored for each user by the framework.
Combining the salt with the password and hashing it using the technique above will allow you to verify users passwords using the hashed value stored by the framework.
I think we both read your question differently. The code I posted won't generate your salt, but it will let you use it in a way that is compatible with ASP.NET membership.
Sorry my explanation isn't the best- does that answer your question?
回答2:
Here is how the SQLMembershipProvider generates salt.
private string GenerateSalt() {
var buf = new byte[16];
(new RNGCryptoServiceProvider()).GetBytes(buf);
return Convert.ToBase64String(buf);
}
You can download the ASP.NET's SQL Provider code here.
The issue I was having was a development application running on IIS7. .NET 4.0 was using a different default hash algorithm than the default HashAlgorithmType for .NET 2.0.
In the "EncodePassword" sample code by Microsoft, they reference Membership.HashAlgorithmType
which I believe returns the default for the framework, if it is not specified in the web.config
.
I was able to get both this GenerateSalt and EncodePassword method to work for my application.
My combined code:
internal string GenerateSalt()
{
byte[] buf = new byte[16];
(new RNGCryptoServiceProvider()).GetBytes(buf);
return Convert.ToBase64String(buf);
}
internal string EncodePassword(string pass, int passwordFormat, string salt)
{
if (passwordFormat == 0) // MembershipPasswordFormat.Clear
return pass;
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bAll = new byte[bSalt.Length + bIn.Length];
byte[] bRet = null;
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
if (passwordFormat == 1)
{ // MembershipPasswordFormat.Hashed
HashAlgorithm s = HashAlgorithm.Create("SHA1");
// Hardcoded "SHA1" instead of Membership.HashAlgorithmType
bRet = s.ComputeHash(bAll);
}
else
{
bRet = EncryptPassword(bAll);
}
return Convert.ToBase64String(bRet);
}
回答3:
Here is one way of doing it. A salt is just a random number, you can use RNGCryptoServiceProvider class in the framework library to produce good random number to use as salt
private const int ITERATIONS = 10000;
private const int SALT_SIZE = 32;
private const int HASH_SIZE = 32;
public void SaltAndHashPassword(string password, out byte[] salt,
out byte[] hash)
{
Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(
password,
SALT_SIZE,
ITERATIONS);
salt = rdb.Salt;
hash = rdb.GetBytes(HASH_SIZE);
}