我正在使用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
随机生成?
让我们看看您的代码;
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?
}
- 随机盐-好
- Rfc2898带盐的eriveBytes;只要用户密码具有良好的强度,这就很好。派生密钥的强度(而不是熵!(不能超过密码的强度
- 调用GetBytes(32(获取密钥-好,这是预期的
- 调用GetBytes(16(进行IV-
这也很好;自
重复调用此方法不会生成相同的键;相反,附加两个cb参数值为20的GetBytes方法调用相当于一次cb参数为40的GetByte方法调用。
对于每次加密,您可以通过调用GetBytes(16)
继续获得新的IV。当然,这是有限度的。PKKDF2标准限制输出2^32-1 * hLen
,请参阅RFC 8018。
将某些部分输出为IV并保留某些部分作为加密密钥没有错。已经有大量使用PBKDF2的密码方案,甚至密码哈希和salt都已被破解。
如果你担心这不是一个好主意,那么你可以使用其中之一;
- 生成两个salt,并分别导出IV和加密密钥以形成密码as
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并导出加密密钥,jus生成随机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位随机数也可以由计数器/LFSR生成。确保(密钥,IV(对永远不会出现
- CBC模式,nonce必须是随机的和不可预测的。以上内容适用于此
- 当然,您应该忘记这些,并使用经过身份验证的加密模式,如AES-GCM、ChaCha20-Poly1305。如果你担心IV重复使用,那么使用AES-GCM-SIV,它只能泄漏你发送的相同消息,而不会泄漏其他消息。SIV模式只慢了几倍,因为它必须通过明文才能导出IV,然后执行加密
不,从派生密钥的同一源派生IV是不安全的。IV的存在使得在相同密钥下对相同消息的加密产生不同的密文。
您应该使用加密安全的随机源(如您识别的RNGCryptoServiceProvider
(来导出IV,并将其与密文一起进行通信(通常作为一个字节流预处理在密文中,或者在更结构化的文件格式中的单独字段中(。
许多加密算法都表示为迭代算法。例如,当在CBC模式下用分组密码对消息进行加密时;块";首先与先前加密的块进行异或,然后对异或的结果进行加密。第一块没有"0";前一块";因此,我们必须提供一种传统的替代品";第0个块";我们称之为";初始化矢量";。一般来说,IV是开始运行算法所需的任何数据,它不是秘密的(如果它是秘密的,我们会称之为"密钥",而不是IV(。
IV是一个任意常数,因此任何值都有效。确保加密器和解密器使用相同的值。有关更多信息,您可以参考以下链接:
https://crypto.stackexchange.com/questions/732/why-use-an-initialization-vector-iv
https://crypto.stackexchange.com/questions/3965/what-is-the-main-difference-between-a-key-an-iv-and-a-nonce
基于此MS文档,可以使用Rfc2898DeriveBytes
从密码生成iv。Rfc2898DeriveBytes
是PBKDF2的实现,其目的是:基于密码的密钥派生功能。请参阅此处的示例。
附言:你应该使用RNGCryptoServiceProvider
来生成盐。