从表列中读取二进制并存储到 byte[] 数组中

9

我在应用程序中使用PBKDF2来存储用户的密码。在我的用户表中,我有一个SaltPassword列,其确定方式如下:

// Hash the users password using PBKDF2
var DeriveBytes = new Rfc2898DeriveBytes(_Password, 20);
byte[] _Salt = DeriveBytes.Salt;
byte[] _Key = DeriveBytes.GetBytes(20);  // _Key is put into the Password column

在我的登录页面上,我需要检索这个salt和密码。因为它们是byte[]数组,所以我将它们存储在我的表中作为varbinary(MAX)。现在我需要检索它们以与用户输入的密码进行比较。我该如何使用SqlDataReader来做到这一点?目前我有:

cn.Open();
SqlCommand Command = new SqlCommand("SELECT Salt, Password FROM Users WHERE Email = @Email", cn);
Command.Parameters.Add("@Email", SqlDbType.NVarChar).Value = _Email;
SqlDataReader Reader = Command.ExecuteReader(CommandBehavior.CloseConnection);
Reader.Read();
if (Reader.HasRows)
{
    // This user exists, check their password with the one entered
    byte[] _Salt = Reader.GetBytes(0, 0, _Salt, 0, _Salt.Length);
}
else
{
    // No user with this email exists
    Feedback.Text = "No user with this email exists, check for typos or register";
}

但我可以确信地说这是错误的。在Reader中的其他方法只有一个参数,即要检索的列的索引。


你怎么确定它是错误的?因为你正在做所有其他相关问题都在做的事情。你确定你创建的字节数组可以适合 varbyte 吗? - Security Hound
VS 抛出一个错误,说它无法将 long 转换为 byte[],而且参数描述与我输入的不匹配,比如 Salt._Length - James Dawson
2个回答

14

到目前为止,将它直接转换成 byte[] 对我有用。

using (SqlConnection c = new SqlConnection("FOO"))
{
    c.Open();
    String sql = @"
        SELECT Salt, Password 
        FROM Users 
        WHERE (Email = @Email)";
    using (SqlCommand cmd = new SqlCommand(sql, c))
    {
        cmd.Parameters.Add("@Email", SqlDbType.NVarChar).Value = _Email;
        using (SqlDataReader d = cmd.ExecuteReader())
        {
            if (d.Read())
            {
                byte[] salt = (byte[])d["Salt"];
                byte[] pass = (byte[])d["Password"];

                //Do stuff with salt and pass
            }
            else
            {
                // NO User with email exists
            }
        }
    }
}

3
我不确定为什么你认为你写的代码是错误的(请解释一下)。但是特别针对这个错误:
请注意,GetBytes 返回一个 long 而不是一个字节数组。

所以,您应该使用: Reader.GetBytes(0, 0, _Salt, 0, _Salt.Length);

或者 long bytesRead = Reader.GetBytes(0, 0, _Salt, 0, _Salt.Length);


如果你看一下该方法所需的参数,就会发现我的参数是不正确的,但我不知道要指定什么。并且我不能将其转换为long类型,必须以字节数组的形式返回,以使我的密码检查工作正常运行。 - James Dawson
1
@JamesDawson 请阅读我在答案中发布的 GetBytes 函数的描述:从指定的列偏移量读取一系列字节到缓冲区数组中,从给定的缓冲区偏移量开始。换句话说,在您的示例中,将复制列号为0的字节流到 _Salt 变量中。这正是您要求的。 (GetBytes 函数的返回值仅为读取的字节数,因此它是一个 long 类型)。您是否按照我的建议更改了代码?它可行吗? - Blachshma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接