从 Rfc2898DeriveBytes 生成 AES IV
Generating AES IV from Rfc2898DeriveBytes
我正在使用 Rfc2898DeriveBytes
生成 AES
密钥和 iv
。但是,我听说 iv
不应该依赖于密码。以下是我现在的做法:
byte[] salt = GenerateRandomBytes(32); // Generates 32 random bytes
using (Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(plainStrPassword, salt)) {
byte[] aesKey = rfc.GetBytes(32);
byte[] iv = rfc.GetBytes(16); // Should I do this or generate it randomly?
}
我的问题:从 Rfc2898DeriveBytes
生成 iv
是否可以(安全)?或者我应该使用 RNGCryptoServiceProvider
?
随机生成它
Many cryptographic algorithms are expressed as iterative algorithms. E.g., when encrypting a message with a block cipher in CBC mode, each message "block" is first XORed with the previous encrypted block, and the result of the XOR is then encrypted. The first block has no "previous block" hence we must supply a conventional alternate "zero-th block" which we call "initialization vector". Generally speaking, an IV is whatever piece of data is needed to begin running an algorithm, and is not secret (if it was secret, we would call it a "key", not an IV).
IV 是一个任意常数,因此任何值都可以。确保您的加密器和解密器使用相同的值。有关更多信息,您可以参考这些链接:
https://crypto.stackexchange.com/questions/732/why-use-an-initialization-vector-iv
不,从您派生密钥的同一来源派生 IV 是不安全的。 IV 的存在使得在相同密钥下对相同消息的加密产生不同的密文。
您应该使用加密安全的随机源(例如您确定的 RNGCryptoServiceProvider
)来导出 IV 并将其与密文一起传送(通常作为一个字节流添加到密文之前,或者在一个单独的结构化文件格式中的字段)。
基于this MS Docs,使用Rfc2898DeriveBytes
从密码生成iv就可以了。 Rfc2898DeriveBytes
是 PBKDF2 的实现,其目的是:基于密码的密钥派生功能。请参阅此处的示例。
PS: 你应该使用 RNGCryptoServiceProvider
生成盐。
让我们看看你的代码;
byte[] salt = GenerateRandomBytes(32); // Generates 32 random bytes
using (Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(plainStrPassword, salt)) {
byte[] aesKey = rfc.GetBytes(32);
byte[] iv = rfc.GetBytes(16); // Should I do this or generate it randomly?
}
- 随机盐 - 好
- Rfc2898DeriveBytes 加盐;只要用户密码具有良好的强度,这就很好。派生密钥的强度(不是熵!)不能超过密码的强度。
- 为密钥调用 GetBytes(32) - 很好,这是预期的。
- 为 IV 调用 GetBytes(16) -
这个也不错; since
Repeated calls to this method will not generate the same key; instead, appending two calls of the GetBytes method with a cb parameter value of 20 is the equivalent of calling the GetBytes method once with a cb parameter value of 40.
对于每次加密,您可以通过调用GetBytes(16)
继续获取新的IV。当然,这是有限制的。 PKKDF2 标准限制输出 2^32-1 * hLen
,见 RFC 8018.
将一部分输出为IV并保留一部分作为加密密钥没有错。已经有大量使用 PBKDF2 的密码方案,即使密码哈希和加盐值已知,也没有一个被破解。
如果您担心这不是一个好主意,那么您可以使用其中之一;
- 生成两个盐并分别导出 IV 和加密密钥以形成密码;
byte[] saltForKey = GenerateRandomBytes(32); // Generates 32 random bytes
using (Rfc2898DeriveBytes rfcKey = new Rfc2898DeriveBytes(plainStrPassword, saltForKey)) {
byte[] aesKey = rfcKey.GetBytes(32);
byte[] saltForIV = GenerateRandomBytes(32); // Generates 32 random bytes
using (Rfc2898DeriveBytes rfcIV = new Rfc2898DeriveBytes(plainStrPassword, saltForIV)) {
byte[] iv = rfcIV.GetBytes(16); // Should I do this or generate it randomly?
}
- 生成随机 Salt 并导出加密密钥并生成随机 IV
byte[] salt = GenerateRandomBytes(32); // Generates 32 random bytes for Salt
byte[] IV = GenerateRandomBytes(16); // Generates 16 random bytes of IV
using (Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(plainStrPassword, salt)) {
byte[] aesKey = rfc.GetBytes(32);
}
请注意,您没有定义加密模式。对于
这样的模式
- CTR模式,96位nonce,32位计数器通用。为此,96 位随机数也可以由 counter/LFSR 生成。确保永远不会出现 (key,IV) 对。
- CBC模式,nonce必须是随机的,不可预测的。以上就可以了。
- 当然,您应该忘记这些并使用经过身份验证的加密模式,例如 AES-GCM、ChaCha20-Poly1305。如果您担心 IV 重用,请使用 AES-GCM-SIV,它只会泄漏您发送的相同消息,不会泄漏任何其他信息。 SIV 模式只是慢了 to 倍,因为它必须通过明文来导出 IV,然后执行加密。
我正在使用 Rfc2898DeriveBytes
生成 AES
密钥和 iv
。但是,我听说 iv
不应该依赖于密码。以下是我现在的做法:
byte[] salt = GenerateRandomBytes(32); // Generates 32 random bytes
using (Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(plainStrPassword, salt)) {
byte[] aesKey = rfc.GetBytes(32);
byte[] iv = rfc.GetBytes(16); // Should I do this or generate it randomly?
}
我的问题:从 Rfc2898DeriveBytes
生成 iv
是否可以(安全)?或者我应该使用 RNGCryptoServiceProvider
?
Many cryptographic algorithms are expressed as iterative algorithms. E.g., when encrypting a message with a block cipher in CBC mode, each message "block" is first XORed with the previous encrypted block, and the result of the XOR is then encrypted. The first block has no "previous block" hence we must supply a conventional alternate "zero-th block" which we call "initialization vector". Generally speaking, an IV is whatever piece of data is needed to begin running an algorithm, and is not secret (if it was secret, we would call it a "key", not an IV).
IV 是一个任意常数,因此任何值都可以。确保您的加密器和解密器使用相同的值。有关更多信息,您可以参考这些链接:
https://crypto.stackexchange.com/questions/732/why-use-an-initialization-vector-iv
不,从您派生密钥的同一来源派生 IV 是不安全的。 IV 的存在使得在相同密钥下对相同消息的加密产生不同的密文。
您应该使用加密安全的随机源(例如您确定的 RNGCryptoServiceProvider
)来导出 IV 并将其与密文一起传送(通常作为一个字节流添加到密文之前,或者在一个单独的结构化文件格式中的字段)。
基于this MS Docs,使用Rfc2898DeriveBytes
从密码生成iv就可以了。 Rfc2898DeriveBytes
是 PBKDF2 的实现,其目的是:基于密码的密钥派生功能。请参阅此处的示例。
PS: 你应该使用 RNGCryptoServiceProvider
生成盐。
让我们看看你的代码;
byte[] salt = GenerateRandomBytes(32); // Generates 32 random bytes
using (Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(plainStrPassword, salt)) {
byte[] aesKey = rfc.GetBytes(32);
byte[] iv = rfc.GetBytes(16); // Should I do this or generate it randomly?
}
- 随机盐 - 好
- Rfc2898DeriveBytes 加盐;只要用户密码具有良好的强度,这就很好。派生密钥的强度(不是熵!)不能超过密码的强度。
- 为密钥调用 GetBytes(32) - 很好,这是预期的。
- 为 IV 调用 GetBytes(16) -
这个也不错; since
Repeated calls to this method will not generate the same key; instead, appending two calls of the GetBytes method with a cb parameter value of 20 is the equivalent of calling the GetBytes method once with a cb parameter value of 40.
对于每次加密,您可以通过调用GetBytes(16)
继续获取新的IV。当然,这是有限制的。 PKKDF2 标准限制输出 2^32-1 * hLen
,见 RFC 8018.
将一部分输出为IV并保留一部分作为加密密钥没有错。已经有大量使用 PBKDF2 的密码方案,即使密码哈希和加盐值已知,也没有一个被破解。
如果您担心这不是一个好主意,那么您可以使用其中之一;
- 生成两个盐并分别导出 IV 和加密密钥以形成密码;
byte[] saltForKey = GenerateRandomBytes(32); // Generates 32 random bytes
using (Rfc2898DeriveBytes rfcKey = new Rfc2898DeriveBytes(plainStrPassword, saltForKey)) {
byte[] aesKey = rfcKey.GetBytes(32);
byte[] saltForIV = GenerateRandomBytes(32); // Generates 32 random bytes
using (Rfc2898DeriveBytes rfcIV = new Rfc2898DeriveBytes(plainStrPassword, saltForIV)) {
byte[] iv = rfcIV.GetBytes(16); // Should I do this or generate it randomly?
}
- 生成随机 Salt 并导出加密密钥并生成随机 IV
byte[] salt = GenerateRandomBytes(32); // Generates 32 random bytes for Salt
byte[] IV = GenerateRandomBytes(16); // Generates 16 random bytes of IV
using (Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(plainStrPassword, salt)) {
byte[] aesKey = rfc.GetBytes(32);
}
请注意,您没有定义加密模式。对于
这样的模式- CTR模式,96位nonce,32位计数器通用。为此,96 位随机数也可以由 counter/LFSR 生成。确保永远不会出现 (key,IV) 对。
- CBC模式,nonce必须是随机的,不可预测的。以上就可以了。
- 当然,您应该忘记这些并使用经过身份验证的加密模式,例如 AES-GCM、ChaCha20-Poly1305。如果您担心 IV 重用,请使用 AES-GCM-SIV,它只会泄漏您发送的相同消息,不会泄漏任何其他信息。 SIV 模式只是慢了 to 倍,因为它必须通过明文来导出 IV,然后执行加密。