Passwords
非常簡單,非常難記憶(?)基於密碼的密鑰派生
我知道基於記憶硬密碼的密鑰派生函式的問題最好留給 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
:
- 附加到它
- 最後,從前到後對它進行一次雜湊處理。
攻擊者根本不需要儲存
expansionString
,hash(expansionString)
只要您追加到expansionString
.這意味著整個算法只需要少量的恆定記憶體,而且根本不難記憶。