用PBKDF2腌制和腌制

时间:2014-04-19 11:20:14

标签: c# encryption hash cryptography pbkdf2

我正在尝试通过哈希和盐析在数据库中保存密码来学习密码学,所以我决定尝试使用登录系统来实现这个系统。

我的数据库由

组成
  • UserID int PK
  • 用户名 varchar(250)
  • varbinary(64)
  • 密码 varbinary(64)
  • 注册日期时间
  • 电子邮件 varchar(250)

我正在使用 PBKDF2 ,但似乎这不是哈希/腌制方法,如果它不是什么呢?

如果是这样,我这样做了吗?

我的钥匙

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

将数据插入数据库

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();
            }
        }

检查用户是否有效

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。但这是正确的方法吗?这甚至是哈希/盐渍吗?

1 个答案:

答案 0 :(得分:8)

你基本上是朝着正确的方向前进,但我会指出一些需要考虑的事情:

  1. PBKDF2方法的默认迭代次数可能不足,您可能不希望将内容保留为默认值。我建议指定一个至少10K的迭代次数。

  2. 另一方面,密钥大小和salt大小由此实现计算,以字节为单位。 64字节有点太多了。每个都保持16个字节应该是充足的。不建议超过20个字节,因为它是底层散列函数/ HMAC的最大大小。越过这一点只会给攻击者带来好处(据许多人说,这是PBKDF2中的设计错误)。您当然可以将varbinary的大小设置为更高的值,以便将来升级。

  3. 建议您使用salt和哈希密码保存协议号。这样做可以让您在以后的日期和时间点升级该方案,此时用户可以重置他/她的密码。

  4. 小点;当生成salt时,MSDN不指定。我会检查盐的随机性(检查它是否每次都不同)并且在调用getBytes之后只询问盐以确保盐确实是随机的,即使实现发生了变化。否则使用加密安全随机数生成器自己生成它。