【问题标题】:Generating AES IV from Rfc2898DeriveBytes从 Rfc2898DeriveBytes 生成 AES IV
【发布时间】:2021-05-17 17:53:09
【问题描述】:

我正在使用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 随机生成?

【问题讨论】:

标签: c# security encryption aes


【解决方案1】:

让我们看看你的代码;

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

重复调用此方法不会生成相同的密钥;相反,附加两个 cb 参数值为 20 的 GetBytes 方法调用相当于调用一次 GetBytes 方法,其 cb 参数值为 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 位计数器很常见。为此,计数器/LFSR 也可以生成 96 位随机数。确保永远不会出现 (key,IV) 对。
  • CBC 模式,nonce 必须是随机且不可预测的。上面的就可以了。
  • 当然,您应该忘记这些并使用经过身份验证的加密模式,如 AES-GCM、ChaCha20-Poly1305。如果您担心 IV 重用,请使用 AES-GCM-SIV,它只会泄漏您发送相同的消息,没有其他泄漏。 SIV 模式只是慢了几倍,因为它必须通过明文来导出 IV,然后执行加密。

【讨论】:

  • 我认为 GetBytes(16) 会生成一个独立于 GetBytes(32) 的 byte[]。不过我可能错了
  • OP 代码中的调用 rfc.GetBytes(16) 不返回密钥的前 16 个字节,而是返回密钥后面的 16 个字节。因此,OP 的代码相当于您使用GetBytes(48) 的第二个场景,请参阅here
  • @Topaco,我已经更新了。是的,每个电话都有不同的。你能查一下吗?
  • @Win32ApiUSer 我已经更新了,Topaco 对,后续调用返回不同,所以没有危险。
  • 第二个代码 sn-p:rfcIV.GetBytes(16) 中的一个小错字在确定 IV 时必须使用。除此之外一切似乎都很好。
【解决方案2】:

不,从派生密钥的同一来源派生 IV 是不安全的。 IV 的存在使得在相同密钥下对相同消息的加密会产生不同的密文。

您应该使用加密安全的随机源(例如您确定的 RNGCryptoServiceProvider)来导出 IV 并将其与密文一起通信(通常作为一个字节流添加到密文之前,或者在一个单独的字段中结构化文件格式)。

【讨论】:

  • 啊。好,谢谢。这或多或少是我的预期
  • What are you say in the first sentence意味着,如果给定PBKDF2的输出,那么您可以找到密码。为什么从单个 PBKDF2 的输出中导出 IV 和密钥不安全?你能详细说明一下吗?使用 PBKDF2 有大量密码 hashing shemes
  • @kelalaka - 我不明白我的句子是如何暗示的。我的意思是从获得密钥的相同材料中确定性地得出 IV 是错误的。这并没有说明能够向后工作。不应使用相同的密钥重复使用 IV,但在这种情况下,您可以保证每次使用相同的密钥时都会使用相同的 IV。
  • 您的第一句话确实暗示了这一点。 OP 的代码为此生成一个密钥和一个 IV。它不是为单个密钥生成许多 IV 的代码。操作模式没有提到,SIV 模式对于 IV 重复使用问题非常安全。它是为这种情况设计的。
【解决方案3】:

许多加密算法都表示为迭代算法。例如,在 CBC 模式下使用块密码加密消息时,每个消息“块”首先与前一个加密块进行异或,然后对异或的结果进行加密。第一个块没有“前一个块”,因此我们必须提供一个传统的替代“第零块”,我们称之为“初始化向量”。一般来说,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

【讨论】:

  • 你说得对,任何值都可以,但有些值并不安全。例如,您不应该对 IV 进行硬编码。
  • 是的,你不应该。你可以为 IV 使用任何随机值,只要你复制它或再次获取它。
  • 是的,我明白了。但我的问题是使用从密码生成的 IV 是否安全?
【解决方案4】:

基于this MS Docs,可以使用Rfc2898DeriveBytes从密码生成iv。 Rfc2898DeriveBytes 是 PBKDF2 的实现,其目的是:基于密码的密钥派生功能。请参阅那里的示例。

PS:你应该使用RNGCryptoServiceProvider 来生成盐。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-07
    • 1970-01-01
    • 2020-12-09
    • 2011-11-08
    • 2021-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多