使用 AES 在数据库中加密密码时是否需要 Salt、IV 和 Key?如果是这样,它们应该如何使用?

信息安全 加密 密码 AES 初始化向量
2021-09-06 08:05:59

想象一下,我有一个带有用户帐户的网站。我想对用户进行身份验证,所以我需要知道他们提供的密码是否与存储在我的数据库中的密码匹配。为了保护密码不被窥探,我想混淆它们,我决定在 CBC 模式下使用 AES 来做到这一点。

我知道我不应该使用 AES-CBC 来执行此操作,并且可能应该使用散列算法而不是加密算法,但是请忽略这个事实。如果你这样做,它将帮助我更好地理解事情。

使用 AES-CBC 加密用户密码以将其存储在我的数据库中时,我是否需要使用密钥、IV 和 Salt?无论我需要使用什么,它们将如何使用?

我将举一个例子来更好地解释我的问题:

用户名为“bob”的用户使用密码“mypass”注册

我需要确定使用 AES-CBC 混淆此密码的最安全方法是什么。

现在我认为要做到这一点,我需要使用 CSPRNG[1] 生成一个 16 字节的盐。比我必须在盐前面加上用户密码:salt+“mypass”。我必须使用 AES-CBC 加密 salt+“mypass”,我将使用硬编码的 256 位密钥和随机生成的 16 字节 IV。

实际上我有: AesEncrypt(salt+"mypass", GenerateIv(), Key)

鉴于这个例子,我有几点让我感到困惑。

1)我传递给 AES 的随机 IV 将产生没有两个“mypass”给出相同密文的效果。这不会使加盐变得多余,因为加盐的目的是防止“mypass”的两个密文相同?

2)相反,IV是否是多余的,我可以只传入零IV或恒定IV,因为我正在加盐我的密码?

3)说IV和salt不是多余的,因为不知何故我读到并没有真正理解IV是XORed而不是salt,因此两者都很有用。我只需在“mypass”前面加上盐就可以适当加盐了吗?

4)我是否应该以某种方式使用盐来派生我将用于使用 AES 加密“mypass”的密钥?或者我只是通过使用硬编码的密钥来做对了吗?

5) 我应该在我的数据库中存储什么?盐、iv 和密文应该都存储在单独的列中,还是应该以某种方式组合在一起,如果是这样,简单的连接就足够了,还是必须与特殊功能组合?

6)我完全错了,如果是,我应该怎么做?

谢谢。

==============

[1] 密码安全的伪随机数生成器

2个回答

使用 AES-CBC 加密用户密码以将其存储在我的数据库中时,我是否需要使用密钥、IV 和 Salt?无论我需要使用什么,它们将如何使用?

IV 用于初始化 AES-CBC 加密方案的前 16 字节矩阵。它与消息的前 16 个字节进行异或。这意味着,如果 IV 是常数,则相同的消息将始终输出相同的密文。另一方面,如果IV在同一消息的每次加密运行中都不同,由于IV与第一个块的异或,密文总是不同的,因为异或的结果会不同。IV 是 AES-CBC 的固有部分,您将始终必须使用 IV,选择是该 IV 是否为常数。

Salt 是一个随机消息,您将其添加到真实消息之前,因此在真实消息的每次编码中,您实际上都在对不同的消息(盐 + 真实消息)进行编码,这将导致不同的密文。这通常用于散列算法,以便在每次运行相同消息的散列时获得不同的散列。

您不需要将盐与 AES-CBC 一起使用,因为 IV 已经具有盐的设计效果。但如果你想使用盐,你可以,这就是会发生的事情。假设您有一个 16 字节的盐,它将被添加到您的消息中,因此您将 (salt + message) 作为要由 AES-CBC 加密的输入。作为 16 字节,您的盐将适合 AES-CBC 的第一个块,它将与 IV 异或,因此您将拥有(盐异或 iv)。(salt XOR iv) 的结果将被用作第二个块的 IV,在这种情况下,它将是真实消息的第 16 个字节。

因此,在 AES-CBC 的情况下,使用盐只会对您的 IV 进行额外处理。如果您的 IV 是恒定的,则盐将与它进行异或运算,从而为第二个块生成一个新的 IV,即使 IV 是恒定的,每次运行的加密也是不同的。

所以总而言之,你最好只使用随机IV而不使用盐。或者使用恒定的 IV 并使用随机盐(但请注意这一点,请参阅下面的 #2 了解详细信息)。这两者将具有相同的效果,即在同一消息的每次加密运行中生成不同的密文。

1)我传递给 AES 的随机 IV 将产生没有两个“mypass”给出相同密文的效果。这不会使加盐变得多余,因为加盐的目的是防止“mypass”的两个密文相同?

是的,它确实。IV 和盐有效地具有相同的效果,并有助于防止相同的攻击。请注意,要使盐具有相同的效果,必须考虑在其实现中的正确考虑,有关更多详细信息,请参见下面的#2。

2)相反,IV是否是多余的,我可以只传入零IV或恒定IV,因为我正在加盐我的密码?

没那么快。很多事情必须正确地放在一起才能做到这一点。根据 AES 的模式,加盐可能会导致所需的行为并不总是正确的。您的盐长度以及将其与消息连接的方式也必须正确,例如,附加可能会导致长密码出现问题。因此,最好使用它所想到的 AES,即使用随机 IV 并且不使用盐。

3)说IV和salt不是多余的,因为不知何故我读到并没有真正理解IV是XORed而不是salt,因此两者都很有用。我只需在“mypass”前面加上盐就可以适当加盐了吗?

IV 与要加密的 CBC 模式下的第一个 AES 块进行异或运算。如果您使用盐,盐将与第一个块中的 IV 进行异或运算,并且这个(IV xor Salt)将有效地成为第二个的 IV,给定一个 16 字节的盐,这将是您要加密的实际消息.

4)我是否应该以某种方式使用盐来派生我将用于使用 AES 加密“mypass”的密钥?或者我只是通过使用硬编码的密钥来做对了吗?

您永远不应该从盐中获取密钥。盐不是秘密的,因此,如果你这样做,很容易从非秘密盐中找到密钥。我对基于密码的加密感到困惑,在这种加密中,您使用密钥派生函数从秘密密码中派生密钥。

5) 我应该在我的数据库中存储什么?盐、iv 和密文应该都存储在单独的列中,还是应该以某种方式组合在一起,如果是这样,简单的连接就足够了,还是必须与特殊功能组合?

据我了解,这并不重要,只要您知道如何检索它们即可。您可以使用不同的列,或者以某种方式将它们组合在一起。

6)我完全错了,如果是,我应该怎么做?

基本上,我使用 AES-CBC 作为散列函数。通常 AES 的 256 位密钥意味着很难暴力破解,这绕过了这一点,因为在这里你可以暴力破解消息的组合,因为消息是密码,很可能它比 256 位暴力破解要短得多力量。

另一个问题是,作为一种对称算法,如果黑客攻破了服务器,得到了密钥,他甚至不需要暴力破解、字典攻击、彩虹表或其他任何东西,他可以解密所有密码。

您是正确的,盐和 IV 是多余的:它们都可以防止相同类型的攻击(发现两个帐户具有相同的密码),并且它们以相同的方式进行(通过对密码进行加密表示)不同)。