4 ответов:
обновление:ЭТОТ ОТВЕТ СЕРЬЕЗНО УСТАРЕЛ. Пожалуйста, используйте рекомендации от https://stackoverflow.com/a/10402129/251311 вместо этого.
можно использовать
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);и получить обратно строку из
md5dataилиsha1datavar hashedPassword = ASCIIEncoding.GetString(md5data);
большинство других ответов здесь несколько устарели с сегодняшними лучшими практиками. Как таковой здесь является применение использования PBKDF2 / Rfc2898DeriveBytes для хранения и проверки паролей. Следующий код находится в автономном классе в этом сообщении:еще один пример того, как хранить соленый хэш пароля. Основы очень просты, поэтому здесь он разбит:
Шаг 1 создать значение соли с помощью криптографического ПРНГ:
byte[] salt; new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);Шаг 2 создайте Rfc2898DeriveBytes и получите хэш-значение:
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 включить смешанная соль+хэш в строку для хранения
string savedPasswordHash = Convert.ToBase64String(hashBytes); DBContext.AddUser(new User { ..., Password = savedPasswordHash });Шаг 5 Проверьте введенный пользователем пароль на сохраненный пароль
/* 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();Примечание: В зависимости от производительности требования вашего специфического применения, значение '10000' можно уменьшить. Минимальное значение должно быть около 1000.
на основе csharptest.net ' s Отличный ответ, я написал класс для этого:
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", 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$V1000$Qhxzi6GNu/Lpy3iUqkeqR/J1hh8y/h5KPDjrv89KzfCVrubnкак вы можете видеть, я также включил итерации в хэш для удобства использования и возможности обновить это, если нам нужно обновить.
Я использую хэш и соль для шифрования пароля (это тот же хэш, который Asp.Net членство использует):
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); }
Comments