關於哈希演算法

哈希演算法有時候被稱之為摘要,這個比喻有點不精確,因為摘要畢竟還是要讓人看懂的,而哈希演算法後的數字,人是完全讀不懂的。而且我們哈希後的字元串可能比原文還要長,所以這個比喻不太恰當。

簡單來說,通過哈希演算法:

  1. 同樣的輸入一定會有同樣的輸出。但你拿輸出要想還原輸入則不可能。
  2. 無論多長或者多短的輸入,輸出都是一樣長的。
  3. 改動一點點,輸出就會完全不一樣,且毫無規律。

用點例子就秒懂了。

from hashlib import sha256nnmy_string = "Hello"nsha256_digest = sha256(my_string).hexdigest()nprint sha256_digestn

我們這裡用Python現成的庫來實驗SHA256演算法。

運行結果:

輸出:185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969

完全看不懂是什麼,重點是當我們知道輸出是185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969

完全沒辦法還原成原始信息Hello,但這不是隨機數。

只要輸入信息一致,結果肯定是完全一樣:

same_string="Hello"nsha256_digest = sha256(same_string).hexdigest()nprint sha256_digestn

如果輸入有哪怕一點點小小的不一樣,結果會完全不同,並且完全無法預測。

diff="hello"nsha256_digest = sha256(diff).hexdigest()nprint sha256_digestn

只是把Hello的第一個字母改成小寫的h,兩者的結果完全看不出聯繫。

2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824這個結果和185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969是看不出啥聯繫的,這個效應稱之為「雪崩效應」。

也就是說,哪怕任何一點點不同的輸入都能保證有不同的輸出,並且不可逆。

並且,長度不一樣的信息哈希後,長度是一致的。

long_string="The quick brown fox jumps over the lazy dog"nsha256_digest = sha256(long_string).hexdigest()nprint sha256_digestn

不同長度的字元串哈希後,結果的長度是一致的。

這裡有個問題,輸出的字元串的長度必然是一致的話,哈希的結果應該是有窮的。但我們輸入的信息可能性是無窮的,這意味著必然有「撞車」事件發生。理論上是的,但不必擔心,這種事情發生的概率很小,可以忽略不計。

哈希演算法的用處很多,比如我們驗證文件下載是否完整時,就會應用到。因為哪怕一個位元組有不一樣,雪崩效應也會讓哈希後的值完全不一樣,所以哈希值一樣可以保證你下載的文件和上傳者的完全一致。

這裡的SHA1值就是一個哈希值,下載完文件後跑同樣的演算法,如果結果和這個一致,那就證明一個位元組都不差,可以放心。

另外一個比較多的應用場景是儲存你的密碼,你在註冊一個網站的時候,網站後台的資料庫是不存儲你的密碼的,因為這樣做不安全。萬一網站的資料庫被泄露了,用戶的密碼就都泄露了,但網站又要驗證你的密碼,怎麼辦呢?用哈希演算法。

第一次註冊的時候,你的密碼哈希後存儲在資料庫里,當你下次登錄的時候密碼再哈希一次,和存儲的哈希值對比。如果完全一致,這證明密碼鍵入和註冊的時候一樣。這樣網站不用知道你的密碼,還能驗證你的密碼。

考慮到有些用戶的密碼十分簡單,大量使用諸如abcd1234這樣的密碼,那我們事先把常用的密碼哈希過後結果存起來,和網站泄露的資料庫一對比,就能知道用戶的密碼是什麼了。這種攻擊方法確實存在,應對的辦法是「加鹽」,用戶註冊密碼的時候,在密碼後追加一個字元串,只有網站自己知道。驗證的時候同樣追加一個字元串,這樣密碼一致的時候,哈希值也會是一樣的。但是攻擊者不知道鹽是什麼樣的字元串,這種攻擊也就無效了。

關於哈希演算法的其他應用還有很多,重點了解數字簽名演算法。


推薦閱讀:

基礎優化-讓哈希表更公平一些
Bloom filter(布隆過濾器)和普通hash表對於碰撞和存儲空間的不同?
Purple Rain:一種新型哈希破解方法
為什麼比特幣的block產生速度被設定為10分鐘?

TAG:哈希函数 | 加密 |