Hash

如果我知道輸入和輸出,我可以獲得散列算法嗎?

  • June 21, 2018

假設我有一個字元串"Hello World". ,我將它傳遞給一個未知函式,該函式將輸出作為"6Xbhkfo520/78".

那麼,使用幾個輸入和輸出對,我可以確定散列函式的算法嗎?

假設散列函式是私有的是很奇怪的。這與 Kerckhoffs 的原則相矛盾。如果您在談論鍵控雜湊函式,那麼我認為答案在理論上是否定的。它們通常用於建構消息認證程式碼,如 HMAC,其中的密鑰不能從多個雜湊輸入/輸出中導出。

您無法直接確定使用什麼功能。您甚至無法判斷是否使用了雜湊函式。安全雜湊函式可以建模為隨機預言機。表單的輸入/輸出對 $ (m, hash(m)) $ 與形式對無法區分 $ (m, \text{random-value}) $ .


輕微切題:這可能與本網站禁止“挑戰”問題、“這是什麼算法”和“破解這個密文”問題的原因之一有關。如果您想惡作劇,請對他們說“我挑戰您僅從密文中破解此密碼。” 然後給他們一個隨機選擇的假密文字元串。您可以通過要求他們解決沒有答案的難題來輕鬆浪費他們的時間。

此外,存在與一對輸入/輸出一致的無限數量的潛在(數學)函式。即使你找到了一個與任意數量的函式一致的函式,你也不能確定它是同一個函式,因為有無限多的選擇。


你能做的就是提出一個假設,比如“這個散列函式是 MD5”。(或 SHA-1。或任何其他已知算法。)**然後檢驗你的假設。**如果 $ hash(m) \neq \textit{MD5}(m) $ 然後你拒絕你的假設。對您能想到的每個候選函式重複此操作。

當給定的輸出與計算的輸出不匹配時,您可以肯定地說“雜湊算法不是普通的 MD5”。另一方面,如果這兩個值相等,那麼您不能肯定地說您的假設是正確的。對於具有長輸出的安全雜湊,作為一個人,您可能確信您的假設是正確的。這些函式不會導致很多(或任何)誤報,因為輸出太大而無法偶然發生匹配。但正如我之前指出的,它不能讓你在數學上證明你的假設是正確的(除非你排除了所有可能函式的宇宙中的所有其他函式),因為有無限多的選擇。


其次:出於同樣的原因,Sebastián Mestre 使用機器學習的建議是(非常)錯誤的。您可以訓練一個神經網路,為任何給定的輸入/輸出對集產生相同的結果,但神經網路所做的操作將是一個函式,不一定或可能是原始函式。這就是“過度訓練”現象。或者“過度擬合”一個函式。此外,神經網路訓練不適用於這類事情。偽隨機離散事物沒有梯度。如果雜湊算法可以用神經網路簡潔地表示,那將意味著一個非常有缺陷的密碼算法。


回到主題:在實踐中,您需要進一步複雜化“對每個散列算法進行測試是否合適”的方法。可能的算法有很多變化。

作為選擇潛在假設的啟發式方法,您可以查看函式的輸出。如果它是 512 位長,那麼您應該查看諸如 SHA-512、SHA3-512、Skein-512、Blake-512、Blake2b 之類的東西……你明白了。它可能不會是 MD5 或 SHA-1,因為它們的輸出少於 512 位。

不過,這可能很複雜。如果您有 256 位的輸出,那麼您可能有 SHA-256、SHA3-256、SHA-512 截斷為 256 位、SHA-512/256(與 SHA-256 和截斷的 SHA-512 不同),截斷的 SHA3-512,連接在一起的兩個 MD5 輸出等。

到目前為止,我已經忽略了散列函式輸出的文本編碼。也就是說,為了簡單起見,我將輸出字元串視為某個雜湊函式(二進製字元串)的原始輸出,而不是像"6Xbhkfo520/78".

如果您有一個 64 字節的輸出並且每個字節都是 ASCII 字元 0-9 或 AF,那麼也許您應該假設您正在查看 32 字節值的十六進制編碼,而不是恰好適合這個的 64 字節二進製字元串偶然的描述。

您應該嘗試不同的編碼方法。計算輸出中唯一字元的數量是另一個很好的啟發式方法,這次用於猜測編碼方法。尋找編碼方法的其他顯著特徵,例如分隔符或填充字元。(以兩個等號結尾的字元串可能是 base64 的變體。雖然不太確定哪一個。有許多 base64 和 base32“字母表”可供選擇,因此您需要嘗試最常見的。)

您應該注意到,這本質上是一種蠻力方法。(除了密碼破解或暴力破解已知算法的密鑰之外,您正在針對許多可能的散列函式和編碼算法測試已知的輸入/輸出對。

這與Kerckhoffs 原理相比是倒退的。(密碼系統應該是安全的,即使系統的所有內容,除了密鑰,都是公共知識。)嘗試使用您想出的一些混淆方法來保護自己通常被稱為“通過默默無聞的安全性”。通過默默無聞的“安全性”並不是很好的安全性,但它可能會使某人的工作更加困難。以這個問題為例。

有很多方法可以混淆雜湊輸出或使用的雜湊算法。不常見的文本編碼、字元替換、字元轉置、雙散列、在散列之前加密輸入、加密散列函式的輸出。如果您想要壞主意,請查看人們提出的“聰明”密碼雜湊解決方案。(就像在 PHP 文件註釋部分中一樣,假設他們沒有清理它。)

如果您想讓外人難以計算您的雜湊函式,那麼使用秘密算法有更好的選擇。您可以使用帶有密鑰的公共(安全)算法。以 HMAC 為例。這樣做的好處是更容易安全地實施。它並不要求每個可能想要破解你的人都比你“聰明”得多。

儘管 HMAC 只是一種算法(它使用您選擇的散列函式),但您可以將每個具有不同鍵的 HMAC 實例視為一個單獨的散列函式,即使每個實例都使用相同的散列算法。(HMAC 有個怪癖,就是有等效的密鑰,但隨機生成的密鑰不是安全問題。)

將一個散列函式轉換為一系列散列函式的其他方法包括加鹽、個性化字元串和非標準 IV。

加鹽通常是指不需要保密的值。非標準 IV 可能使安全算法不安全。個性化字元串與鹽幾乎相同。

由於暴力破解許多不同的散列函式、編碼和附加輸入可能是確定散列函式的最佳方法,因此使用具有足夠熵的密鑰將無法在不破解保護密鑰的系統的情況下“獲取”該函式。對於這篇文章,我假設獲取意味著您完全了解如何為任何輸入計算相同的輸入/輸出對。

重要提示:密碼應使用 Argon2 或 bcrypt 等算法進行散列,使用不可預測的全域唯一鹽。通過使用受 HSM 保護的密鑰進行加密,可以隱藏這些函式的 salt 和輸出。這實際上提供了比僅使用加鹽密碼拉伸雜湊算法所能獲得的更高程度的安全性。它不是通過默默無聞的安全性,因為它只需要正確實施的算法和對關鍵材料的保護。

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