我理解在多次迭代中散列密码以使攻击者更难处理是很重要的。我已经多次读过,在处理这些迭代时,不仅要散列先前散列的结果,而且每次都附加原始盐是至关重要的。换句话说:
我需要不这样做:
var hash = sha512(salt + password);
for (i = 0; i < 1000; i++) {
hash = sha512(hash);
}
相反,需要这样做:
var hash = sha512(salt + password);
for (i = 0; i < 1000; i++) {
hash = sha512(salt + hash);
}
我的问题是关于这里的数学。为什么我上面的坏例子让攻击者更容易?我听说它会增加碰撞的可能性,但我不明白为什么。
答案 0 :(得分:0)
这不是你只需要做“hash = sha512(salt + hash)” - 它比那更复杂。 HMAC是添加盐的更好方式(PBKDF2基于HMAC - 有关PBKDF2的详细信息,请参见下文) - When is it safe to use a broken hash function?对这些细节进行了很好的讨论。
你是正确的,你需要多次迭代哈希函数以确保安全性。
但是,不要自己滚动。请参阅How to securely hash passwords?,并注意PBKDF2,BCrypt和Scrypt都是这样做的。
PBKDF2,也称为PKCS#5v2和RFC2898实际上与您正在进行的操作相当接近(正常散列函数的多次迭代),特别是以PBKDF2-HMAC-SHA-512的形式,特别是第5.2节列出:
For each block of the derived key apply the function F defined
below to the password P, the salt S, the iteration count c, and
the block index to compute the block:
T_1 = F (P, S, c, 1) ,
T_2 = F (P, S, c, 2) ,
...
T_l = F (P, S, c, l) ,
where the function F is defined as the exclusive-or sum of the
first c iterates of the underlying pseudorandom function PRF
applied to the password P and the concatenation of the salt S
and the block index i:
F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
where
U_1 = PRF (P, S || INT (i)) ,
U_2 = PRF (P, U_1) ,
...
U_c = PRF (P, U_{c-1}) .
Here, INT (i) is a four-octet encoding of the integer i, most
significant octet first.
P.S。 SHA-512是一个很好的哈希原语选择 - SHA-512(和SHA-384)也优于MD5,SHA-1,甚至SHA-224和SHA-256,因为SHA-384及以上使用64位操作当前的GPU(2014年初)与32位操作相比没有当前CPU的优势,从而降低了攻击者对离线攻击的优势。