1. 程式人生 > >怎樣的 Hash 演算法能對抗硬體破解

怎樣的 Hash 演算法能對抗硬體破解

前言

用過暴力破解工具 hashcat 的都知道,這款軟體的強大之處在於它能充分利用 GPU 計算,比起 CPU 要快很多。所以在破解諸如 WiFi 握手包、資料庫中的口令 Hash 值時,能大幅提高計算效率。

當然 GPU 仍屬於通用硬體,顯然還不是最優化的。要是為特定的演算法打造特定的硬體,效率更是高出幾個量級。比特幣礦機就是很好的例子。

硬體的仍在不斷進步,系統安全等級若不提高,暴力破解將會越來越容易。因此,一種能抵抗「硬體破解」的 Hash 演算法,顯得很有必要。

時間成本

在探討如何對抗硬體之前,先來講解過去是如何對抗「暴力破解」的。

一些經典的 Hash 演算法,例如 MD5、SHA256 等,計算速度是非常快的。如果口令 Hash 用了這類函式,將來攻擊者跑字典時,可達到非常高的速度。那些強度不高的口令,很容易被破解。

為了緩解這種狀況,密碼學家引入了「拉伸」的概念:反覆 Hash 多次,從而增加計算時間。

例如 PBKDF2 演算法就運用了這種思想。它的原理很簡單,對指定函式 F 反覆進行 N 次:

function PBKDF2(F, ..., N)
    ...
    for i = 0 to N
        ...
        x = F(x, ...)
        ...
    ...
    return x

這樣就能靈活設定 Hash 的時間成本了。例如設定 10000,對開發者來說,只是多了幾十毫秒的計算;但對於攻擊者,破解速度就降低了一萬倍!

時間成本侷限性

PBKDF2 確實有很大的效果,但對於硬體破解,卻無任何對抗措施。

因為 PBKDF2 只是對原函式簡單封裝,多執行幾次而已。如果原函式不能對抗硬體,那麼套一層 PBKDF2 同樣也不能。

例如 WiFi 的 WPA2 協議,就是讓 HMAC-SHA1 重複執行 4096 次:

DK = PBKDF2(HMAC−SHA1, Password, SSID, 4096, ...)

雖然相比單次 Hash 要慢上幾千倍,但這並不妨礙硬體破解。

硬體依然可發揮其「高併發」優勢,讓每個執行緒分別計算不同口令的 PBKDF2:

執行緒 計算
1 PBKDF2(..., "12345678", 4096, ...) == KEY
2 PBKDF2(..., "00000000", 4096, ...) == KEY
... ...
100 PBKDF2(..., "88888888", 4096, ...) == KEY

雖然耗時確實增加了很多倍,但並沒有影響到硬體的發揮。同樣的破解,效率仍然遠高於 CPU。

所以,時間成本並不能抵抗硬體破解。

空間成本

單論計算效能,硬體是非常逆天的,但再綜合一些其他因素,或許就未必那麼強大了。

假如某個硬體可開啟 100 個執行緒同時破解,但總記憶體卻只有 100M —— 這顯然是個很大的短板。

如果有種 PBKDF 演算法空間複雜度為 2M,那將會有一半的執行緒,因記憶體不足而無法執行!

若再極端些,將空間複雜度提高到 100M,那麼整個硬體只能開啟 1 個執行緒,99% 的算力都無法得到發揮!

這樣,即使硬體的計算效能再強勁,也終將卡在記憶體這個瓶頸上。

不過,怎樣才能讓演算法消耗這麼多記憶體,同時又不能被輕易繞過?這裡舉個簡單的例子:

function MemoryHard(..., M)
    int space[M]

    for i = 0 .. 10000
        x = Hash(x, ...)
        space[int(x) % M] ^= int(x)

    return Hash(space)

當然這個例子是隨意寫的,並不嚴謹。但主要思想是:

  • 引入了空間成本 M,並申請相應的記憶體

  • 利用經典 Hash 函式的結果,作為陣列索引,對記憶體進行讀寫

  • 每次記憶體讀寫,都會影響到最終結果

由於 Hash 函式的結果是不可預測的,因此事先無法知道哪些位置會被訪問。只有準備充足的記憶體,才能達到 O(1) 的訪問速度。

攻擊者要想達到同樣的速度,就不得不花費同樣多的記憶體!

