Passwords

非常簡單,非常難記憶(?)基於密碼的密鑰派生

  • December 3, 2016

我知道基於記憶硬密碼的密鑰派生函式的問題最好留給 scrypt、argon2 等…

但是這些算法的經過驗證的實現並不總是可用(見鬼,.NET 的標準庫只包括 PBKDF2-HMAC-SHA1)。因此,當我在玩密碼儲存時,我想出了以下非常簡單、非常難以記憶的(?)“算法”:


string expansionString = veryLongPseudoRandomInitializerConstant;
for (int i = 0; i < 3849; i++)
{
   passwd = GetSha384HashString(GetSha384HashString(passwd + originalpass) + GetSha384HashString(user + saltString));
   expansionString = expansionString + GetSha384HashString(passwd) + GetSha384HashString(passwd + passwd) + GetSha384HashString(passwd + passwd + passwd);
}
passwd = GetSha384HashString(GetSha384HashString(passwd) + GetSha384HashString(expansionString));

這顯然不是完整的原始碼(我努力避免這個問題被認為是題外話的一部分。),但是在使用這些確切參數(它是 C#)執行“算法”時,它的峰值約為 2 兆字節(非常粗略的估計) ) 記憶體消耗。

這種類型的構造似乎太簡單了,沒有任何好處,但我自己無法打破它,所以(除非通常的“不要推出你自己的加密貨幣”警告):

如果人們對 SHA-384 做出的通常假設成立,那麼人們將如何打破這一點(在不經過完整算法的情況下恢復原始密碼),甚至只是破壞它的記憶難度?

撇開那些愚蠢的東西,你的算法相當於:

$ x_0=\mathrm{const} $

$ m_0=\mathrm{empty} $

$ x_i=h(x_{i-1}||\mathrm{password}||\mathrm{salt}) $

$ m_i=m_{i-1}||x_i $

$ \mathrm{result} = h(x_n||h(m_n)) $

你只做兩件事expansionString

  • 附加到它
  • 最後,從前到後對它進行一次雜湊處理。

攻擊者根本不需要儲存expansionStringhash(expansionString)只要您追加到expansionString.

這意味著整個算法只需要少量的恆定記憶體,而且根本不難記憶。

引用自:https://crypto.stackexchange.com/questions/41977