多长时间蛮力腌SHA-512哈希? (提供盐)

这里是Java中的一个algorithm:

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); } 

假定盐是已知的。 我想知道当密码是一个字典单词的时候,还有当它不是一个字典单词。

在你的情况下,打破散列algorithm等同于在散列algorithm中find冲突。 这意味着你不需要find密码本身(这将是一个preimage攻击 ),你只需要find哈希函数的输出等于有效密码的哈希(因此“碰撞”)。 使用生日攻击来查找冲突需要O(2 ^ n / 2)个时间,其中n是散列函数的输出长度(以位为单位)。

SHA-2具有512位的输出大小,因此发现冲突将花费O(2 ^ 256)时间。 鉴于algorithm本身没有明智的攻击(目前SHA-2哈希族中没有人知道),这就是破解algorithm所需要的。

为了得到2 ^ 256实际上意味着什么的感觉:目前认为(整个!!!)宇宙中的primefaces数大概是10 ^ 80,大约是2 ^ 266。 假设32字节的input(对于你的情况这是合理的 – 20字节的盐+ 12字节的密码),我的机器在65536(= 2 ^ 16)的计算中花费约0.22s(〜2 ^ -2s)。 所以2 ^ 256计算将在2 ^ 240 * 2 ^ 16计算中完成

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

即使称这几百万年也是荒谬的。 而且这个星球上最快的硬件并行计算数以千计的散列并不会好得多。 没有人类技术能够把这个数字变成可以接受的东西。

所以在这里忘记蛮力的SHA-256。 你的下一个问题是关于字典的话。 为了检索这种弱密码,传统上使用彩虹表 。 一个彩虹表通常只是一个预先计算的散列值表,这个想法是,如果你能够预先计算并存储每个可能的散列以及它的input,那么你需要O(1)来查找一个给定的散列并检索有效的preimage它。 当然这在实践中是不可能的,因为没有存储设备可以存储如此大量的数据。 这种困境被称为记忆时间折衷 。 由于您只能存储如此多的值,所以典型的彩虹表格包括一些带有中间缩减function的哈希链接forms(这在维基百科文章中有详细说明),以节省一些时间,节省空间。

盐是使这样的彩虹桌不可行的一个对策。 为了阻止攻击者预先计算特定盐的表,build议应用每个用户的盐值。 但是,由于用户不使用安全的,完全随机的密码,所以如果知道盐的成功率,并且只是通过一个简单的试验和错误scheme遍历一个普通密码的大字典,仍然令人惊讶。 自然语言与随机性之间的关系表示为熵 。 典型的密码select通常是低熵的,而完全随机的值将包含最大的熵。

典型密码的低熵使得你的一个用户使用相对较小的普通密码数据库的密码的可能性相对较高。 如果你为他们谷歌,你会最终find这样的密码数据库,通常在GB级大小类别torrent链接。 如果攻击者不受任何限制,使用这种工具获得成功的时间通常在几分钟到几天之间。

这就是为什么通常只有散列和咸味是不够的,你还需要安装其他的安全机制。 您应该使用PKCS#5中描述的PBKDF2等人工减速熵增方法,您应该在给定用户重试input密码之前强制等待一段时间。 一个好的scheme是从0.5秒开始,然后每次尝试失败的时间加倍。 在大多数情况下,用户不会注意到这一点,平均而言,失败次数通常不会超过三次。 但是这会显着减慢任何试图攻击你的应用程序的恶意外人。

我想知道当密码是一个字典单词的时候,还有当它不是一个字典单词。

字典密码

球场图 :大约有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个字符长。

这是所有非常球公园,但你明白了。 更新:请参阅下面的注释,实际上可以破解比这更长的密码。

这里发生了什么?

让我们来澄清一些误解:

  • 计算散列值的时候salt的计算速度并不慢 ,这意味着他们必须单独破解每个用户的密码,并且预先计算的散列表(buzz-word: rainbow table )完全没有用处。 如果你没有一个预先计算好的散列表,而你只是破解一个密码散列,腌制没有任何区别。

  • SHA-512的devise不是很难暴力 。 像BCrypt,PBKDF2或SCrypt这样的更好的哈希algorithm可以被configuration为需要更长的时间进行计算,而普通的计算机可能只能够每秒计算10-20次哈希。 如果你还没有阅读这个关于密码哈希的优秀答案 。

  • 更新:如在CodesInChaos的评论中所写的,如果使用正确的硬件来计算SHA-512散列值,甚至可以使用高熵密码(约10个字符)进行暴力破解。


接受答案的注释:

截至2014年9月的答案是不正确的,也是危险的错误:

在你的情况下,打破散列algorithm等同于在散列algorithm中find冲突。 这意味着你不需要自己find密码(这将是一个原像攻击)…使用生日攻击来查找冲突需要O(2 ^ n / 2)时间,其中n是散列的输出长度function在位。

生日攻击破解给定的散列完全无关 。 这实际上是一个完美的前像攻击的例子 。 这个公式和接下来的几段对于攻击时间来说是非常危险的,完全没有意义的值。 如上所示, 完全可以在几分钟内破解咸味字典密码

典型密码的低熵使得你的一个用户从一个相对较小的普通密码数据库中使用密码的可能性相对较高。

这就是为什么通常只有散列和咸味是不够的,你还需要安装其他的安全机制。 你应该使用一种人为的减慢熵的方法,如PKCS#5中描述的PBKDF2 …

是的,请使用一个计算速度慢的algorithm,但什么是“熵 – 熵”? 把一个低熵密码通过哈希不会增加熵。 它应该保留熵,但是你不能用散列表来更好地制作垃圾密码,但是这样做不行。 通过PBKDF2的弱密码仍然是一个弱密码。

这个问题没有一个答案,因为variables太多,但是SHA2还没有真正破解(参见: 密码散列函数的生存期 ),所以它仍然是一个很好的algorithm来存储密码。使用盐是好的,因为它可以防止字典攻击或彩虹桌的攻击 。 盐的重要性在于每个密码都应该是唯一的。 存储哈希密码时,可以使用[128位盐] [512位密码哈希]等格式。

唯一可行的方法是实际计算散列密码的不同可能性,最后通过匹配哈希来find正确的密码。

为了让人们了解一下可以完成多less次哈希,我认为比特币就是一个很好的例子。 比特币使用SHA256,并缩短它,你产生越多的比特币,你得到更多的比特币(你可以交易真正的钱),因此人们有动力使用GPU来达到这个目的。 您可以在硬件概览中看到,平均价值仅为150美元的graphics卡可以计算出2亿次以上的哈希/秒。 密码越长越复杂,需要的时间也越长。 以200M / s计算,尝试所有可能的8个字母的数字(大写,小写,数字)大约需要300个小时。 如果密码是符合条件的或者是一个普通的英文单词,那么实际时间很可能会更less。

因此,您需要在上下文中查看任何安全性。 攻击者的动机是什么? 什么是应用程序的种类? 对每一个随机盐进行哈希处理,可以很好地保护数千个密码被泄露的情况。

你可以做的一件事是通过减缓哈希程序来增加额外的powershell保护。 由于您只需密码一次,攻击者必须多次执行此操作,这对您有利。 典型的做法是取值,散列,取出输出,再次散列,等等。 例如,您可以尝试类似1,000或10,000次的迭代。 这会使攻击者find每个密码的速度要慢很多倍。