2011-09-26 147 views
2

我最近在我正在进行的项目中为我的密码实施了哈希处理,而且我似乎无法弄清楚发生了什么问题。HashPasswordForStoringInConfigFile - 对于相同密码的不同哈希

似乎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()方法和密码1密码2相同的哈希值。

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

什么可能导致password1和password2被不同地散列?

回答

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

即使VerifyPassword看起来像它剥离了非散列字符串的盐部分,但你说的应该返回true代码实际上不叫VerifyPassword。

您的代码只生成两个盐腌散列,然后使用String.Equals来比较它们。

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

+0

它不起作用,我为了简洁而忽略了呼叫,我应该包括它 – TheJediCowboy

0

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

盐的缺省长度设置为5

创建盐当花费5字节数组变得8个字符不是5

验证密码然后用于盐仅需5个字符关的字符串不是8,所以验证将总是失败,因为它使用5个字符作为salt,而不是用于创建哈希密码的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。

这给你我认为是有意的这不仅包括哈希里面的盐,而且将它添加到哈希的外部,所以它可以作为1列值存储在数据库中,然后使用使用存储的盐值在用户输入的密码上重新创建散列并获得匹配。