【问题标题】:Encryption with AES-256 and the Initialization Vector使用 AES-256 和初始化向量进行加密
【发布时间】:2010-12-22 07:13:37
【问题描述】:

我有一个关于在 AES 加密中使用初始化向量的问题。我正在参考以下文章/帖子以在我的程序中构建加密:

[1]Java 256-bit AES Password-Based Encryption
[2]http://gmailassistant.sourceforge.net/src/org/freeshell/zs/common/Encryptor.java.html

我最初从第一个链接开始关注埃里克森的解决方案,但据我所知,我的实现不支持 PBKDF2WithHmacSHA1。因此,我转向第二个链接以了解我自己的迭代 SHA-256 哈希创建的想法。

我的问题在于 IV 是如何创建的。一种实现 ([1]) 使用来自 Cypher 类的方法来派生 IV,而另一种实现 ([2]) 使用散列的第二个 16 字节作为 IV。很简单,为什么会有区别,从安全角度来看哪个更好?我对 IV 的推导和使用也有点困惑(我了解它们的用途,只是不了解细微的差异),因此也非常欢迎任何澄清。

我注意到第二个链接使用的是 AES-128 而不是 AES-256,这表明如果我想使用这种方法,我必须升级到 SHA-512。这似乎是一个不幸的要求,因为用户的密码必须长 16 个字符才能确保远程安全散列,而且这个应用程序是为手机而设计的。

来源可应要求提供,但仍不完整。

提前谢谢你。

【问题讨论】:

标签: java android encryption aes


【解决方案1】:

不应仅从密码生成 IV。

IV的一点是即使重复使用相同的密钥和明文,也会产生不同的密文。如果 IV 仅从密码确定性地产生,那么您每次都会得到相同的密文。在引用的示例中,salt 是随机选择的,因此即使使用相同的密码也会生成一个新密钥。

只需使用随机数生成器来选择 IV。这就是密码在内部所做的。


我想强调的是,您必须将 IV(如果您使用第一种方法)或盐(如果您使用第二种方法)与密文一起存储。如果一切都来自密码,那么您将没有很好的安全性;您需要在每条消息中添加一些随机性。

【讨论】:

  • 好的,这更有意义。那么还有一个问题:如果 Cypher 在内部使用随机数生成器,我该如何解密?据我了解,加密和解密都需要使用相同的 IV。他们是简单地使用密钥作为生成器的种子,以使每个密钥获得相同的 IV,还是有更多的事情发生?
  • @phobos51594 - 您必须将 IV 与密文一起存储。将 IV 视为密文的第一个块的一种方法是,您可以将其存储为密码实际输出的前缀。管他呢。它不需要保密;只需将其与其余密文一起存储即可。
  • 忽略之前的评论,我刚看到你的编辑。这更有意义。因此,该模式将大致如下:散列密码,使用 Cypher 或安全随机功能生成 IV,使用 hash-IV-salt 加密,存储以前的值,使用存储的值解密,丢弃 IV,庆祝,重复。跨度>
  • 正如 phobos51594 所指出的,由于“PBKDF2WithHmacSHA1”算法导致 NoSuchAlgorithmException,链接 [1] 在 Android 上不起作用,但“PBEWITHSHA256AND128BITAES-CBC-BC”似乎工作正常。
【解决方案2】:

密码学家应使用安全的伪随机随机数生成器生成 IV。

应用程序开发人员应使用现有的现成加密技术。我建议您使用带有证书的 SSL 来保护您的网络流量,并使用 GPG 来保护文件数据。

有太多细节会导致实现不安全,例如timing attacks。当应用程序开发人员在 AES 128 和 AES 256 之间做出决定时,这几乎总是毫无意义的,因为您可能留下了导致额外密钥位无用的定时攻击。

【讨论】:

  • 我在原帖中没有提到这一点,但这不适用于任何类型的网络流量。我将加密一个永远不会离开设备的文件,除非整个系统受到威胁。
  • 所以您要将加密密钥和加密文件放在同一设备上?这是没有意义的。
  • 定时攻击真的是网络应用程序中的一个问题吗?我会假设网络速度的变化会抹去这些信息。如果不是简单的睡眠,直到 Xms 过去加密开始将解决此问题。
【解决方案3】:

我的理解是初始化向量只是加密算法的随机输入,否则对于相同的输入,您总是会得到相同的结果。初始化向量与密文一起存储,无论如何都不是秘密。只需使用安全随机函数来生成初始化向量。 PBKDF* 算法用于根据用户输入的密码为加密算法派生所需长度的密钥。

