为什么 KDF 很慢?使用 KDF 是否比使用原始密钥更安全?

信息安全 密钥管理 pbkdf2 kdf
2021-08-31 02:30:39

根据 Wikipedia page for key derivation functions,KDF 的目的是为密码学派生密钥:

在密码学中,密钥派生函数 (KDF) 使用伪随机函数从一个秘密值(例如主密钥、密码或密码短语)派生一个或多个秘密密钥。 [1][2] KDF 可用于将密钥拉伸为更长的密钥或获取所需格式的密钥,例如将作为 Diffie-Hellman 密钥交换结果的组元素转换为用于 AES 的对称密钥。密钥加密散​​列函数是用于密钥推导的伪随机函数的流行示例。 [3]

假设我们刚刚完成了一次 Curve25519 密钥交换,并且我们希望将密钥用于对称算法,例如 AES。

  • 如果原始共享密钥可以用作对称密码的密钥,那么使用 KDF 是否提供任何安全优势?(假设 KDF 的输出也可以用于对称密码。
  • 如果原始密钥不能用作密码的密钥,我们将对其应用 KDF。在这种情况下,为什么 KDF 必须很慢?(或者 KDF 的这个属性只是针对特定情况,而不是这个?)
3个回答

这里的混淆在于有两种不同的密钥生成函数,人们经常说“密钥派生函数”而不明确他们的意思是哪一种(甚至理解有两种):

  • 基于密钥的密钥派生函数
  • 基于密码的密钥派生函数

像 HKDF 这样的基于密钥的派生函数的前提是输入可能有偏差或部分可预测,但否则它具有足够的最小熵以可靠地不可猜测。由 Diffie-Hellman 交换产生的共享秘密是教科书示例之一。

另一方面,基于密码的函数假设输入具有低熵,因此它们被设计为对猜测攻击施加尽可能高的成本(不会对诚实方造成难以承受的成本)。通过大量迭代来减慢计算速度是经典技术,但 scrypt 和 Argon2 等较新的函数超越了这一点,旨在提高内存难度

  • 计算它们的规范算法使用大量可调整的内存;
  • 任何用于计算使用比规范算法更少内存的函数的算法都应该付出非常高的时间代价(不利的时间 - 内存权衡)。

并非所有的 KDF 都很慢!HKDF这样的东西非常快,并且只涉及对底层 PRF 的少数调用。

仅当 KDF 旨在将潜在的低熵输入(如密码)转换为高熵输出(如加密密钥或密码验证器)时,它们才会变慢。在这种情况下,为了增加计算时间,这些函数被设计得很慢,就好像攻击者试图暴力破解一个比实际使用的熵更高的秘密一样。

对于 Curve25519 密钥交换后的共享密钥之类的东西,您通常更喜欢快速 KDF。例如,Noise 协议框架使用 HDKF 从曲线乘法得出的共享密钥生成加密密钥。虽然您可以直接使用原始共享密钥作为密钥,但实际上大多数协议都使用某种形式的 KDF 来支持前向保密等功能。

在 curve25519 共享密钥上使用 KDF 或安全散列的原因是这些位不是随机分布的。您有 32 个字节的“点数据”,其中包含大约 126 位“安全性”。

那么...您选择哪些位?取前 126 位并将 128 位密钥的剩余 2 位保留为零?还是取最后 126 位?或者只是从中间取出 128 位?其他一些策略?你怎么知道你选对了?你怎么知道没有可利用的模式?
使用安全哈希或 KDF 可以解决所有这些问题。Something-something-input 提供 128 位的几乎完全随机的输出(或者更确切地说,看起来是随机的)。或者,您想要的任何其他数量的位。您不会浪费熵,您不必担心是否选择了“好”位,并且您不会冒着可能存在来自 ECC 计算的可能可利用的、明显的模式(这些模式并非完全“随机”)的风险。当然,如果你拉伸,熵不会“神奇地”添加,但关键是,外部观察者无法分辨它在哪里。KDF 或哈希不需要很慢(大多数时候不应该)。

在密码或任何其他用户输入上使用慢速哈希或 KDF的原因是,来自人类的任何东西的熵都非常低,并且会在字典的帮助下被暴力破解(加上明显的排列)。现代计算机实际上每秒可以进行数亿次简单的哈希运算,因此如果您的密码数据库被盗,这将是一个问题。攻击者可能不会破坏完整的数据库,但如果没有故意使用慢速功能,那么获取几个用户的密码只需几分之一秒。潜在攻击者花费的时间越长越好。破解密码需要做更多的工作,这意味着您有更多的时间窗口来做出反应并通知用户以防万一发生泄露。

例如访问您的加密磁盘或您的 Keepass 文件也是如此。如果攻击者每秒可以尝试 100-2 亿个密码,那么您可能根本不加密,无论您花多少心思选择一个好的密码都没有关系。
如果攻击者每秒可以尝试 3-4 个密码,因为这正是运行 KDF 所需的时间,那么您的密码基本上是“牢不可破的”,因为以这种速度找到匹配项需要很长时间。

当然,这也会使您解锁音量变得更加昂贵。然而,你只做一次,攻击者必须做很多次