以下是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);
}
假设盐是已知的。我想知道在密码是字典单词时以及不是字典单词时暴力的时间。
答案 0 :(得分:112)
在您的情况下,打破哈希算法等同于在哈希算法中查找冲突。这意味着你不需要找到密码本身(这将是preimage attack),你只需要找到一个哈希函数的输出,该输出等于有效密码的哈希值(因此“冲突”) )。使用birthday attack查找冲突需要O(2 ^(n / 2))时间,其中n是散列函数的输出长度(以位为单位)。
SHA-2的输出大小为512位,因此发现冲突需要O(2 ^ 256)时间。鉴于对算法本身没有明智的攻击(目前没有人知道SHA-2哈希族),这就是打破算法所需要的。
感受2 ^ 256实际意味着什么:目前认为(整个!!!)宇宙中的原子数大约是10 ^ 80,大约是2 ^ 266。假设32字节输入(这对你的情况是合理的 - 20字节盐+ 12字节密码)我的机器需要~0,22s(~2 ^ -2s)进行65536(= 2 ^ 16)次计算。因此2 ^ 256计算将在2 ^ 240 * 2 ^ 16计算中进行,这将花费
2^240 * 2^-2 = 2^238 ~ 10^72s ~ 3,17 * 10^64 years
即使称之为数百万年也是荒谬的。使用地球上最快的硬件并行计算数千个哈希值并没有好转。没有任何人类技术能够将这个数字压缩成可以接受的东西。
所以在这里忘记强制使用SHA-256。你的下一个问题是关于词典的话。为了检索这种弱密码,传统上使用了rainbow tables。彩虹表通常只是一个预先计算的哈希值表,这个想法是,如果你能够预先计算并存储每个可能的哈希及其输入,那么你需要O(1)来查找给定的哈希并检索一个哈希值。有效的原像。当然,这在实践中是不可能的,因为没有存储设备可以存储如此大量的数据。这种困境被称为memory-time tradeoff。由于您只能存储如此多的值,因此典型的彩虹表包括某些形式的哈希链和中间约简函数(这在维基百科文章中有详细解释),以节省空间,节省一些时间。
盐是使这种彩虹表不可行的对策。为了阻止攻击者预先计算特定盐的表,建议应用每用户盐值。但是,由于用户不使用安全,完全随机的密码,如果盐已知并且您只是在简单的试错法中迭代一个大型常用密码字典,那么您仍然可以获得成功。自然语言和随机性之间的关系表示为entropy。典型的密码选择通常具有低熵,而完全随机的值将包含最大的熵。
典型密码的低熵使得您的某个用户使用相对较小的通用密码数据库中的密码的可能性相对较高。如果你谷歌为他们,你将最终找到这种密码数据库的torrent链接,通常在千兆字节大小类别。如果攻击者没有受到任何限制,那么使用这样的工具成功通常会在几分钟到几天的范围内。
这就是为什么通常单独进行散列和腌制是不够的,您还需要安装其他安全机制。您应该使用人工减速的熵 - 结束方法,例如PKCS#5中描述的PBKDF2,并且您应该在给定用户重试输入密码之前强制执行等待期。一个好的方案是以0.5秒开始,然后将每次失败尝试的时间加倍。在大多数情况下,用户不会注意到这一点,并且平均不会经常失败三次。但它会大大减缓任何试图攻击你的应用程序的恶意局外人。
答案 1 :(得分:31)
我想知道在密码是字典单词时以及不是字典单词时暴力的时间。
Ballpark数字:大约有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个字符,我们就可以破解密码。
这都是非常棒的球场,但你明白了。 更新:请参阅下面的评论,它实际上可能会破解比此更长的密码。
让我们澄清一些误解:
盐并不会使计算哈希值变慢,这只是意味着他们必须单独破解每个用户的密码,并预先计算哈希表( buzz-word:彩虹表)完全没用。如果您没有预先计算好的哈希表,并且您只是破解了一个密码哈希,那么盐析并没有任何区别。
SHA-512并非设计为难以暴力。可以将更好的散列算法(如 BCrypt,PBKDF2或SCrypt )配置为计算时间更长,而普通计算机可能只能计算每秒10-20个哈希值。如果您还没有密码哈希,请阅读This excellent answer。
更新:如在CodesInChaos的评论中所写,如果使用正确的硬件计算SHA-512哈希值,即使是高熵密码(大约10个字符)也可以强制执行。
2014年9月中接受的答案是错误的,并且存在危险错误:
在您的情况下,打破哈希算法等同于在哈希算法中查找冲突。这意味着您不需要自己找到密码(这将是一个preimage攻击)...使用生日攻击查找冲突需要O(2 ^ n / 2)时间,其中n是输出长度以位为单位的散列函数。
生日攻击完全不相关来破解给定的哈希。事实上,这是一个原始攻击的完美例子。该公式和接下来的几段导致攻击时间的危险高且完全无意义的值。如上所示,完全有可能在几分钟内破解盐渍词典密码。
典型密码的低熵使得您的某个用户使用相对较小的通用密码数据库中的密码的可能性相对较高......
这就是为什么一般只进行散列和盐析是不够的,你还需要安装其他安全机制。您应该使用人工减速的熵吸收方法,例如PKCS#5中描述的PBKDF2 ......
是的,请使用计算速度慢的算法,但是" entropy-enducing&#34 ;?通过哈希放置低熵密码不会增加熵。它应该保留熵,但你不能用哈希来更好地制作垃圾密码,它不会那样工作。 通过PBKDF2输入的弱密码仍然是一个弱密码。
答案 2 :(得分:8)
这个问题没有一个答案,因为变量太多,但SHA2还没有真正破解(参见:Lifetimes of cryptographic hash functions)所以它仍然是一个很好的算法,用于存储密码。使用盐是好的,因为它可以防止来自dictionary attacks或彩虹表的攻击。 salt的重要性在于每个密码都应该是唯一的。存储散列密码时,可以使用[128位盐] [512位密码哈希]等格式。
唯一可行的攻击方式是实际计算不同密码可能性的哈希值,并最终通过匹配哈希值找到正确的哈希值。
为了了解一秒钟内可以完成多少次哈希,我认为比特币就是一个不错的例子。 Bitcoin使用SHA256并缩短它,你产生的哈希越多,你获得的比特币就越多(你可以用真钱交易),因此人们有动力为此目的使用GPU。您可以看到in the hardware overview只需150美元的普通显卡可以计算超过2亿个哈希/秒。密码越长越复杂,所需的时间就越长。以200M / s计算,尝试8字符字母数字(资本,更低,数字)的所有可能性将花费大约300小时。如果密码符合条件或英语常用词,则实际时间很可能会减少。
因此,您需要在上下文中查看任何安全性。攻击者的动机是什么?什么是申请?每个哈希都有一个随机盐哈希,可以很好地防止数千个密码被泄露的情况。
您可以做的一件事是通过减慢向下散列过程来添加额外的强力保护。由于您只对密码进行一次哈希攻击,并且攻击者必须多次执行此操作,因此这对您有利。典型的方法是获取值,散列它,获取输出,再次散列它等等,以进行固定的迭代次数。例如,您可以尝试1,000或10,000次迭代。这将使攻击者找到每个密码的速度慢很多倍。