HashPasswordForStoringInConfigFile - 相同密码的不同哈希值

时间:2011-09-26 05:48:35

标签: c# sha1

我最近在我正在进行的项目中为我的密码实施了Hashing,我似乎无法弄清楚出了什么问题。

似乎HashPasswordForStoringInConfigFile()函数为同一密码返回不同的值。

我实现了以下代码,它实际上非常类似于在MSDN文档中使用的推荐算法。

我知道SHA1散列不被认为是非常安全的,但这是一个研究应用程序,我现在不太担心它。

 public const int DefaultSaltSize = 5;
    private static string CreateSalt()
    {
        RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
        byte[] buffer = new byte[DefaultSaltSize];
        rng.GetBytes(buffer);
        return Convert.ToBase64String(buffer);
    }

    public static string CreateHash(string password)
    {
        string salt = CreateSalt();
        string saltAndPassword = String.Concat(password, salt);
        string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword,"SHA1");
        hashedPassword = string.Concat(hashedPassword,salt);
        return hashedPassword;
    }

    public static bool VerifyPassword(string username, string password,AccountDataContext context)
    {
        var user = context.UserAccounts.FirstOrDefault(p => p.UserName == username);
        if (user != null)
        {
            string salt = user.Password.Substring(user.Password.Length - DefaultSaltSize);
            string hashedPassword = CreateHash(password);
            return hashedPassword.Equals(user.Password);
        }
        return false;

    }

简单地说,如果我有以下代码。

string password1 = "password";
string password2 = "password";

var hashedPassword1 = CreateHash(password1);
var hashedPassword2 = CreateHash(password2);

var match = hashedPassword1.Equals(hashedPassword2);

//match should be True, but it is turning out False.

似乎FormsAuthenticationForStoringInConfigFile()没有在CreateHash()方法中为password1和password2返回相同的哈希值。

我理解使用盐它们不一样,但是如果你在代码中看到,我在删除盐之前比较两个hashedPasswords是否相等。

什么可能导致密码1和密码2被散列不同?

3 个答案:

答案 0 :(得分:4)

您的代码在散列之前已将密码(随机值)添加到密码中。这是一件好事。

这意味着如果用户A和用户B使用相同的密码,密码哈希值将会不同。

您的VerifyPassword方法未使用原始哈希值来比较密码 - 而是调用CreateHash,调用CreateSalt并创建新的盐。

您可以尝试以下方式:

public static string CreateHash(string password)
{
    return CreateHash(password, CreateSalt());
}

private static string CreateHash(string password, string salt)     
{         
    string saltAndPassword = String.Concat(password, salt);         
    string hashedPassword = 
        FormsAuthentication.HashPasswordForStoringInConfigFile(
                         saltAndPassword,"SHA1");         
    hashedPassword = string.Concat(hashedPassword,salt);         
    return hashedPassword;     
} 

    public static bool VerifyPassword(string username, 
                    string password,AccountDataContext context)
    {
        var user = context.UserAccounts.FirstOrDefault(p => p.UserName == username);
        if (user != null)
        {
            string salt = user.Password.Substring(user.Password.Length - DefaultSaltSize);
            string hashedPassword = CreateHash(password, salt);
            return hashedPassword.Equals(user.Password);
        }
        return false;

    }

答案 1 :(得分:1)

即使VerifyPassword看起来像是剥离了未散列字符串的salt部分,但是你说的代码应该返回true并不会实际调用VerifyPassword。

您的代码只生成两个盐渍哈希值,然后使用String.Equals来比较它们。

使用VerifyPassword而不是String.Equals会发生什么?

答案 2 :(得分:0)

此代码根本不起作用。为什么它被标记为正确答案?

Salt的默认长度设置为5

当一个字符串需要5个字节的数组时,创建Salt,它变为8个字符而不是5个

验证密码然后只关闭5个字符,因为盐不是8,因此验证将始终失败,因为它使用盐的5个字符而不是用于创建哈希密码的8个字符。

以下是更新代码,以使上述代码有效。

    private const int DEFAULT_SALT_SIZE = 5;

    private static string CreateSalt()
    {
        RNGCryptoServiceProvider rngCryptoServiceProvider = new RNGCryptoServiceProvider();
        byte[] buffer = new byte[DEFAULT_SALT_SIZE];
        rngCryptoServiceProvider.GetBytes(buffer);
        return Convert.ToBase64String(buffer);
    }

    public static string CreateHash(string password)
    {
        return CreateHash(password, CreateSalt());
    }

    private static string CreateHash(string password, string salt)
    {
        string saltAndPassword = String.Concat(password, salt);
        string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword, "SHA1");
        hashedPassword = string.Concat(hashedPassword, salt);
        return hashedPassword;
    }

    public static bool VerifyPassword(string userpassword, string password)
    {
        byte[] bytePassword = Convert.FromBase64String(userpassword);
        byte[] byteSalt = new byte[DEFAULT_SALT_SIZE];
        Array.Copy(bytePassword, bytePassword.Length - DEFAULT_SALT_SIZE, byteSalt, 0, DEFAULT_SALT_SIZE);
        string salt = Convert.ToBase64String(byteSalt);
        string hashedPassword = CreateHash(password, salt);
        return hashedPassword.Equals(userpassword);
    }

这就是我所说的。

        string hashedPassword = Security.CreateHash("password");
        if (Security.VerifyPassword(hashedPassword, "password"))
        {
            Response.Write("Valid");
        }
        else
        {
            Response.Write("Not Valid");
        }

只要密码匹配就返回true,否则返回false。

这给了你我认为的目的,不仅是在哈希中包含salt而且还将它添加到哈希的外部,这样它们就可以作为1列值存储在数据库中然后用于使用存储的salt值重新创建用户输入密码的哈希并获得匹配。