您链接到的第一个实现只是让 Cipher 对象生成初始化向量。然后它会获取这个生成的 IV 并将其与密文一起存储。

第二个使用部分哈希字节。任何生成非重复 IV 的方法都足够好。

IV 最重要的特性是它不重复(非常频繁)。

【讨论】:

  • 我假设我必须存储 IV,除非我以某种方式从原始密钥派生它?所以第一个实现实际上比我想象的更类似于第二个实现,因为它们都(以某种方式)从给定的密钥中获取 IV?在那种情况下,我不能只使用密钥作为 IV 吗?
  • 好吧,密钥必须保密。 IV是公开的。您不想将密钥用作您的 IV,否则您将向所有人广播您的密钥!出于同样的原因,但在较小程度上,这就是为什么您不希望基于使用散列的密钥来获得 IV。 (就像 [2] 所做的那样)因为如果散列算法在其中发现了一个弱点,攻击者可以从 IV 中获取您的密钥。
  • 好的,这很有道理。所以 [2] 真的只是不好的做法。
  • @phobos51594:确实有点奇怪... [2] 使用 key + salt 生成哈希,并从哈希中提取 IV。现在随机性问题取决于盐。如果有人每次都通过相同的盐,他们将得到相同的 IV,这是个问题。 [2] 的问题是现在您必须记住盐以及 IV :-)
  • 在 [2] 中,由于 IV 完全来自 salt+密码,因此您不需要存储 IV。您可以只存储盐并在运行时将其与密码结合以生成 IV。但是这样的设计让IV的强度等于盐的强度。而且我认为我在代码中没有看到盐的任何长度保证。它可能非常小,具体取决于它的使用方式。
【解决方案4】:

IV 只是使用区块链的结果。我认为这不仅仅是一个简单的 API 设计问题。我假设您知道使用它的原因是相同的明文不会在多个块中显示为相同的密文。

考虑从最后一个块开始的递归,其中第 N 个密文块以某种方式依赖于第 (N-1) 个块等。当你到达第一个块,第 0 个块时,你需要一些数据才能开始。只要您在尝试解密之前就知道该数据是什么并不重要。使用非秘密随机数据作为初始化向量将导致在相同密钥下加密的相同消息以完全不同的密文形式出现。

它在概念上类似于加盐哈希。那个源代码在我看来有点可疑。 IV 应该只是 fresh-at-encryption-time 不依赖任何东西的随机位,例如 nonce。 IV 基本上是加密消息的一部分。如果您使用相同的密钥重新加密相同的数据,您应该无法关联这些消息。 (嘿,想想密文长度相关的后果。)

【讨论】:

  • 那一点是有道理的。我的困惑在于生成一个 IV 以使最好的加密成为可能(在实用性范围内)。
  • 试图绕过使用加密数据传输 IV 的负担违背了拥有 IV 的目的。使用源自秘密的 IV 是没有意义的,它实际上违背了它的目的。关键是 IV 是新鲜的不可预测的,因此以前加密的消息无法关联。
  • 有时新的 IV 被计算为 (previous IV) + 1,所以它是可以预测的。我不确定这是否会带来一些问题。
  • @Peter,我明白你的意思了。但是您仍然需要隐式或显式地传输 IV 作为消息的一部分,即使这仅在会话中的一系列加密中的第一个上完成。但是,请考虑一下在没有关于特定密码的详细信息的情况下提供此建议的时间。使用可预测的 IV,与随机 IV 相比,能够关联消息的机会肯定会更高(或相同)。
  • 谜题:我的密码的 2 个实例具有相同的密钥,每个实例使用从 0 开始并递增的 IV。如果我总是对相同数量的消息进行编码,就会存在相关性。如果只有一个实例,则递增会使周期最大化,直到已知它会重复。所以我猜如果你使用随机生成的 IV,决定因素将是产生碰撞的概率。
【解决方案5】:

和这里的其他人一样,我一直都知道 IV 只是使用标准算法随机选择的。

不过,您提供的第二个参考资料似乎没有这样做。看起来他对密码进行了加盐并对其进行哈希处理。然后获取该哈希并将其分成两半。一半是加密密钥,一个是IV。所以IV是从密码中得出的。

我对这种方法没有任何强烈的休息,但这是糟糕的设计。 IV应该是独立的和随机的。也许如果散列算法存在弱点,或者您选择了弱密码。您不希望能够从其他任何东西中推导出 IV,否则可能会发起预计算攻击。

【讨论】:

    猜你喜欢
    • 2014-10-15
    • 2019-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    • 2016-10-18
    • 1970-01-01
    相关资源
    最近更新 更多