繁体   English   中英

使用 Rfc2898DeriveBytes 在 C# 中用胡椒和盐散列密码

[英]Hashing a password with pepper and salt in C# using Rfc2898DeriveBytes

我想在 C# 中使用带有胡椒和盐的 PBKDF2 散列密码。 我对密码学有点陌生,所以如果我错了,请随时纠正我。

我使用 Rfc2898DeriveBytes 类是因为(根据其他 Stackoverflow 用户的说法)bcrypt 和其他哈希算法在 C# 中不受本机支持和验证,因此它可能构成安全威胁。 这篇文章的目的不是开始讨论哪种散列算法是最好的。 > C# Stackoverflow 中的 Bcrypt

我的目标:每个密码都会得到一个随机的盐和胡椒,密码将经过一定数量的迭代进行散列。

我的问题:与所需的散列大小相比,输入大小是否不好,我的实现是否正确?

  • 示例: (PasswordInput (?) + Pepper (16 Bytes) + Salt (16 Bytes) > HashOutput (20 Bytes)

我的代码

public class GenerateHash
{
    //Fields
    private const int saltSize = 16;
    private const int hashSize = 16;
    private const int iterations = 10000;
    private const string secretPepper = "Secret 16 Byte pepper."; 

   //Properties
    private string inputId { get; set; }

    //Methods
    public byte[] GeneratePBKDF2String(string inputId, string secretPepper, int saltSize, int 
    hashSize, int iterations)
    {
        // Generate a random salt.
        RNGCryptoServiceProvider cryptographicServiceProvider = new RNGCryptoServiceProvider();
        byte[] salt = new byte[saltSize];
        provider.GetBytes(salt);

        // Generate a salted hash with pepper.
        Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(inputId + secretPepper, salt, iterations);
        return pbkdf2.GetBytes(hashSize);
    }
}

我明白那个:

  • 散列是不可逆的。
  • 添加盐和胡椒粉以提高安全性并防止彩虹桌攻击。
  • 盐是一个唯一的随机字符串,它不必是秘密的,可以与哈希值一起存储在数据库中。
  • 胡椒不是唯一的,它用于每个哈希。 这是一个秘密,它不存储在数据库中。
  • 盐和胡椒至少应使用 128 位(16 字节 > 16 个字符)。
  • 该算法至少应使用 10.000 次迭代。

研究: Microsoft Rfc2898DeriveBytes示例代码

PBKDF2(带有 SHA-1) - 可怕的Rfc2898DeriveBytes实现 - 使用重复的 HMAC 和密码 - 编码为字节 - 作为密钥。 一般情况下,HMAC 只是对输入键(ipad 和 opad 如果要查找)执行填充方法。 该填充达到哈希函数的输入块大小 但是,让我们看看 HMAC RFC 中 HMAC 的定义:

我们用 B 表示这些块的字节长度(对于上述所有哈希函数示例,B=64),用 L 表示哈希输出的字节长度(MD5 的 L=16,SHA-1 的 L=20 )。 认证密钥 K 可以是任意长度,最大为 B,即散列函数的块长度。 使用长于 B 字节的密钥的应用程序将首先使用 H 对密钥进行散列,然后将得到的 L 字节字符串用作 HMAC 的实际密钥。

在您的情况下,如果您的编码密码长于 64 - 16 = 48 个字节(胡椒大小为 16),您的 HMAC可能会更慢。 然而,智能 PBKDF2 函数可以检测到这一点并通过仅执行一次初始散列部分来解决该问题。

因此,如果您的密码超过 48 字节,那么您可以在以下情况下为攻击者提供一些好处:

  1. 你的实现不是那么聪明
  2. 攻击者的实现聪明的。

请注意,哈希输出大小与此无关。 您可以将 PBKDF2 与 SHA-512 一起使用 - 块大小为 1024 位,而不是 SHA-1 和 SHA-256 的 512 位 - 以防出现问题。

如果您请求的字节数大于输出大小,则 PBKDF2 中散列函数的散列输出大小(默认为 SHA-1)确实很重要。 在这种情况下,您也将优势还给了攻击者。 幸运的是,您只要求hashSize 16 个字节(您可能希望将其更改为passwordHashSize以避免混淆的变量名称)。


我明白那个:

哦亲爱的 ;)

  • 散列是不可逆的。

加密散列函数和密码散列函数不可逆,其他散列函数可能是可逆的。

  • 添加盐和胡椒粉以提高安全性并防止彩虹桌攻击。

你只需要盐。 胡椒可以防止攻击者完全猜出密码,前提它可以保证安全并且足够强大。

  • 盐是一个唯一的随机字符串,它不必是秘密的,可以与哈希值一起存储在数据库中。

没错。

  • 胡椒不是唯一的,它用于每个哈希。 这是一个秘密,它不存储在数据库中。

或者它本身被加密并存储在数据库中,但是是的,最终需要以一种或另一种方式保护它。

  • 盐和胡椒至少应使用 128 位(16 字节 > 16 个字符)。

嗯,这是上限,我会说 64 到 128 个完全随机的位,最好超过 80。但是,不是每个字符都可以映射到一个字节,所以你的胡椒不太可能是完全随机的 - 一个坏主意对于基本上是秘密密钥的东西。

请注意,在 SHA-1 需要另一个块加密之前,PBKDF2 的 salt 配置选项可以是最大 64 - 8 - 4 = 52 字节的任何大小。 出于这个原因,盐和胡椒通常是连接在一起的。 这也将允许您使用真正的随机胡椒。 它也会以这种方式为密码留下更多字符 (64)。

  • 该算法至少应使用 10.000 次迭代。

现在我们通常推荐大约一百万。 但实际上,您可以节省的任何 CPU 周期数量都会让对手更难。 当然,如果对手真的无法获得胡椒,这一点就没有实际意义了。 在这种情况下,单轮就足够了 - 但您可能希望使用更高的迭代次数作为第二道防线(例如,防止系统管理员尝试使用数据库副本获取用户密码)。

  1. 输入大于输出大小不是问题。 一个好的哈希函数应该能够抵御所有攻击,即使输入非常大。
  2. 说到好的散列函数:20 字节的输出大小暗示正在使用 SHA-1。 SHA-1 已被破坏,实际冲突已经存在,因此不应使用它。 (我不知道 Rfc2898 是否是一种安全方案,无论是否存在 SHA-1 冲突,但在安全性方面,安全总比抱歉好。
  3. 否则,实施似乎没问题。 我不是最新的 C#,但您似乎正在使用加密 RNG 作为盐。
  4. 你的胡椒也应该是随机的。
  5. 128 位(16 字节)密钥完全没问题,只要您的密码不需要保持安全超过 50 年左右。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM