暴力破解一个加盐的SHA-512哈希需要多长时间?(盐提供)



下面是Java中的一个算法:

public String getHash(String password, String salt) throws Exception {
    String input = password + salt;
    MessageDigest md = MessageDigest.getInstance(SHA-512);
    byte[] out = md.digest(input.getBytes());
    return HexEncoder.toHex(out);
}

假设盐是已知的。我想知道,当密码是字典单词时,以及当它不是字典单词时,使用暴力破解的时间。

在您的例子中,破坏哈希算法相当于在哈希算法中发现冲突。这意味着您不需要找到密码本身(这将是一个预映像攻击),您只需要找到哈希函数的输出,该输出等于有效密码的哈希值(因此"冲突")。使用生日攻击寻找碰撞需要O(2^(n/2))时间,其中n是哈希函数的输出长度,以位为单位。

SHA-2的输出大小为512位,因此发现碰撞将花费O(2^256)时间。假设没有针对算法本身的聪明攻击(目前还没有针对SHA-2哈希族的攻击),这就是破坏算法所需要的。

要了解2^256的实际含义:目前人们认为(整个!!)宇宙中的原子数量大约是10^80,大约是2^266。假设32字节的输入(对您的情况来说是合理的- 20字节盐+ 12字节密码),我的机器进行65536(=2^16)次计算需要~0,22秒(~2^-2s)。所以2^256的计算将在2^240 * 2^16的计算中完成这将占用

2^240 * 2^-2 = 2^238 ~ 10^72s ~ 3,17 * 10^64 years

甚至称这是数百万年都是荒谬的。即使是世界上最快的硬件并行计算成千上万的哈希值,它也不会变得更好。没有任何人类技术能够将这个数字压缩成可以接受的数字。

所以忘记强制SHA-256吧。你的下一个问题是关于字典单词的。为了检索这种弱密码,传统上使用彩虹表。彩虹表通常只是一个预先计算的哈希值表,其思想是,如果您能够预先计算并存储每个可能的哈希值及其输入,那么查找给定哈希值并检索有效的预像将花费您O(1)。当然,这在实践中是不可能的,因为没有存储设备可以存储如此大量的数据。这种困境被称为内存时间权衡。由于您只能存储这么多值,典型的彩虹表包括带有中间约简函数的某种形式的散列链(这在Wikipedia文章中有详细解释),以便通过放弃一点时间节省来节省空间。

盐是使彩虹表不可行的对策。为了阻止攻击者预先计算特定盐的表,建议应用每个用户的盐值。然而,由于用户不使用安全的、完全随机的密码,如果盐是已知的,并且您只是在一个简单的试错方案中迭代一个大的通用密码字典,那么您仍然可以获得令人惊讶的成功。自然语言和随机性之间的关系被表示为熵。典型的密码选择通常是低熵的,而完全随机的值将包含最大熵。

典型密码的低熵使得您的一个用户使用相对较小的常用密码数据库中的密码的可能性相对较高。如果你在谷歌上搜索它们,你最终会找到这些密码数据库的torrent链接,通常在gb大小的类别中。如果不以任何方式限制攻击者,成功使用这种工具通常在几分钟到几天的范围内。

这就是为什么通常单靠散列和盐是不够的,你还需要安装其他安全机制。您应该使用pkcs# 5中描述的PBKDF2等人为降低熵诱导的方法,并且应该强制给定用户在重试输入密码之前等待一段时间。一个好的方案是从0.5秒开始,然后每失败一次,时间就增加一倍。在大多数情况下,用户不会注意到这一点,并且平均失败次数不会超过三次。但是,它将显著降低任何试图攻击您的应用程序的恶意外人的速度。

我想知道当密码是字典单词时,以及当它不是字典单词时,暴力破解的时间。

<

字典密码/h2>

大致数字:大约有1,000,000个英语单词,如果黑客每秒可以计算大约10,000个SHA-512哈希值(更新:参见CodesInChaos的评论,这个估计非常低),1,000,000/10,000 = 100秒。因此,破解单个用户的单字字典密码只需要一分钟多一点。如果用户将两个字典单词连接在一起,那么您可能需要几天的时间,但如果攻击者足够关心,那么仍然很有可能。超过这个,它开始变得困难。

随机密码

如果密码是字母数字字符,大写和小写的真正随机序列,则长度为N的可能密码的数量为60^N(有60个可能的字符)。这次我们从另一个方向来计算;我们会问:给定特定的时间长度,我们可以破解多少长度的密码?就用这个公式:

N = Log60(t * 10,000),其中t是以秒为单位计算哈希值所花费的时间(再次假设每秒10,000个哈希值)。

1 minute:    3.2
5 minute:    3.6
30 minutes:  4.1
2 hours:     4.4
3 days:      5.2

所以给3天的时间,我们可以破解密码,如果它是5个字符长。

这一切都很简单,但你明白了。更新:见下面的评论,实际上有可能破解比这长得多的密码

这是怎么回事?

让我们澄清一些误解:

  • 盐并没有使计算哈希变慢,它只是意味着它们必须单独破解每个用户的密码,并且预先计算的哈希表(流行语:彩虹表)完全无用。如果您没有预先计算的哈希表,并且您只破解一个密码哈希,那么盐不会产生任何影响。

  • SHA-512不是设计成难以暴力破解的。更好的哈希算法,如BCrypt、PBKDF2或SCrypt可以配置为需要更长的计算时间,一台普通的计算机可能每秒只能计算10-20个哈希。如果你还没有读过这个关于密码散列的优秀答案。

  • 更新:正如CodesInChaos在评论中所写的那样,如果使用正确的硬件来计算SHA-512哈希,即使是高熵密码(大约10个字符)也可以被暴力破解。


接受答案注释:

2014年9月接受的答案是不正确的,并且是危险的错误:

在你的例子中,破坏哈希算法相当于在哈希算法中找到一个碰撞。这意味着你不需要找到密码本身(这将是一个镜像攻击)…使用生日攻击寻找碰撞需要O(2^n/2)时间,其中n是哈希函数的输出长度,以位为单位。

生日攻击与破解给定哈希完全无关。这实际上是一个完美的图像前攻击的例子。这个公式和接下来的几段会导致攻击时间的高数值变得非常危险且毫无意义。如上面所示,完全有可能在几分钟内破解盐渍字典密码

典型密码的低熵使得您的一个用户使用相对较小的常用密码数据库中的密码的可能性相对较高…

这就是为什么通常单靠散列和盐是不够的,你还需要安装其他安全机制。您应该使用人工减慢熵诱导方法,如pkcs# 5中描述的PBKDF2…

是的,请使用计算速度较慢的算法,但是什么是"熵诱导"?将低熵密码放入散列中不会增加熵。它应该保持熵,但是你不能用散列来制作一个垃圾密码,它不是这样工作的。通过PBKDF2输入的弱密码仍然是弱密码

这个问题没有一个单一的答案,因为有太多的变量,但是SHA2还没有真正破解(参见:加密哈希函数的生命周期),所以它仍然是一个很好的算法来存储密码。使用盐是好的,因为它可以防止字典攻击或彩虹表的攻击。salt的重要性在于对于每个密码它应该是唯一的。你可以使用像[128-bit salt][512-bit password hash]这样的格式来存储散列后的密码。

唯一可行的攻击方法是实际计算不同可能性密码的哈希值,并最终通过匹配哈希值找到正确的密码。

我认为比特币是一个很好的例子来说明一秒钟可以完成多少哈希。比特币使用SHA256,简而言之,你生成的哈希值越多,你得到的比特币就越多(你可以用真钱交易比特币),因此人们有动力为此使用gpu。您可以在硬件概述中看到,成本仅为150美元的普通图形卡可以计算超过2亿哈希/秒。密码越长越复杂,需要的时间就越长。以200M/s的速度计算,尝试8个字符的字母数字(大写、小写、数字)的所有可能性需要大约300小时。如果密码是符合条件的东西或一个常见的英语单词,那么实时时间很可能会减少。

对于您需要在上下文中查看的任何安全性都是如此。攻击者的动机是什么?应用程序的类型是什么?为每个密码使用随机盐的散列可以很好地防止数千个密码泄露的情况。

您可以做的一件事是通过减慢散列过程来添加额外的暴力破解保护。由于您只对密码进行一次散列,而攻击者必须进行多次散列,因此这对您是有利的。典型的方法是获取一个值,对其进行哈希,获取输出,再对其进行哈希,以此类推,进行固定次数的迭代。例如,您可以尝试1,000或10,000次迭代。这将使攻击者找到每个密码的速度慢很多倍。