如何散列密码

嘿,我想在手机上存储密码的散列,但我不知道该怎么做。 我似乎只能findencryption方法。 散列密码的最佳方法是什么? 谢谢

更新这个答案严重失效 。 请使用https://stackoverflow.com/a/10402129/251311中的build议。

你可以使用

var md5 = new MD5CryptoServiceProvider(); var md5data = md5.ComputeHash(data); 

要么

 var sha1 = new SHA1CryptoServiceProvider(); var sha1data = sha1.ComputeHash(data); 

要获取data作为字节数组,你可以使用

 var data = Encoding.ASCII.GetBytes(password); 

并从md5datasha1data取回string

 var hashedPassword = ASCIIEncoding.GetString(md5data); 

这里的大多数答案都与今天的最佳实践有点过时。 因此,这里是使用PBKDF2 / Rfc2898DeriveBytes来存储和validation密码的应用程序。 下面的代码在这篇文章中是一个独立的类: 另一个如何存储一个盐渍密码哈希的例子 。 基础是非常容易的,所以在这里它被打破了:

步骤1用密码PRNG创build盐值:

 byte[] salt; new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]); 

步骤2创buildRfc2898DeriveBytes并获取哈希值:

 var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000); byte[] hash = pbkdf2.GetBytes(20); 

步骤3合并盐和密码字节供以后使用:

 byte[] hashBytes = new byte[36]; Array.Copy(salt, 0, hashBytes, 0, 16); Array.Copy(hash, 0, hashBytes, 16, 20); 

第4步将合并的salt + hash变成一个string进行存储

 string savedPasswordHash = Convert.ToBase64String(hashBytes); DBContext.AddUser(new User { ..., Password = savedPasswordHash }); 

步骤5根据存储的密码validation用户input的密码

 /* Fetch the stored value */ string savedPasswordHash = DBContext.GetUser(u => u.UserName == user).Password; /* Extract the bytes */ byte[] hashBytes = Convert.FromBase64String(savedPasswordHash); /* Get the salt */ byte[] salt = new byte[16]; Array.Copy(hashBytes, 0, salt, 0, 16); /* Compute the hash on the password the user entered */ var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000); byte[] hash = pbkdf2.GetBytes(20); /* Compare the results */ for (int i=0; i < 20; i++) if (hashBytes[i+16] != hash[i]) throw new UnauthorizedAccessException(); 

注意:根据具体应用的性能要求,可以减less值“10000”。 最小值应该在1000左右。

基于csharptest.net的很好的答案,我写了一个类:

 public sealed class SecurePasswordHasher { /// <summary> /// Size of salt /// </summary> private const int SaltSize = 16; /// <summary> /// Size of hash /// </summary> private const int HashSize = 20; /// <summary> /// Creates a hash from a password /// </summary> /// <param name="password">the password</param> /// <param name="iterations">number of iterations</param> /// <returns>the hash</returns> public static string Hash(string password, int iterations) { //create salt byte[] salt; new RNGCryptoServiceProvider().GetBytes(salt = new byte[SaltSize]); //create hash var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations); var hash = pbkdf2.GetBytes(HashSize); //combine salt and hash var hashBytes = new byte[SaltSize + HashSize]; Array.Copy(salt, 0, hashBytes, 0, SaltSize); Array.Copy(hash, 0, hashBytes, SaltSize, HashSize); //convert to base64 var base64Hash = Convert.ToBase64String(hashBytes); //format hash with extra information return string.Format("$MYHASH$V1${0}${1}", iterations, base64Hash); } /// <summary> /// Creates a hash from a password with 10000 iterations /// </summary> /// <param name="password">the password</param> /// <returns>the hash</returns> public static string Hash(string password) { return Hash(password, 10000); } /// <summary> /// Check if hash is supported /// </summary> /// <param name="hashString">the hash</param> /// <returns>is supported?</returns> public static bool IsHashSupported(string hashString) { return hashString.Contains("$MYHASH$V1$"); } /// <summary> /// verify a password against a hash /// </summary> /// <param name="password">the password</param> /// <param name="hashedPassword">the hash</param> /// <returns>could be verified?</returns> public static bool Verify(string password, string hashedPassword) { //check hash if (!IsHashSupported(hashedPassword)) { throw new NotSupportedException("The hashtype is not supported"); } //extract iteration and Base64 string var splittedHashString = hashedPassword.Replace("$MYHASH$V1$", "").Split('$'); var iterations = int.Parse(splittedHashString[0]); var base64Hash = splittedHashString[1]; //get hashbytes var hashBytes = Convert.FromBase64String(base64Hash); //get salt var salt = new byte[SaltSize]; Array.Copy(hashBytes, 0, salt, 0, SaltSize); //create hash with given salt var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations); byte[] hash = pbkdf2.GetBytes(HashSize); //get result for (var i = 0; i < HashSize; i++) { if (hashBytes[i + SaltSize] != hash[i]) { return false; } } return true; } } 

用法:

 //Hash var hash = SecurePasswordHasher.Hash("mypassword"); //Verify var result = SecurePasswordHasher.Verify("mypassword", hash); 

样本散列可以是这样的:

 $MYHASH$V1$10000$Qhxzi6GNu/Lpy3iUqkeqR/J1hh8y/h5KPDjrv89KzfCVrubn 

正如你所看到的,如果我们需要升级的话,我还包含了散列中的迭代以方便使用,并有可能升级它。

我使用散列和盐来进行密码encryption(与Asp.Net Membership使用的散列相同):

 private string PasswordSalt { get { var rng = new RNGCryptoServiceProvider(); var buff = new byte[32]; rng.GetBytes(buff); return Convert.ToBase64String(buff); } } private 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); }