時空權衡

通常硬體的「計算資源」要比「儲存資源」充足得多,因此可考慮「時間換空間」的策略 —— 使用更復雜的儲存管理機制,從而減少空間分配,這樣就能開啟更多的執行緒。

比如犧牲 40% 的速度,換取 50% 的空間:

方案 可用記憶體 空間分配 可用執行緒 單執行緒速度 總速度
A 1000M 100M 10 / 100 10 hash/s 100 hash/s
B 1000M 50M 20 / 100 6 hash/s 120 hash/s

由於空間成本是之前的一半,因此可多啟動一倍的執行緒。算上折損,最終速度仍增加了 20%。

當然,如果 效能折損比例 > 空間壓縮比例,這個方案就沒有意義了。

訪問瓶頸

事實上,記憶體除了容量外,訪問頻率也是有限制的。

就記憶體本身而言,每秒讀寫次數是有上限的。其次,計算單元和記憶體之間的互動,更是一大瓶頸。

像 MD5、SHA256 這類 Hash 函式,空間複雜度非常低。硬體破解時,每個計算單元光靠自身的暫存器以及快取記憶體,就差不多夠用了,很少需要訪問記憶體。

但對於 Memory-Hard 函式,就沒那麼順利了。它不僅很佔記憶體,而且還十分頻繁地「隨機訪問」記憶體,因此很難命中快取記憶體。這使得每次訪問,幾乎都會和記憶體進行互動,從而佔用大量頻寬。

如果有多個計算單元頻繁訪問,那麼記憶體頻寬就會成為瓶頸。這樣,也能起到抑制併發的效果!

例如 bcrypt 演算法就運用了類似思想,它在計算過程中頻繁訪問 4KB 的記憶體空間,從而消耗頻寬資源。

不過隨著硬體發展,bcrypt 的優勢也在逐漸降低。為了能更靈活地設定記憶體大小,scrypt 演算法出現了 —— 它既有時間成本,還有空間成本,這樣就能更持久地對抗。

當然,空間成本也不是絕對有效的。如果攻擊者不惜代價,製造出儲存「容量」和「頻寬」都很充足的硬體裝置,那麼仍能高效地進行破解。

並行維度

十幾年來,記憶體容量翻了好幾翻,但 CPU 主頻卻沒有很大提升。由於受到物理因素的制約,主頻已很難提升,只能朝著多核發展。

然而像 PBKDF2 這樣的演算法,卻只能使用單執行緒計算 —— 因為它每次 Hash 都依賴上一次的 Hash 結果。這種序列的模式,是無法拆解成多個任務的,也就無法享受多執行緒的優勢。

這就意味著 —— 時間成本,終將達到一個瓶頸!

對此,多執行緒真的無能為力嗎?

儘管單次 PBKDF 不能被拆解,但可以要求多次 PBKDF,並且互相沒有依賴。這樣多執行緒就能派上用場了。

例如我們對 PBKDF 進行封裝,要求執行 4 次完全獨立的計算,最後再將結果融合到一起:

function Parall(Password, Salt, ...)

    -- 該部分可被並行 --
    for i = 0 .. 4
        DK[i] = PBKDF(Password, Salt + i, ...)
    ------------------

    return Hash(DK)

這樣,我們即可開啟 4 個執行緒,同時計算這 4 個 PBKDF。

現在就能用 1 秒的時間,獲得之前 4 秒的強度!攻擊者破解時,成本就增加了 4 倍。

如今主流的口令 Hash 函式都支援「並行維度」。例如 scrypt 以及更先進的 argon2,都可通過引數 p 設定。

執行緒開銷

現實中,「執行緒數」未必要和「並行維度」一樣多,因為還得考慮「空間成本」。

假設上述的 PBKDF 空間成本有 512MB,如果開啟 4 個執行緒,就得佔用 2GB 的記憶體!若使用者只有 1.5 GB 的空閒記憶體,還不如只開 2 個執行緒,反而會更順暢。

當然,也可以開 3 個執行緒,但這樣會更快嗎?顯然不會!

因為 4 個任務分給 3 個執行緒,總有一個執行緒得做兩份,所以最終用時並沒有縮短。反而增加了執行緒建立、記憶體申請等開銷。

