【问题标题】:Is it ok to use SHA1 hash of password as a salt when deriving encryption key and IV from password string?从密码字符串派生加密密钥和 IV 时,可以使用密码的 SHA1 哈希作为盐吗?
【发布时间】:2012-09-21 11:25:54
【问题描述】:

我正在使用 Rfc2898DeriveBytes 从用户提供的字符串密码安全地生成加密密钥和初始化向量,以用于对称加密(例如 AesManaged)。

我将密码的 SHA1 哈希作为盐参数传递给Rfc2898DeriveBytes。那样可以么?如果没有,那么我应该从哪里得到盐?解密时我需要相同的盐,对吗?所以我必须将它存储在未加密的地方 - 不安全。如果我必须安全地存储它,那么它就变成了另一个“密码”,不是吗?

void SecureDeriveKeyAndIvFromPassword(string password, int iterations, 
    int keySize, int ivSize, out byte[] key, out byte[] iv)
{
    // Generate the salt from password:

    byte[] salt = (new SHA1Managed()).ComputeHash(Encoding.UTF8.GetBytes(password));

    // Derive key and IV bytes from password:

    Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(password, salt, iterations);

    key = derivedBytes.GetBytes(keySize);
    iv = derivedBytes.GetBytes(ivSize);
}

我见过使用常量(硬编码)盐,也见过有人抱怨它。我认为从密码中派生盐会是更好的主意,但我不确定这是最佳解决方案。

简而言之,我有一个需要加密的文件,以及用户输入的密码字符串。如何正确使用Rfc2898DeriveBytes 导出安全加密密钥和IV?

谢谢。

编辑:

感谢您的回答。我现在明白了盐的主要(也许只是?)目的是使彩虹表的生成变得不可能 - 你不能预先生成“P@$$w0rd”的散列,因为它对于每个可能都有不同的散列盐值。我完全理解这一点,但是......这真的与对称加密有关吗?我没有将哈希存储在任何地方吗?因此,即使攻击者拥有所有可能的密码组合的彩虹表,他也无能为力,对吧?

所以,我现在的问题是:与对称加密算法一起使用时,与使用密码派生(甚至硬编码)盐相比,在每个加密操作中使用随机盐有什么优势(如 .NET 的 AesManaged)?

【问题讨论】:

  • 最好只存储密码的哈希值。与加密密码相比,即使攻击者控制您的代码并知道密钥,哈希值也无法反转。那么为什么要加密密码(PBKDF2 不是加密,它是散列)?
  • @martinstoeckli,我没有加密密码,也没有将其哈希存储在任何地方。我只是从字符串密码中导出加密密钥(和 iv),然后用它加密有效负载。
  • 我想我现在明白了。您想先从密码计算哈希值,然后使用此哈希值加密某些数据(而不是直接使用原始密码)。

标签: c# .net security encryption cryptography


【解决方案1】:

盐应该每个密码都是唯一的,这意味着为您要散列的每个密码创建一个随机密码。 salt 不是秘密,可以使用您计算的哈希值存储纯文本。

盐的想法是,攻击者不能使用预建的彩虹表来获取密码。他必须为每个密码分别建立这样一个彩虹表,这没有意义。在找到匹配之前,暴力破解更容易。

MSDN 中有一个示例,其中盐是从操作系统的随机源获取的。这是你能做的最好的事情,为了获得安全的盐,不要从你的密码中得到它。

【讨论】:

    【解决方案2】:

    盐旨在通过使每个目标的行为不同来防止多目标攻击。彩虹表只是多目标攻击的一种特殊形式,在获得目标之前就已经花费了计算量。

    有适用多目标攻击但彩虹表不适用的情况。

    其中一个示例:假设您使用具有语义安全性的经过身份验证的加密方案,例如具有唯一随机数的 AES-GCM。现在您已经获得了一百万条使用不同密码加密的不同消息。

    如果你不使用盐,为了检查密码是否适用于其中任何一个,攻击者需要一次 KDF 操作和 一百万次解密 操作。如果你使用盐,攻击者需要一百万次KDF操作和一百万次解密操作。由于与解密相比,KDF 速度较慢,因此对第一种方案的攻击比对第二种方案的攻击要快得多。

    【讨论】:

      【解决方案3】:

      我真的不知道Rfc2898DeriveBytes 是什么,但我可以告诉你以下内容:salt 不一定是安全的。现在,您说您已经看到人们抱怨盐的硬编码、恒定值,以及谁说的都是对的。盐应该是一个随机值,而不是一个常数,否则它的目的就失败了。

      你了解盐的用途吗?你显然没有。使用散列作为盐是一个坏主意,因为密码 X 将始终使用相同的值 Y 加盐,这再次违背了它的目的。

      【讨论】:

      • RFC 2898 也称为基于密码的密钥派生函数 2 或 PBKDF2。
      • @akton 谢谢。但是,TX_ 的问题是不了解盐的用途。
      • 当你说“我真的不知道什么是 Rfc2898DeriveBytes”时,我只是想帮忙。我同意您对从明文或消息中派生的盐的评论。
      • @akton,我明白了,这就是为什么我以“谢谢”开始我之前的评论:)
      【解决方案4】:

      人们不喜欢硬编码的盐,因为项目的所有开发人员(在开源项目或逆向工程的情况下也可能是公众)都可以使用它们。然后,攻击者可以为您的特定盐计算彩虹表并开始攻击您的系统。

      盐值的好选择是:

      • 每次检查密码时都可用
      • 在密码检查之间不改变
      • 每个(或大多数)密码计算都不同

      用户名将是一个不错的选择,前提是它不能更改。或者,在您首次创建用户时生成一个完全随机的值,并将其与用户数据一起存储在数据库中。

      【讨论】:

        【解决方案5】:

        其他人已经解释了盐的用途,以及为什么它可以成为公共信息。

        您的问题的答案的另一个部分:不要从密码本身中提取盐。这与在 Ashley Madison 黑客事件后最终暴露数百万个密码的编程错误非常相似。

        问题在于,当您使用密码生成 salt 时,您实际上是在瞬间使密码可用,而且更容易破解。攻击者可以完全忽略 PBKDF2 的输出,并简单地反转 salt 本身。那只受 SHA1 保护,它已经被破坏了。

        在 Ashley Madison,错误类似。密码使用 bcrypt 存储在主数据库中,并且被认为是安全的。但是后来有人发现,很多账号的密码实际上被存储了两次,而第二个副本只使用了 MD5 保护。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-02
          • 2011-12-06
          • 2019-08-13
          • 2015-05-27
          • 2011-04-30
          相关资源
          最近更新 更多