密钥派生函数和(盐渍)哈希有什么区别?

信息安全 加密 密码学 哈希 kdf
2021-08-31 05:42:06

我在这篇文章中看到主要区别在于 KDF 输出具有“某些随机性属性”,我不明白这是什么意思。假设“某些随机性属性”是为了防止彩虹表和预先计算的东西。

但是使用带有适当加盐的哈希,我们也可以防止这些攻击。所以从这个意义上说,我相信这两个工具之间没有区别,只是在实现上有所不同。

我也知道 KDF 的另一个目标是足够以减缓假设性攻击,同时又不破坏用户在速度方面的体验。好吧,从严格意义上讲,这也可以通过添加一些无用操作(例如for(i = 0; i < 1000000; i++);)的散列来实现,即使它不是很干净。

那么,有什么区别呢?一个比另一个好吗?我们什么时候必须使用一个,什么时候使用另一个?

2个回答

实际上有两种 KDF。一种被设计为从高熵输入中导出一个密钥(就像另一个密钥一样);这可以通过像 HMAC 这样的快速键控散列来完成。另一种以密码作为输入。密码是低熵的;它们本质上并不是很难暴力破解。因此,一个好的密码散列必须很慢。

在您的问题中,您说添加for (i=0; i<bignum; i++);会减慢哈希值。这实际上是完全没用的。攻击者不必遵守你的规则。当攻击者拥有哈希的副本时,哈希需要保护密码。如果攻击者能够快速的计算哈希值,它并没有多么慢慢计算它们。哈希需要天生很慢;不应该有比合法服务器更快地评估它们的捷径。

“随机属性”是因为 KDF 需要生成密钥。它们与预计算无关,包括彩虹表。密码算法通常对密钥做出某些假设;除其他外,他们通常假设它是从一组可能的密钥中完全随机选择的。密钥也应该有一定的长度;它们的推导函数需要任意长度的输出。相反,如果密码散列的输出具有很多结构,那就没问题了。也许有 70% 的机会相邻位具有相同的值。也许它将 128 位熵传播到 4096 位输出中。只要难以逆转,那是一个很好的哈希,但它不适合作为密钥。

基于安全密码的密钥派生函数是安全密码散列(PBKDF2 实际上是三大散列之一)。反过来不一定正确。使用哪一个很简单:使用基于密码的密钥派生函数从密码中派生密钥,并使用散列来存储密码。

只是解决另一个答案(cpast's),关于何时使用一个或另一个来管理密码:

这实际上是完全没用的。攻击者不必遵守你的规则。当攻击者拥有哈希的副本时,哈希需要保护密码。如果攻击者可以快速计算散列,那么计算它们的速度有多慢并不重要。哈希需要天生很慢;不应该有比合法服务器更快地评估它们的捷径。

sha256sum(sha256sum(sha256sum.....(salt + master password)))...

多次应用散列确实增加了攻击者试图从散列中检索密码的难度,并且确实使密码推导函数本质上变慢了。攻击者每次尝试都需要遍历每一个 SHA256 函数。

这将使其与其他密钥派生算法一样慢(甚至更慢/更难)。

密码算法通常对密钥做出某些假设;除其他外,他们通常假设它是从一组可能的密钥中完全随机选择的。密钥也应该有一定的长度;它们的推导函数需要任意长度的输出。相反,如果密码散列的输出具有很多结构,那就没问题了。也许有 70% 的机会相邻位具有相同的值。也许它将 128 位熵传播到 4096 位输出中。只要难以逆转,那是一个很好的哈希,但它不适合作为密钥。

只运行一次 SHA256 将产生看似从整数集中随机选择的输出,最大为2 2562 256是一个天文数字,截断它允许用户在不损失安全性的情况下对任意长度的输出进行采样(当然,只要他们采样足够的熵)。

SHA256 函数可能存在“大量输出结构”而损害生成的密码的可能性微乎其微。即便如此,如果攻击者想要破解散列输出,没有比猜测随机数更好的策略(即使尝试也是徒劳的)。