使用Rfc2898DeriveBytes和MSSQL在C#中使用加密密码的问题

时间:2018-01-19 11:51:12

标签: c# sql-server encryption hash rfc2898

我已经为我的应用程序创建了一个登录系统,但是它的工作非常不一致。

有时密码会起作用,但有时候它会说错误。我100%肯定我正确输入它。

为了存储密码,我生成一个随机盐,用盐哈希密码并将哈希密码和盐以及用户名存储在数据库中。

要对用户进行身份验证,我会根据给定的用户名选择哈希密码和salt。然后我使用salt对密码尝试进行哈希处理,看看它是否与原始哈希密码匹配,如果是,则允许他们登录。

我的代码如下:

private const int NumberOfRounds = 5000, SaltLength = 32;
public static byte[] GenerateSalt()
{
    using (var rng = new RNGCryptoServiceProvider())
    {
        var randomNumber = new byte[SaltLength];

        rng.GetBytes(randomNumber);

        return randomNumber;
    }
}

public static byte[] HashPassword(byte[] passwordToHash, byte[] salt)
{
    using (var deriveBytes = new Rfc2898DeriveBytes(passwordToHash, salt, numberOfRounds))
    {
        return deriveBytes.GetBytes(32);
    }
}



public static bool IsPasswordValid(string inputPassword, string hashedPassword, string salt)
{
    byte[] potentialValidPassword = HashPassword(Encoding.Unicode.GetBytes(inputPassword),
                Encoding.Unicode.GetBytes(salt));

    string potentialAsString = Encoding.Unicode.GetString(potentialValidPassword);

    return  Encoding.Unicode.GetBytes(hashedPassword).SequenceEqual(potentialValidPassword) ||
                hashedPassword.Equals(potentialAsString);
}

我的检查比较字节数组值和字符串值的原因是有时字节值比较失败但字符串值有效。

我将用户插入数据库的代码如下

public SecurityReturnMessage AddUser(string username, string password)
{
    byte[] salt = PasswordManagement.GenerateSalt();

    byte[] hashedPassword = PasswordManagement.HashPassword(Encoding.Unicode.GetBytes(password), salt);

    if (conn.State != ConnectionState.Open)
        conn.Open();

    int result;
    using (IDbCommand comm = conn.CreateCommand())
    {
        comm.CommandText = "usp_IFRS_SEC_USER_INSERT";
        comm.CommandType = CommandType.StoredProcedure;

        SqlParameter hashPwd =new SqlParameter("@hashpwd", SqlDbType.NVarChar)
        {
            Value = Encoding.Unicode.GetString(hashedPassword)
        };

         SqlParameter saltParameter = new SqlParameter("@salt", SqlDbType.NVarChar)
         {
             Value = Encoding.Unicode.GetString(salt)
         };

         comm.Parameters.Add(Extensions.CreateParameter(comm, "@user", username));
         comm.Parameters.Add(hashPwd);
         comm.Parameters.Add(saltParameter);

         var returnVal = comm.CreateParameter();
         returnVal.Direction = ParameterDirection.ReturnValue;
         comm.Parameters.Add(returnVal);

         comm.ExecuteNonQuery();

         result = (int)returnVal.Value;
     }

     if (conn.State != ConnectionState.Closed)
         conn.Close();

     return (SecurityReturnMessage)result;
}

如果有人能帮我解决这个问题,我将非常感激。

1 个答案:

答案 0 :(得分:2)

我建议您在将值从字节转换为字符串时使用如下的Base64转换,反之亦然。

    string base64 = Convert.ToBase64String(bytes);
    byte[] bytes = Convert.FromBase64String(base64);

通过这种方式,您可以确保在任一转换过程中unicode数据都不会丢失或损坏,这可能是代码不一致的正当理由。