HMAC 中的零填充

信息安全 密码学 哈希 密码分析
2021-08-20 20:20:32

RFC 2104 的第 2 节定义了 HMAC 中使用的密钥应该用零字节填充,直到底层哈希算法的块长度。这不是一个潜在的安全漏洞,因为任何以零字节结尾的密钥都会产生与没有最后一个字节的密钥相同的结果吗?

以下 PHP 代码说明了该示例:

$key = "key";
$message = "message";
var_dump(hash_hmac("SHA256", $message, $key));
var_dump(hash_hmac("SHA256", $message, $key.chr(0x00)));

并产生以下输出:

string(64) "6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a"
string(64) "6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a"

我知道同一 RFC 的第 3 节推荐了最小长度的密钥,这将消除这个问题,就像某种散列密钥生成步骤一样。但是,在我看来,这可能是一个潜在的问题,还是我过于偏执?

2个回答

不,这不是安全漏洞。

HMAC 需要底层哈希算法块大小的密钥。通常,您应该提供一个具有底层哈希算法块大小的密钥。

如果您忘记提供这种大小的密钥,则有两种选择。第一个选项是 HMAC 快速失败,通知您您的密钥大小错误。第二种选择是 HMAC 只是假设您打算提供正确大小的密钥,但是您只是不小心遗漏了所有应该存在的尾随零字节。

上面的第二个选项符合在人们将接受的输入方面自由但在将产生的输出方面严格的政策。

所以 HMAC 不会丢失第二个选项的信息,因为较小的密钥不是有效的密钥。有一个简单的策略是采用无效密钥并以某种方式使它们以一种确定的、记录的方式为您的方便而有效。

对于像 HMAC 这样的算法,密钥的强度与您选择使用的集合中可能的密钥数量有关。例如,您可能希望使用 128 位密钥,在这种情况下,您的所有密钥的长度都将正好为 16 个字节。

仅当您的系统中可能存在两个不同的密钥时,这两个不同的密钥可能会产生相同的 HMAC 行为才是潜在的问题。对于您在这里谈论的事情,只有当您的系统接受各种长度的密钥时才会发生这种情况,这不是常见的情况。如果您考虑SSL/TLS,则 HMAC 与从主密钥生成的密钥一起使用,对于给定的散列函数具有一定的固定长度(例如,如果使用 SHA-256,HMAC 密钥的长度将始终为 32 字节) . 因此,没有问题。

如果您的键是 C 字符串(即以值 0 的字节结尾的字符串),那么也没有问题:根据定义,C 字符串不包含值 0 的字节,因此您不能有两个不同的 C 字符串,它们通过零-padding,将产生相同的密钥。

如果您真的对此感到不安,一种选择是系统地散列密钥,并将散列输出用作 HMAC 的真正密钥(请注意,当密钥大于“块大小”时,HMAC 规范实际上要求进行这样的散列)底层哈希函数)。