如何处理不正确的密钥大小(AES 加密)

信息安全 AES
2021-09-11 16:45:54

我在规范中找不到正确的答案如何处理大于 AES_KEY_SIZE 的不正确密钥大小。(我发现尺寸太短的键将被正确填充 0x00 值)。

例如,如果 AES-128-ECB 使用 144 位密钥(而不是 128 位密钥),那么正确的行为应该是什么?

  1. 返回错误?
  2. 将密钥截断为 128 位?
  3. 将密钥视为密码并使用一些 kdf 功能?
2个回答

这是一个 API 问题,而不是密码学问题。AES 标准 (FIPS 197) 没有说明如何处理非标准密钥大小。我见过的所有 AES 实现都拒绝非标准密钥大小并出现错误;然而,更高级别的加密实现(不仅仅是“AES”)可能会选择提供更多服务(取决于它设计的工作)。

另一方面,这个问题通常不会出现。我们最常使用密钥派生过程生成 AES 密钥,我们特别要求该过程“给我们 128/192/256 位密钥”,这就是它给我们的密钥量。

至于您的替代方案,恕我直言,默默地截断键值是邪恶的;什么是正确的取决于您实际在做什么(以及谁在实际生成密钥,以及为什么它可能不是标准大小)。

还有,欧洲央行模式?除非你确切地知道你在做什么(如果你必须问这个问题,你不会),你应该避免它。

我将作为Crypto-API 的一些附加功能的开发人员和设计人员来回答。

首先,Poncho 是正确的,没有任何 AES 规范或操作模式(例如不安全的 ECB)会指示在这种情况下要做什么。他们几乎肯定不会提出 #2 或 #3,如果仅仅是因为这会严重破坏算法的任何安全证明。

1.返回错误?

我认为唯一正确的答案。AES 仅接受 128、192 或 256 字节的密钥。这称为前提条件。不遵守先决条件应导致失败。在 Java 中,我会快速将其升级为 a RuntimeException,因为为对称密钥提供较少的位总是一个编程错误(您不希望用户直接输入密钥,如果确实需要输入十六进制密钥,则需要在将其提供给加密 API之前对其进行验证)。

这可能不是最佳答案的唯一地方是非常低级的 API,其中只返回一个指向已知大小的键的指针。但是用户永远不应该调用甚至访问那个低级 API。

返回错误(或异常,对于高级语言)也是快速失败的,这是一种很好的安全设计实践。

2. 将密钥截断为 128 位?

不,那太可怕了。您不应该使用低于用户提供的安全相关数据执行加密功能。您将为用户决定可接受的安全性较低,这显然不是 API 设计人员的职责。

用零扩展密钥同样可怕。您告诉您的用户他们正在使用 AES-256,而实际提供的安全性低于此值(甚至可能接近于零)。

就像 (3) 一样,这也将不符合最小意外原则。

基于 PHP mcrypt 的函数采用了这条路线,关于 SO 试图在表现良好的加密 API 中复制 mcrypt 功能的问题永无止境。

3. 把key当作密码,使用一些KDF功能?

不,如果用户想使用 KDF,那么就为他们提供 KDF。以 AES 加密模式执行 KDF 违反了各种设计原则,包括最小意外原则。AES API 应该这样做:提供密码接口以获得机密性。API 可以使 KDF 的使用变得容易,但它本身不应该选择KDF 和一组参数并将其设为默认值(这在当时看来是安全的,并且以后永远无法更改)。

CryptoJS API 的许多用户将使用密码的加密例程与使用密钥的加密例程混淆,只是因为它们具有相同的名称。

对于定义明确的更高级别的API(例如实现 OpenPGP 的 API )来说,创建一个接受密码的加密函数是可以的。


有 PKCS#5基于密码的加密标准。不幸的是,由于该标准在未指定特定二进制容器格式的情况下留下了太多配置,因此仍然很难使 PKCS#5 兼容的密文在运行时之间兼容。所以它只能作为定义受密码保护的容器格式的开始。


笔记:

  • 一些像 Java 这样的 Crypto API 不直接接受二进制密钥。密钥必须首先从字节中生成。不直接使用字节作为密钥的一个原因是硬件设备(HSM、智能卡)甚至可能一开始就不会将字节暴露给软件。在这种情况下,可能会提前抛出错误,具体取决于实现。