这个答案来自 2014 年。
自从我最初写这篇文章以来,密码学的实践已经发生了很大的变化。我已经添加了 2021 年的更新。
原始答案供参考:
“最佳”是相当主观的 - 这取决于您的要求。也就是说,我将为您概述每种模式。
ECB - 电子密码本。这种模式是最简单的,并且单独转换每个块。它只需要一个密钥和一些数据,没有额外的附加功能。不幸的是,它很糟糕——首先,相同的明文块在使用相同的密钥加密时会被加密为相同的密文块。维基百科的文章对这种失败有很好的图形表示。
优点:很简单,加解密可以并行运行。
坏点:非常不安全。
CBC - 密码块连接。这种模式很常见,被认为是相当安全的。每个明文块在转换之前都与前一个密文块进行异或运算,确保相同的明文块在按顺序排列时不会产生相同的密文块。对于明文的第一个块(没有前面的块),我们使用初始化向量代替。该值应该是每个密钥的每个消息唯一的,以确保相同的消息不会导致相同的密文。CBC 用于许多 SSL/TLS 密码套件。
不幸的是,当 CBC 没有与一组强大的完整性和真实性检查一起实施时,就会出现针对 CBC 的攻击。它具有的一个属性是块级延展性,这意味着攻击者可以在不知道密钥的情况下以有意义的方式更改消息的明文,如果他可以弄乱密文的话。因此,实现通常包括基于 HMAC 的真实性记录。不过,这是一个棘手的主题,因为即使执行 HMAC 和加密的顺序也会导致问题 - 查找“MAC 然后加密”以获取有关该主题的血腥细节。
优点:正确使用时安全,并行解密。
缺点:没有并行加密,当真实性检查错误/缺失时容易受到延展性攻击。但是如果做得好,那就太好了。
OFB - 输出反馈。在这种模式下,您实际上创建了一个流密码。IV(唯一的随机值)被加密以形成密钥流的第一个块,然后将该输出与明文异或以形成密文。为了获得下一个密钥流块,前一个密钥流块被再次加密,使用相同的密钥。重复此过程,直到为整个消息长度生成足够的密钥流。这在理论上很好,但在实践中存在关于其安全性的问题。块变换被设计为在执行一次时是安全的,但不能保证E(E(m,k),k)对于每个独立的安全分组密码都是安全的——内部原语之间可能存在奇怪的交互,这些交互尚未得到适当的研究。如果以提供部分块反馈的方式实现(即,仅前一个块的一部分被向前购买,另一半具有一些静态或弱随机值),那么就会出现其他问题,例如密钥流周期短。一般来说,您应该避免使用OFB。
优点:可以提前计算密钥流,提供快速的硬件实现
坏点:安全模型有问题,一些配置导致密钥流周期短
CFB - 密码反馈。另一种流密码模式,与反向执行的 CBC 非常相似。它的主要优点是您只需要加密转换,而不需要解密转换,这样在为小型设备编写代码时可以节省空间。这有点奇怪,我不经常提到它。
优点:占用空间小,并行解密。
缺点:不常用或不常用。
CTR - 计数器模式。这实质上涉及加密一系列以随机数(使用一次的数字)为前缀的递增数字以生成密钥流,这也是一种流密码模式。这种模式消除了重复运行相互转换的问题,就像我们在 OFB 模式中看到的那样。它通常被认为是一种很好的模式。
优点:正确完成时安全,并行加密和解密。
坏点:不多。有人质疑“相关明文”模型的安全性,但通常认为它是安全的。(2021 年更新:我不知道为什么我在 2014 年没有提到这一点,但流密码本质上是可延展的,这意味着如果您无法验证数据的完整性和真实性,攻击者可以翻转您明文中的任意位。密文正确)
填充模式可能很棘手,但总的来说,我总是建议使用 PKCS#7 填充,它涉及添加每个代表填充长度的字节,例如04 04 04 04
四个填充字节或03 03 03
三个填充字节。与其他一些填充机制相比,它的好处是很容易判断填充是否损坏 - 填充越长,随机数据损坏的机会就越高,但它也会增加您拥有的填充长度的副本数。验证和删除也很简单,没有真正的机会以某种方式验证正确的填充。
一般来说,坚持使用 CBC 或 CTR,必要时使用 PKCS#7(您不需要在流密码模式上进行填充)并在密文上使用真实性检查(例如 HMAC-SHA256)。CBC 和 CTR 均由 Niels Ferguson 和 Bruce Schneier 推荐,他们都是受人尊敬的密码学家。
话虽如此,有新模式!EAX和GCM最近受到了很多关注。GCM 被放入 TLS 1.2 套件并修复了 CBC 和流密码中存在的许多问题。主要好处是两者都是经过身份验证的模式,因为它们将真实性检查构建到密码模式本身中,而不必单独应用一个。这解决了填充 oracle 攻击和其他各种诡计的一些问题。这些模式解释起来并不那么简单(更不用说实现了),但它们被认为非常强大。
2021 年更新
自 2021 年 11 月起,通常不再建议将 CBC 用于新系统。您应该使用AEAD,例如 ChaCha20-Poly1305 或 AES-GCM。
CBC 在实践中非常令人担忧,因为您必须非常小心您选择的填充方案以及您应用的完整性和真实性检查。如果将真实性记录应用于明文而不是密文(即 MAC-then-encrypt),则攻击者可能能够利用填充 oracle 边信道攻击通过重复向接收器发送修改后的数据包来解密数据,该接收器试图解密它们。如果攻击者可以在传输过程中修改 IV,因为它没有受到真实性记录的保护,他们可以通过操纵 IV 来修改第一个解密的明文块。还必须选择填充方案本身以抵抗不明确的解码,例如,全零填充方案将导致实际消息中的任何尾随零被剥离。
点击率不那么令人担忧。没有填充,因为 CTR 密文的长度与其明文相同。修改 IV 的攻击者只能混淆整个消息 - 修改 IV 不允许他们进行有意义的修改。然而,流密码仍然具有比特级的延展性,这意味着未经身份验证的密文(例如使用 MAC)可以被操纵以在任何位置翻转明文中的任意位。虽然在 CBC 中使用 MAC-then-encrypt 可能会完全破坏系统,但在 CTR 模式(和其他流密码)中,它不能保证是灾难性的。
AES-CBC 在 TLS 1.2 中仍然被广泛使用,但它需要多年的精心设计才能使该实现足够安全以供一般使用。在您自己的系统中实施 CBC 模式是不明智的。所有 CBC 模式密码套件已从 TLS 1.3 中删除。您应该认为它已被弃用,并且仅在必须与无法升级以使用更现代方案的系统互操作时使用它。
AES-CTR 也仍然存在,但通常不推荐用于新设计。它可能比 CBC 问题少,但如果我们正在谈论为 TLS 选择密码套件,那么几乎没有任何区别。
现在首选 AEAD。AEAD 代表 Authenticated Encryption with Associated Data。实际上,这意味着您可以加密某些消息(从而提供机密性),对其进行身份验证(从而提供完整性和真实性),还可以验证一些不需要机密性的相关数据,所有这些都在密码模式本身内。这消除了单独实施真实性验证的负担。相关数据通常用于以防止篡改的方式将 IV 或其他特定于协议的数据附加到加密消息,这再次减轻了单独实施的需要。
AES-GCM 是一种基于 AES-CTR 和 Galois Message Authentication Code (GMAC) 的 AEAD,用于消息认证。它在 TLS 1.2 和 1.3 中受支持,并从 CBC 和 CTR 模式提供有意义的安全升级。现代 x86 处理器和更高功率的 ARM 处理器包括加速 AES 加密/解密操作和伽罗瓦域计算的专用指令,使 AES-GCM 在这些平台上的速度非常快。GCM 的一个缺点是难以安全地实施,而且如果它失败了也是非常无情的。如果您只是在 TLS 之类的协议中使用 AES-GCM,这些事情都不是问题,但它们是密码学家关心的问题。
CCM是另一个 AEAD,这次基于 CBC 和CBC-MAC的组合。虽然 CBC 本身被认为很弱,但由于我上面描述的原因,CCM 的构建并没有违反这些具体问题。CBC-MAC 部分提供真实性,它本身是由 CBC 操作构建的。CCM 在密码学方面被认为不如其他 AEAD,但它可以节省您在没有加速指令的平台上实施 Galois 现场操作。AES-CCM 在 TLS 1.2 和 TLS 1.3 中都可用。还有一个带有截断身份验证标签的变体,称为CCM_8
,它使用 8 字节(64 位)身份验证标签,而不是通常的 16 字节(128 位)身份验证标签 - 您可以在此处阅读相关信息.
我之前提到过 EAX 模式。这还没有真正流行起来。它比 GCM 慢得多。还有一个名为“EAX(prime)”的变体,它完全被破坏了。
另一种较少使用的 AEAD 是偏移码本模式 (OCB). 从理论上讲,这是一种很好的 AEAD 密码模式。它使用伽罗瓦域,但比 GCM 更容易实现。有三种变体。OCB1 不是 AEAD。OCB2 增加了 AEAD 功能。OCB3 是较新的版本。OCB2 已损坏 - 对其进行了完整的明文恢复攻击。OCB3 仍然被认为是安全的。然而,这在实践中并不重要,因为作者为其申请了专利并应用了限制性豁免条款,该条款只允许在 GPL 许可代码中自由实施。这后来被放宽到任何 OSI 批准的开源许可证,但这仍然是一个重大的实际负担。这些专利在 2021 年 2 月被放弃,但此时每个人都已经对其他模式进行了标准化。尽管 OCB 可能比 GCM 更好,但现在基本上无关紧要。
ChaCha20-Poly1305 目前(截至 2021 年 11 月)被认为是较好的 AEAD 之一。它不是严格意义上的“密码模式”,因为它是密码和 MAC 的特定组合 - 它由ChaCha20 流密码(Salsa20 的变体)和Poly1305 消息验证码构成。当专门的硬件加速不可用时,它通常比 AES-GCM 和 AES-CCM 更快、更节能。它具有强大的安全特性和对实施者有吸引力的实用特性。它在 TLS 1.2 和 TLS 1.3 中可用,目前是 libsodium 的秘密盒 API 中使用的默认密码。您应该在新系统中更喜欢它。
总之:
- 欧洲央行 - 不要使用它。在极少数情况下,ECB 是正确的选择,但除非您是密码学家,否则您几乎永远不会遇到它们。
- CBC - 理论上是安全的,但在实践中很难做到。由于使用 MAC-then-CBC,多年来一直是 TLS 中许多漏洞的原因。认为这已被弃用。在具有仔细实现的遗留系统中可接受,但不应在新设计中使用。
- OFB - 不要使用它。这是一种不寻常的模式,缺乏理想的特性并且存在周期长度问题。
- CFB - 不要使用它。同样,这是一种不寻常的模式。
- CTR - 理论上安全,并且比 CBC 更少。仍然需要仔细实施以提供强大的真实性。认为这已被弃用。在具有仔细实现的遗留系统中可接受,但不应在新设计中使用。
- GCM - 一个强大的、广泛支持的 AEAD。如果时间和功率分析侧信道攻击是一个问题,那么安全实施就很棘手,但是如果您在标准协议实施(例如 openssl)中使用它,那很好。适合新设计。
- CCM - 另一个强大的、广泛支持的 AEAD。可能有点慢,但比 AES-GCM 更容易实现,并且支持截断标签。适合新设计,但一般不是首选。
- EAX - 没有理由使用这种模式。它并不比 GCM 更安全,后者更快。
- OCB - 理论上是一个很好的 AEAD,但专利产权负担阻止了它的流行。也许它会在未来起飞?现在你可以忽略它。
- ChaCha20-Poly1305 - 特定密码和 MAC 对而不是模式,但如果您尝试选择密码套件,它是截至 2021 年 11 月可用的最佳选项之一。广泛支持。我建议将其设为您的首选。