BCrypt验证存储的密码哈希值

时间:2016-09-20 17:57:40

标签: mysql .net vb.net bcrypt

将哈希密码存储在数据库中是成功的。但是在验证输入密码和存储在数据库中的哈希时,它总是返回false。

    Dim pw As String = txt_password.Text
    Dim salt As String = BCrypt.Net.BCrypt.GenerateSalt(12)
    Dim hash As String = BCrypt.Net.BCrypt.HashPassword(pw, salt)

    With sqlLogin
            .Parameters.AddWithValue("@userid", txt_username.Text)
            .Parameters.AddWithValue("@userpass", hash)
    End With

                Dim Reader As MySqlDataReader = sqlLogin.ExecuteReader()
            If (BCrypt.Net.BCrypt.Verify(pw, hash)) Then
                MessageBox.Show("Login Succesful!", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information)
                Me.Hide()
                Reader.Close()
            ElseIf Reader.HasRows = False Then
                MessageBox.Show("Invalid Login Information!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                txt_username.Text = ""
                txt_password.Text = ""
                txt_username.Focus())
            End If

1 个答案:

答案 0 :(得分:2)

特别是在加密方面,您应该对所涉及的原则和概念有一些大致的了解。 Salted Password Hashing解释了常见的陷阱并提出了一些建议(一个是BCrypt,因此您可能走在正确的道路上。)

在验证之前,您似乎没有从数据库中读取存储的哈希值。您没有显示它的保存方式,但这对于验证它非常重要。

 ' cuts down on dot operators
 Imports BCryptor = BCrypt.Net.BCrypt

创建新登录

' new user save
Dim sql = "INSERT INTO userlogin (email, username, pwhash) VALUES (@email, @n, @pw)"
' prep:
Dim salt = BCryptor.GenerateSalt(12)    ' == 2^12
Dim hash = BCryptor.HashPassword(tbPass)

' to do: Try/Catch for an email that already exists
Using dbCon As New MySqlConnection(MySQLConnStr),
    cmd As New MySqlCommand(sql, dbCon)

    cmd.Parameters.Add("@email", MySqlDbType.Text).Value = tbEmail
    cmd.Parameters.Add("@n", MySqlDbType.Text).Value = tbUserName
    cmd.Parameters.Add("@pw", MySqlDbType.Text).Value = hash
    dbCon.Open()
    cmd.ExecuteNonQuery()

End Using

验证尝试

Dim bRet As Boolean = False

' login user 
Dim sql = "SELECT pwhash FROM userlogin WHERE email = @email"

Using dbCon As New MySqlConnection(MySQLConnStr),
        cmd As New MySqlCommand(sql, dbCon)

    ' data for the where clause
    cmd.Parameters.Add("@email", MySqlDbType.Text).Value = tbEmail

    dbCon.Open()
    Using rdr = cmd.ExecuteReader()
       ' read from the reader to load data
        If rdr.Read() Then
            ' get the saved hash
            Dim savedHash = rdr.GetString(0)
            bRet = BCryptor.Verify(tbPass, savedHash)
        Else
            bRet = False
        End If
    End Using
    ' return whether the hash verified
    Return ret
End Using

备注

  • DbConnectionDbCommandDbDataReader都实现Dispose,这意味着他们可以很好地分配需要释放的资源。代码在Using块中使用它们中的每一个。这会在开始时创建它们,并在块的末尾处理它们。
  • 这使用电子邮件作为唯一标识符,因为那里有很多Steves。这意味着SQL最多将返回一条记录。
  • 从数据库加载散列pw后,使用 it 验证输入的密码尝试。您的代码似乎正在创建一个新的哈希(并且实际上并没有从数据库中加载任何内容)。

创建帐户时最初生成的随机盐会成为散列的一部分(以及您使用的工作因素),如下所示:

Dim pw = "My!Weak#Pa$$word"
Dim salt = BCryptor.GenerateSalt(12)
Dim hash = BCryptor.HashPassword(pw, salt)

Console.WriteLine(salt)
Console.WriteLine(hash)

输出:

  

$ 2A $ 12 $ XPC20niJIhZPxaKvJkSUfO
  $ 2A $ 12 $ XPC20niJIhZPxaKvJkSUfO / rwIetoScCze.tOcVS / aJzowvjpCPlq

12之后的"$2a$"是工作因素。