为什么我需要将原始盐添加到密码的每个哈希迭代中?

时间:2014-01-08 18:04:24

标签: hash passwords salt

我理解在多次迭代中散列密码以使攻击者更难处理是很重要的。我已经多次读过,在处理这些迭代时,不仅要散列先前散列的结果,而且每次都附加原始盐是至关重要的。换句话说:

我需要这样做:

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

我的问题是关于这里的数学。为什么我上面的坏例子让攻击者更容易?我听说它会增加碰撞的可能性,但我不明白为什么。

1 个答案:

答案 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的优势,从而降低了攻击者对离线攻击的优势。