为了账号安全,请及时绑定邮箱和手机立即绑定

如何哈希密码

/ 猿问

如何哈希密码

噜噜哒 2019-07-23 18:02:51

如何哈希密码

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



查看完整描述

3 回答

?
DIEA

更新这个答案严重过时了。请使用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或返回字符串sha1data

var hashedPassword = ASCIIEncoding.GetString(md5data);


查看完整回答
反对 回复 2019-07-23
?
慕姐4208626

这里的大多数其他答案都与今天的最佳实践有些过时。因此,这里是使用PBKDF2 / Rfc2898DeriveBytes来存储和验证密码的应用。以下代码在本文中的独立类中:另一个如何存储salted密码哈希的示例。基础知识非常简单,所以在这里分解:

步骤1使用加密PRNG创建salt值:

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

步骤2创建Rfc2898DeriveBytes并获取哈希值:

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

步骤3将salt和password字节组合起来供以后使用:

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

步骤4将组合的salt + hash转换为字符串进行存储

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左右。


查看完整回答
反对 回复 2019-07-23
?
慕婉清6462132

根据csharptest.net的好答案,我为此编写了一个类:

public static 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>
    /// Checks 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>
    /// Verifies 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 hash bytes
        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;
    }}

用法:

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

示例哈希可以是这样的:

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

正如您所看到的,我还将哈希中的迭代包含在内以便于使用,如果我们需要升级,还可以升级它。


如果你对.net core感兴趣,我在Code Review上也有一个.net核心版本。


查看完整回答
反对 回复 2019-07-23
  • 3 回答
  • 0 关注
  • 340 浏览
我要回答
慕课专栏
更多

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信