关于c#:使用PBKDF2进行Salting和Hashing

Salting and Hashing with PBKDF2

我正在尝试学习密码术,通过散列和跳跃将密码保存在数据库中,所以我决定创建一个登录系统来尝试实现这个系统。

我的数据库由

  • 用户ID int pk
  • 用户名varchar(250)
  • 盐变二元(64)
  • 密码varbinary(64)
  • RegDate日期时间
  • 电子邮件varchar(250)

我正在使用pbkdf2,但这似乎不是一个哈希/加盐方法,如果不是,它是什么?

如果是这样,我做得对吗?

我的钥匙

1
2
private const int SALT_SIZE = 64;
private const int KEY_SIZE = 64;

将数据插入数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static void RegisterMe(string _username, string _password, string _email)
        {
            using (var cn = new SqlConnection(User.strcon))
            {
                string _sqlins = @"
                    INSERT INTO
                    [User]
                        ([Username],[Salt],[Password],[RegDate], [Email])
                    VALUES
                        (@Username, @Salt, @Password, CURRENT_TIMESTAMP, @Email)"
;

                var cmd = new SqlCommand(_sqlins, cn);
                cn.Open();
                using (var deriveBytes = new Rfc2898DeriveBytes(_password, SALT_SIZE))
                {
                    byte[] salt=deriveBytes.Salt;
                    byte[] key = deriveBytes.GetBytes(KEY_SIZE);  

                    // save salt and key to database
                    cmd.Parameters.AddWithValue("@Username", _username);
                    cmd.Parameters.AddWithValue("@Password", key);
                    cmd.Parameters.AddWithValue("@Salt", salt);
                    cmd.Parameters.AddWithValue("@Email", _email);
                }
                cmd.ExecuteNonQuery();
            }
        }

检查用户是否有效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public bool IsValid(string _email, string _password)
    {

        using (var cn = new SqlConnection(strcon))
        {
            byte[] salt={ }, key = { };
            string _sql = @"
                            SELECT
                                SALT,
                                [Password],
                                UserID
                            FROM
                                [User]
                            WHERE [Email] = @email"
;

            SqlCommand cmd = new SqlCommand(_sql, cn);
            cmd.Parameters.AddWithValue("@email", _email);

            cn.Open();
            SqlDataReader reader = cmd.ExecuteReader();
            if (reader.Read())
            {
                salt=reader.GetSqlBytes(0).Value;
                key = reader.GetSqlBytes(1).Value;

                reader.Dispose();
                cmd.Dispose();
                using (var deriveBytes = new Rfc2898DeriveBytes(_password, salt))
                {
                    byte[] newKey = deriveBytes.GetBytes(KEY_SIZE);  // derive a 20-byte key
                    return newKey.SequenceEqual(key);
                }
            }
            else
            {
                reader.Dispose();
                cmd.Dispose();
                return false;
            }
        }
    }

我的系统工作正常,它将数据设置为字节,如果用户输入正确的密码,它将返回true。但是这条路对吗?这是加盐吗?


你基本上走对了方向,但我会指出一些需要考虑的事情:

  • pbkdf2方法的默认迭代次数可能不够,您可能不希望将其保留为默认值。我建议指定至少10公里的迭代计数。

  • 另一方面,这个实现以字节为单位计算密钥大小和salt大小。64字节太多了。两个字节都保持在16个字节就足够了。不建议超过20个字节,因为这是底层哈希函数/hmac的最大大小。浏览这些信息只会给攻击者带来优势(根据许多人的说法,这是PBKdf2中的一个设计错误)。当然,您可以将varbinary的大小设置为更高的值,以便将来进行升级。

  • 建议您使用SALT和哈希密码保留协议号。这样做可以使您在用户可以重置其密码时,在以后的日期和每次输入时升级方案。

  • 次要点;msdn未指定何时生成盐。我会检查salt的随机性(每次检查是否不同),并且只在调用getBytes之后询问salt,以确保salt确实是随机的,即使实现发生了更改。否则,使用加密安全的随机数生成器自己生成它。