一 ,到底什麼是hash呢?
hash(雜湊、雜湊)函式,是將任意長度的資料對映到有限長度的域上。直觀解釋起來,就是對一串資料m進行雜糅,輸出另一段固定長度的資料h,作為這段資料的特徵(指紋)。
也就是說,無論資料塊m有多大,其輸出值h為固定長度。到底是什麼原理?將m分成固定長度(如128位),依次進行hash運算,然後用不同的方法迭代即可(如前一塊的hash值與後一塊的hash值進行異或)。如果不夠128位怎麼辦?用0補全或者用1補全隨意,演算法中約定好就可以了。
原問題回答完畢。但是既然要說hash演算法,不妨說的更透徹些。
***************==分割線**********
由於用途的不同,hash在資料結構中的含義和密碼學中的含義並不相同,所以在這兩種不同的領域裡,演算法的設計側重點也不同。
預備小知識:
抗碰撞能力:對於任意兩個不同的資料塊,其hash值相同的可能性極小;對於乙個給定的資料塊,找到和它hash值相同的資料塊極為困難。
抗篡改能力:對於乙個資料塊,哪怕只改動其乙個位元位,其hash值的改動也會非常大。
在用到hash進行管理的資料結構中,比如hashmap,hash值(key)存在的目的是加速鍵值對的查詢,key的作用是為了將元素適當地放在各個桶裡,對於抗碰撞的要求沒有那麼高。換句話說,hash出來的key,只要保證value大致均勻的放在不同的桶裡就可以了。但整個演算法的set效能,直接與hash值產生的速度有關,所以這時候的hash值的產生速度就尤為重要,以jdk中的string.hashcode()方法為例:
public int hashcode()
hash = h;
}return h;
}很簡潔的乙個乘加迭代運算,在不少的hash演算法中,使用的是異或+加法進行迭代,速度和前者差不多。
在密碼學中,hash演算法的作用主要是用於訊息摘要和簽名,換句話說,它主要用於對整個訊息的完整性進行校驗。舉個例子,我們登陸知乎的時候都需要輸入密碼,那麼知乎如果明文儲存這個密碼,那麼黑客就很容易竊取大家的密碼來登陸,特別不安全。那麼知乎就想到了乙個方法,使用hash演算法生成乙個密碼的簽名,知乎後台只儲存這個簽名值。由於hash演算法是不可逆的,那麼黑客即便得到這個簽名,也絲毫沒有用處;而如果你在**登陸介面上輸入你的密碼,那麼知乎後台就會重新計算一下這個hash值,與**中儲存的原hash值進行比對,如果相同,證明你擁有這個賬戶的密碼,那麼就會允許你登陸。銀行也是如此,銀行是萬萬不敢儲存使用者密碼的原文的,只會儲存密碼的hash值而而已。
在這些應用場景裡,對於抗碰撞和抗篡改能力要求極高,對速度的要求在其次。乙個設計良好的hash演算法,其抗碰撞能力是很高的。以md5為例,其輸出長度為128位,設計預期碰撞概率為,這是乙個極小極小的數字——而即便是在md5被王小雲教授破解之後,其碰撞概率上限也高達,也就是說,至少需要找次才能有1/2的概率來找到乙個與目標檔案相同的hash值。而對於兩個相似的字串,md5加密結果如下:
md5("version1") = "966634ebf2fc135707d6753692bf4b1e";
md5("version2") = "2e0e95285f08a07dea17e7ee111b21c8";
可以看到僅僅乙個位元位的改變,二者的md5值就天差地別了。
二,什麼是hash碰撞呢?怎麼處理?
如果兩個輸入串的hash函式的值一樣,則稱這兩個串是乙個碰撞(collision)。既然是把任意長度的字串變成固定長度的字串,所以必有乙個輸出串對應無窮多個輸入串,碰撞是必然存在的。
乙個優良的hash函式 f 應當滿足以下三個條件:
(1)對於任意y,尋找x,使得f(x)=y,在計算上是不可行的。
(2)給定x1∈a,找x2∈b,,使得f(x1)=f(x2),在計算上是不可能的,這也就是弱無碰撞性。
(3)尋找x1,x2,使得f(x1)=f(x2),在計算上也是不可行的,這也就是強無碰撞性。
這樣就稱為安全保密的hash函式,除了列舉外不可能有別的更快的方法。如第3條,根據生日定理,要想找到這樣的x1,x2,理論上需要大約2^(n/2)的列舉次數。
因為前兩條都能被破壞的hash函式太弱而被拋棄,幾乎所有的hash函式的破解,都是指的破壞上面的第3條性質,即找到乙個碰撞。在密碼學上還有乙個概念是理論破解,指的是提出乙個演算法,使得可以用低於理論值得列舉次數找到碰撞。
4、碰撞處理
通常有兩類方法處理碰撞:開放定址(open addressing)法和鏈結(chaining)法。前者是將所有結點均存放在雜湊表t[0..m-1]中;後者通常是把雜湊到同一槽中的所有元素放在乙個鍊錶中,而將此鍊錶的頭指標放在雜湊表t[0..m-1]中。
(1)開放定址法
所有的元素都在雜湊表中,每乙個表項或包含動態集合的乙個元素,或包含nil。這種方法中雜湊表可能被填滿,以致於不能插入任何新的元素。在開放定址法中,當要插入乙個元素時,可以連續地檢查或探測雜湊表的各項,直到有乙個空槽來放置待插入的關鍵字為止。有三種技術用於開放定址法:線性探測、二次探測以及雙重探測。
<1>線性探測
給定乙個普通的雜湊函式h':u —>,線性探測方法採用的雜湊函式為:h(k,i) = (h'(k)+i)mod m,i=0,1,....,m-1
探測時從i=0開始,首先探查t[h'(k)],然後依次探測t[h'(k)+1],…,直到t[h'(k)+m-1],此後又迴圈到t[0],t[1],…,直到探測到t[h'(k)-1]為止。探測過程終止於三種情況:
(1)若當前探測的單元為空,則表示查詢失敗(若是插入則將key寫入其中);
(2)若當前探測的單元中含有key,則查詢成功,但對於插入意味著失敗;
(3)若探測到t[h'(k)-1]時仍未發現空單元也未找到key,則無論是查詢還是插入均意味著失敗(此時表滿)。
線性探測方法較容易實現,但是存在一次群集問題,即連續被占用的槽的序列變的越來越長。採用例子進行說明線性探測過程,已知一組關鍵字為(26,36,41,38,44,15,68,12,6,51),用除餘法構造雜湊函式,初始情況如下圖所示:
雜湊過程如下圖所示:
<2>二次探測
二次探測法的探查序列是:h(k,i) =(h'(k)+i*i)%m ,0≤i≤m-1 。初次的探測位置為t[h'(k)],後序的探測位置在次基礎上加乙個偏移量,該偏移量以二次的方式依賴於i。該方法的缺陷是不易探查到整個雜湊空間。
<3>雙重雜湊
該方法是開放定址的最好方法之一,因為其產生的排列具有隨機選擇的排列的許多特性。採用的雜湊函式為:h(k,i)=(h1(k)+ih2(k)) mod m。其中h1和h2為輔助雜湊函式。初始探測位置為t[h1(k)],後續的探測位置在此基礎上加上偏移量h2(k)模m。
(2)鏈結法
將所有關鍵字為同義詞的結點鏈結在同乙個鍊錶中。若選定的雜湊表長度為m,則可將雜湊表定義為乙個由m個頭指標組成的指標陣列t[0..m-1]。凡是雜湊位址為i的結點,均插入到以t[i]為頭指標的單鏈表中。t中各分量的初值均應為空指標。在拉鍊法中,裝填因子α可以大於1,但一般均取α≤1。
最終結果如下圖所示:
三 ,為什麼hashmap初始容量是2<<4 ?
如果兩個元素不相同,但是hash函式的值相同,這兩個元素就是乙個碰撞
因為把任意長度的字串變成固定長度的字串,所以存在乙個hash對應多個字串的情況,所以碰撞必然存在
為了減少hash值的碰撞,需要實現乙個盡量均勻分布的hash函式,在hashmap中通過利用key的hashcode值,來進行位運算
公式:index = e.hash & (newcap - 1)
舉個例子:
1.計算"book"的hashcode
十進位制 : 3029737
二進位制 : 101110001110101110 1001
2.hashmap長度是預設的16,length - 1的結果
十進位制 : 15
二進位制 : 1111
3.把以上兩個結果做與運算
101110001110101110 1001 & 1111 = 1001
1001的十進位制 : 9,所以 index=9
hash演算法最終得到的index結果,取決於hashcode值的最後幾位
為了推斷hashmap的預設長度為什麼是16
現在,我們假設hashmap的長度是10,重複剛才的運算步驟:
hashcode : 101110001110101110 1001
length - 1 : 1001
index : 1001
再換乙個hashcode 101110001110101110 1111 試試:
hashcode : 101110001110101110 1111
length - 1 : 1001
index : 1001
從結果可以看出,雖然hashcode變化了,但是運算的結果都是1001,也就是說,當hashmap長度為10的時候,有些index結果的出現機率
會更大而有些index結果永遠不會出現(比如0111),這樣就不符合hash均勻分布的原則
反觀長度16或者其他2的冪,length - 1的值是所有二進位制位全為1,這種情況下,index的結果等同於hashcode後幾位的值
只要輸入的hashcode本身分布均勻,hash演算法的結果就是均勻的
所以,hashmap的預設長度為16,是為了降低hash碰撞的機率
攻破 MD5 SHA1 強抗碰撞性。
github 傳送門 兩個不同的pdf,計算sha1摘要時,發現sha1摘要是一樣的,哈哈,是不是很神奇?經過精心構造,兩個pdf檔案 shattered 1.pdf 與 shattered 2.pdf 的sha1摘要完全一致。pdf的格式 簡單的拆分下 刪除兩個pdf中不同的資料之後,得到兩個檔案...
Hash演算法與Hash碰撞
什麼是hash演算法。雜湊函式 英語 hash function 又稱雜湊演算法 雜湊函式,是一種從任何一種資料中建立小的數字 指紋 的方法。雜湊函式把訊息或資料壓縮成摘要,使得資料量變小,將資料的格式固定下來。該函式將資料打亂混合,重新建立乙個叫做雜湊值 hash values,hash code...
增強Sendmail的抗DoS攻擊能力
還記得yahoo,ebay.受到的拒絕服務 denial of service 攻擊嗎?當然,他們遭受的只是web服務的dos攻擊。其實從最根本上來講,各種拒絕服務攻擊都是攻擊目標的tcp ip協議堆疊,並不是什麼很特殊的運用方式,其目的都是讓伺服器癱瘓,無法工作。之所以這類攻擊能容易得逞,是因為當...