大家可體會下 時空成本(N)、並行維度(P)、執行緒數(Thread)對計算的影響。

小結

到此,我們講解了 3 個對抗破解的因素:

  • 時間成本(迭代次數)

  • 空間成本(記憶體容量、頻寬)

  • 並行維度(多執行緒資源)

或許你已感悟到這其中的理念 —— 讓 Hash 演算法牽涉更多的硬體能力。這樣,只有綜合性能高的硬體,才能順利執行;專為某個功能打造的硬體,就會出現瓶頸!

照這個思路,我們也可發揮想象:假如有個演算法使用了不少條件分支指令,而 CPU 正好擁有強大的分支預測功能。這樣該演算法在 CPU 上執行時,就能獲得很高的效能;而在其他精簡過的硬體上,就沒有這麼好的效果了。

當然這裡純屬想象,自創密碼學演算法是不推薦的。現實中還是得用更權威的演算法,例如 argon2、scrypt 等。

應用

本文提到的對抗方案,都是從硬體消耗上進行的。不過,這樣傷敵一千也會自損八百。

假如伺服器每 Hash 一次口令,就得花 1 秒時間加 1GB 記憶體,那麼一旦有幾十個人同時訪問,系統可能就支撐不住了。

有什麼辦法,既能使用高成本的 Hash,又不耗費伺服器資源?事實上,口令 Hash 完全可以在客戶端計算:

DK = Client_PBKDF(Password, Username, Cost ...)

因為口令與 DK 的對應關係是唯一的。賬號註冊時,提交的就是 DK;登入時,如果提交的 DK 相同,也就證明口令是相同的。

所以客戶端無需提供原始口令,服務端也能認證。使用這種方案,還能進一步減少口令洩露的環節,例如網路被竊聽、服務端惡意程式等。

當然,服務端收到 DK 後,還不能立即儲存。因為萬一 DK 洩露了,攻擊者還是能用它登上使用者的賬號,儘管不知道口令。

因此,服務端需對 DK 再進行 Hash 處理。

不過這一次,只需快速的 Hash 函式即可。因為 DK 是無規律的資料(熵很高),無法通過跑字典還原,所以用簡單的 Hash 就能保護。

這樣,伺服器只需極小的計算開銷,就能實現高強度的口令安全了!

將來即使被拖庫,攻擊者也只能使用如下 Hash 函式跑字典:

f(x) => server_hash( client_hash(x) )

因為其中用到了 client_hash,所以這個最終函式同樣能對抗硬體破解!

用以模擬被入侵的場景。大家可嘗試破解其中弱口令,看看需要多少時間。

相關推薦

怎樣的 Hash 演算法對抗硬體破解

前言 用過暴力破解工具 hashcat 的都知道,這款軟體的強大之處在於它能充分利用 GPU 計算,比起 CPU 要快很多。所以在破解諸如 WiFi 握手包、資料庫中的口令 Hash 值時,能大幅提高計算效率。 當然 GPU 仍屬於通用硬體,顯然還不是最優化的。要是為特定的演算法打造特定的硬體,效率更是高出幾

Python演算法筆試題目,破解Hash值,N進製法

Find the string whichhas this hash: 25267566250558 The string has length8. Characters can befrom: c,e,i,a,r,w,u,s,p The hash functionworks like

2018最新淘寶面試出爐:分散式鎖+叢集+一致Hash演算法+底層技術原理

是需要掌握牢固,重點會問HashMap等集合類,以及多執行緒、執行緒池等。   原文連結:https://blog.csdn.net/SpringJavaMyBatis/article/details/83415696     &n

關於什麼是一致性hash演算法

當需要分散式快取的時候,通過key的hash值分散資料儲存hash(n)%快取伺服器臺數,同時也可以快速查詢資料而不用遍歷所有的伺服器。如下圖: 但是這樣,當業務拓展想要增加一臺伺服器的話,要麼快取伺服器資料全部需要重新計算儲存 -----hash(n)%5 。 要麼需要遍歷所有快取伺服器。不夠靈活。

Hash演算法的講解

     散列表,又叫雜湊表,它是基於快速存取的角度設計的,也是一種典型的“空間換時間”的做法。顧名思義,該資料結構可以理解為一個線性表,但是其中的元素不是緊密排列的,而是可能存在空隙。       散列表

一致性Hash演算法的深入理解

