我正在使用
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?
}
我的问题:从
iv
生成 Rfc2898DeriveBytes
是否可以(安全)?或者我应该使用 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?
}
这也很好; 自从
重复调用该方法不会生成相同的密钥;相反,使用 cb 参数值 20 追加两次 GetBytes 方法调用相当于使用 cb 参数值 40 调用一次 GetBytes 方法。
对于每次加密,您可以通过调用
GetBytes(16)
继续获取新的 IV。当然,这是有限制的。 PKKDF2 标准限制输出2^32-1 * hLen
,请参阅RFC 8018。
输出一部分作为 IV 并保留一部分作为加密密钥并没有什么问题。已经有大量使用 PBKDF2 的密码方案,即使密码哈希和盐已知,也没有被破解。
如果您担心这不是一个好主意,那么您可以使用其中一个;
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?
}
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);
}
请注意,您没有定义加密模式。对于类似
的模式不,从派生密钥的同一来源派生 IV 并不安全。 IV 的存在使得相同的消息在相同的密钥下加密会产生不同的密文。
您应该使用加密安全的随机源(例如您确定的
RNGCryptoServiceProvider
)来导出 IV 并将其与密文一起传递(通常作为一个字节流添加到密文之前,或者在更结构化的文件中的单独字段中)格式)。
许多密码算法都表示为迭代算法。例如,当在 CBC 模式下使用分组密码加密消息时,每个消息“块”首先与前一个加密块进行异或,然后对异或的结果进行加密。第一个块没有“前一个块”,因此我们必须提供一个传统的替代“第零块”,我们称之为“初始化向量”。一般来说,IV 是开始运行算法所需的任何数据,并且不是秘密的(如果它是秘密的,我们将其称为“密钥”,而不是 IV)。
IV 是任意常数,因此任何值都可以。确保您的加密器和解密器使用相同的值。欲了解更多信息,您可以参考这些链接:
https://crypto.stackexchange.com/questions/732/why-use-an-initialization-vector-iv
基于this MS Docs,可以使用
Rfc2898DeriveBytes
从密码生成iv。 Rfc2898DeriveBytes
是PBKDF2的实现,其目的是:基于密码的密钥派生功能。请参阅那里的示例。
PS:你应该使用
RNGCryptoServiceProvider
来生成盐。