1

我正在为我们数据库中的敏感数据编写一个加密序列。

目前我正在使用基于 UserId 的 GUID,并将其放入哈希中。然后,我通过 Rfc2898DeriveBytes 运行哈希以获取用于使用 Rijndael 函数加密数据的密钥和 IV。

我的代码如下所示:

        var salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };
        const int iterations = 1000;
        using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(GenerateHash("2525"), salt, iterations)) {
            _key = rfc2898DeriveBytes.GetBytes(32);
            _iv = rfc2898DeriveBytes.GetBytes(16);
        }

然后我传递 _key 和 _iv 来解密或加密数据。我的目标是让每个用户在每个会话中始终可以访问他们的唯一密钥。话虽如此,什么可以随机化并且仍然保持这个功能?我是否总是必须使用相同的盐和相同的 IV 来获取我想要的数据?

4

1 回答 1

5

Rfc2898DeriveBytes是 PBKDF2 的实现。显然,RFC 2898 是对定义此基于密码的密钥派生函数的标准的参考。请注意,该标准比 KDF 更广泛;它的全称是“PKCS #5: Password-Based Cryptography Specification, Version 2.0”。

PBKDF2 是定义 PBKDF / PBKDF1 的 PKCS#5 v1 的继承者。1 是在 PBKDF2 产生后才添加的。该类PasswordDeriveBytes是 PBKDF1 的实现。它不应该再使用了,因为 KDF 已经过时了,也因为微软严重搞砸了实现;如果请求超过底层哈希的输出 - SHA-1 所以 20 个字节 -它可能会重复输出密钥材料。

除了 KDF,PBKDF2 还用作密码散列函数,其中散列而不是密码存储在数据库中。这样可以验证密码,而如果数据被对手检索,则密码无法轻松检索。这在包含 2.1 版本协议的后续RFC 8018中进行了描述。

在内部,PBKDF2 只是对密码和盐的哈希函数的重复。迭代次数是工作因子;它指定了在计算一个哈希值之前你(和对手)需要做多少工作。盐确保彩虹表攻击是不可能的,并且相同的密码(多个用户)不会导致相同的哈希。

由于设计错误,如果需要多个哈希输出,则需要重复全部工作,因此不建议从中请求比哈希函数的输出更多的数据。在这种情况下,最好使用另一种方法来扩展输出密钥材料(字节),例如 HKDF-Expand。


对问题中代码的观察:

  1. GenerateHash方法是虚假的,Rfc2898DeriveBytes将为您执行此操作;
  2. 您应该使用比 UID 更难预测的东西来创建密钥;数据不应直接提供给攻击者,因为这将完全违背 PBKDF2 的目的;
  3. 如果您想使用同一组 UID + salt + 迭代进行多次加密,那么您应该生成一个随机 IV 并将其添加到密文中,非随机 IV 完全违背了 IV 的目的;
  4. 您可以更改盐以获取多个密钥,但您必须通过 PBKDF2 函数进行每次加密。

只是一个一般提示,仅使用生成的密钥来加密由安全随机函数创建的数据特定密钥。然后,您甚至不需要担心 IV,您可以通过解密数据特定密钥并使用新密钥对其进行加密来“重新加密”。

于 2012-08-22T21:07:47.863 回答