總結: 1、使用一致性Hash演算法,儘管增強了系統的伸縮性,但是也有可能導致負載分佈不均勻,解決辦法就是使用虛擬節點代替真實節點,  2、Hash演算法的選擇上,首先我們考慮簡單的String.HashCode()方法,這個演算法的缺點是,相似的字串如N1(10.0.

Java中的HashCode 1 之hash演算法基本原理

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

學習筆記(六):使用隨機森林演算法檢測FTP暴力破解

1.資料蒐集:         載入ADFA-LD中正常資料         定義遍歷目錄下檔案         從攻擊資料中篩選出和FTP暴力破解有關的資料 &n

學習筆記(五):使用決策樹演算法檢測POP3暴力破解

1.資料蒐集     載入KDD 99中的資料: def load_kdd99(filename): x=[] with open(filename) asf: for line in f: line=line.st

logging日誌模組,re正則表示式模組,hashlib hash演算法相關的庫,

logging: 功能完善的日誌模組 import logging #日誌的級別 logging.debug("這是個除錯資訊")#級別10 #常規資訊 logging.info("常規資訊")#20 #警告資訊 logging.warning("警告

memcache客戶端實現叢集之一致性hash演算法

一致性雜湊的演算法把取餘演算法的等於號來選擇mem伺服器變成了大於號來選擇mem伺服器,這應該是才是關鍵,可以使一個鍵的mem伺服器落點變成是動態選擇(一個伺服器down掉然後選擇crc32(key)後大於這個伺服器的落點....) 新增虛擬節點,虛擬節點其實還是原來那幾臺伺服器,每個虛擬節

linux核心netfilter連線跟蹤的hash演算法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

分散式演算法(一致性Hash演算法)

一、分散式演算法     在做伺服器負載均衡時候可供選擇的負載均衡的演算法有很多,包括: 輪循演算法(Round Robin)、雜湊演算法(HASH)、最少連線演算法(Least Connection)、響應速度演算法(Response Time)、加權法

【轉】【java原始碼分析】Map中的hash演算法分析

全網把Map中的hash()分析的最透徹的文章,別無二家。 2018年05月09日 09:08:08 閱讀數:957 你知道HashMap中hash方法的具體實現嗎?你知道HashTable、ConcurrentHashMap中hash方法

HDU 1686 Oulipo (hash演算法

Oulipo Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2553  

一致性hash演算法程式碼實現

什麼是一致性hash 一致性雜湊演算法(Consistent Hashing Algorithm)是一種分散式演算法,常用於負載均衡。Memcached client也選擇這種演算法,解決將key-value均勻分配到眾多Memcached server上的問題。它可以取代傳統的取模操作

HashMap中的hash演算法總結

前言 演算法一直是我的弱項,然而面試中基本是必考的專案,剛好上次看到一個HashMap的面試題,今天也來學習下 HashMap中的hash演算法是如何實現的。 數學知識回顧 << : 左移運算子,num << 1,相當於num乘以2 低位補0 舉例:3 <<

如果目標資料是一段記憶體區的話,該使用什麼HASH演算法比較合適?

如果目標資料是一段記憶體區的話,該使用什麼HASH演算法比較合適?   演算法的選擇標準: 儘量在不同的輸入的情況下產生在合法區間的離散,不重複的輸出。   有兩種計算方法比較容易產生離散的輸出: 1.異或運算 2.區域性移位運算  

Java架構/一致性Hash演算法在資料庫分表中的實踐

最近有一個專案,其中某個功能單表資料在可預估的未來達到了億級,初步估算在90億左右。與同事詳細討論後,決定採用一致性Hash演算法來完成資料庫的自動擴容和資料遷移。整個程式細節由我同事完成,我只是將其理解併成文,供有相同問題的同行參考。 參看此文的兄弟,預設各位已經熟悉一致性hash

一致性Hash演算法在資料庫分表中的實踐

最近有一個專案,其中某個功能單表資料在可預估的未來達到了億級,初步估算在90億左右。與同事詳細討論後,決定採用一致性Hash演算法來完成資料庫的自動擴容和資料遷移。整個程式細節由我同事完成,我只是將其理解併成文,供有相同問題的同行參考。 參看此文的兄弟,預設各位已經熟悉一致性hash演算法了。此文僅僅闡述程式