简体   繁体   English

了解 Rfc2898DeriveBytes 的工作原理

[英]Understanding how Rfc2898DeriveBytes works

I'm writing an encryption sequence for sensitive data in our database.我正在为我们数据库中的敏感数据编写一个加密序列。

Currently I'm taking a GUID based on the UserId, and putting that through a hash.目前我正在使用基于 UserId 的 GUID,并将其放入哈希中。 Then, I run the hash through a Rfc2898DeriveBytes to get Key and IV which I use to encrypt the data using the Rijndael function.然后,我通过 Rfc2898DeriveBytes 运行哈希以获取用于使用 Rijndael 函数加密数据的密钥和 IV。

My code looks like this:我的代码如下所示:

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

I then pass the _key and _iv along to decrypt or encrypt the data.然后我传递 _key 和 _iv 来解密或加密数据。 My goal is to have each user always have access to their unique key through every session.我的目标是让每个用户在每个会话中始终可以访问他们的唯一密钥。 That being said, what can be randomized and still maintain this function?话虽如此,什么可以随机化并且仍然保持这个功能? Do I always have to use the same salt and the same IV to get the data I want?我是否总是必须使用相同的盐和相同的 IV 来获取我想要的数据?

Rfc2898DeriveBytes is an implementation of PBKDF2. Rfc2898DeriveBytes是 PBKDF2 的实现。 Obviously RFC 2898 is a reference to the standard where this Password Based Key Derivation Function has been defined.显然,RFC 2898 是对定义此基于密码的密钥派生函数的标准的参考。 Note that the standard is broader than just the KDF;请注意,该标准比 KDF 更广泛; it's full title is "PKCS #5: Password-Based Cryptography Specification, Version 2.0".它的全称是“PKCS #5: Password-Based Cryptography Specification, Version 2.0”。

PBKDF2 is a successor of PKCS#5 v1 which defined PBKDF / PBKDF1. PBKDF2 是定义 PBKDF / PBKDF1 的 PKCS#5 v1 的继承者。 The 1 was only added after PBKDF2 came into being. 1 是在 PBKDF2 产生后才添加的。 The class PasswordDeriveBytes is an implementation of PBKDF1. PasswordDeriveBytes类是 PBKDF1 的实现。 It should not be used anymore because both the KDF is outdated but also because Microsoft screwed up the implementation severely;它不应该再使用了,因为 KDF 已经过时了,也因为微软严重搞砸了实现; it may repeat output keying material if more than the output of the underlying hash - SHA-1 so 20 bytes - is requested.如果请求超过底层哈希的输出 - SHA-1 所以 20 个字节 - 它可能会重复输出密钥材料

Besides being used as KDF, PBKDF2 can also be used as password hashing function, where the hash instead of the password is stored in a database.除了用作 KDF 之外,PBKDF2 还可以用作密码散列函数,其中散列而不是密码存储在数据库中。 That way passwords can be verified, while the password cannot easily be retrieved even if the hash data is retrieved by an adversary.这样可以验证密码,而即使攻击者检索到哈希数据,也无法轻松检索密码。 This is described in the followup RFC 8018 which contains the 2.1 version of the protocol.这在包含 2.1 版本协议的后续RFC 8018中进行了描述。

Internally, PBKDF2 is just a repetition of a hash function over the password and salt.在内部,PBKDF2 只是对密码和盐的哈希函数的重复。 The iteration count is the work factor;迭代次数是工作因子; it specifies how much work you (and adversaries) have to do before one hash is calculated.它指定了在计算一个哈希值之前你(和对手)需要做多少工作。 The salt makes sure that rainbow table attacks are impossible, and that identical passwords (of different users) don't lead to the same hash.盐确保彩虹表攻击是不可能的,并且(不同用户的)相同的密码不会导致相同的哈希。

Due to a design error which requires the full amount of work to be repeated if more than one hash output is required, it is not recommended to request more data from it than the output of the hash function.由于设计错误,如果需要多个哈希输出,则需要重复全部工作,因此不建议从中请求比哈希函数的输出更多的数据。 In that case it is better to use another method to expand the output keying material (bytes), eg HKDF-Expand.在这种情况下,最好使用另一种方法来扩展输出密钥材料(字节),例如 HKDF-Expand。


Observations on the code in the question:对问题中代码的观察:

  1. The GenerateHash method is spurious, Rfc2898DeriveBytes will do this for you; GenerateHash方法是假的, Rfc2898DeriveBytes会为你做这个;
  2. You should use something less predictable than a UID to create a key;您应该使用比 UID 更难预测的东西来创建密钥; the data should not be directly available to an attacker as this would completely defeat the purpose of PBKDF2;数据不应直接提供给攻击者,因为这将完全违背 PBKDF2 的目的;
  3. If you want to use the same set of UID + salt + iterations for multiple encryption operations, then you should generate a random IV and prepend it to the ciphertext, having a non-random IV completely defeats the purpose of the IV;如果您想对多个加密操作使用同一组 UID + salt + 迭代,那么您应该生成一个随机 IV 并将其添加到密文中,非随机 IV 完全违背了 IV 的目的;
  4. You can change the salt to get multiple keys, but you would have to go through the PBKDF2 function for each and every encryption.您可以更改盐以获取多个密钥,但您必须通过 PBKDF2 函数进行每次加密。

Just a general hint, only use the resulting key to encrypt data specific keys created out of a secure random function.只是一个一般提示,仅使用生成的密钥来加密由安全随机函数创建的数据特定密钥。 Then you don't even need to bother about an IV, and you may be able to "re-encrypt" by decrypting the data specific key, and encrypting that with a new key.然后,您甚至不需要担心 IV,您可以通过解密数据特定密钥并使用新密钥对其进行加密来“重新加密”。

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

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