散列函數(Hash function)又稱散列算法、哈希函數,散列函數把消息或數據壓縮成摘要,使得數據量變小,將數據的格式固定下來。該函數將數據打亂混合,重新創建一個叫做散列值(hash values)的指紋。這種轉化是一種壓縮映射,也就是散列值的空間通常遠小於輸入值的空間,不同的輸入可能會散列成相同的輸出,二不可能從散列值來唯一的確定輸入值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要函數。
散列函數性質
通過使用單向散列函數,即便是確認幾百MB大小的文件的完整性,也只要對比很短的散列值就可以了。那么,單向散列函數必須具備怎樣的性質呢?我們來整理一下。
-
根據任意長度的消息計算出固定長度的散列值
-
能夠快速計算出散列值
計算散列值所花費的時間短。盡管消息越長,計算散列值的時間也會越長,但如果不能在現實的時間內完成計算就沒有意義了。
-
消息不同散列值也不同
-
難以發現碰撞的性質稱為抗碰撞性(collisionresistance)。密碼技術中所使用的單向散列函數,都需要具備抗碰撞性。強抗碰撞性,是指要找到散列值相同的兩條不同的消息是非常困難的這一性質。在這里,散列值可以是任意值。密碼技術中的單向散列函數必須具備強抗碰撞性。
-
具備單向性
單向散列函數必須具備單向性(one-way)。單向性指的是無法通過散列值反算出消息的性質。根據消息計算散列值可以很容易,但這條單行路是無法反過來走的。
散列函數的應用
散列函數應用具有多樣性
安全加密:
- 保護資料,散列值可用於唯一地識別機密信息。這需要散列函數是抗碰撞(collision-resistant)的,意味着很難找到產生相同散列值的資料。如數字簽名、消息認證碼。
數據校驗:
- 確保傳遞真實的信息:消息或數據的接受者確認消息是否被篡改的性質叫數據的真實性,也稱為完整性。
- 錯誤校正:使用一個散列函數可以很直觀的檢測出數據在傳輸時發生的錯誤。
負載均衡:
- 通過hash算法,對客戶端IP進行計算hash值,將取到值與服務器數量進行取模運算。
分布式存儲:如一致性hash。
常用單項散列函數
MD4 MD5
MD5在1996年后被證實存在弱點,可以被加以破解,對於需要高度安全性的資料,專家一般建議改用其他算法,如SHA-2。2004年,證實MD5算法無法防止碰撞攻擊,因此不適用於安全性認證,如SSL公開密鑰認證或是數字簽名等用途。
SHA-1 SHA-2
SHA-1:1995年發布,SHA-1在許多安全協議中廣為使用,包括TLS、GnuPG、SSH、S/MIME和IPsec,是MD5的后繼者。但SHA-1的安全性在2010年以后已經不被大多數的加密場景所接受。2017年荷蘭密碼學研究小組CWI和Google正式宣布攻破了SHA-1。
SHA-2:2001年發布,包括SHA-224
、SHA-256
、SHA-384
、SHA-512
、SHA-512/224
、SHA-512/256
。SHA-2目前沒有出現明顯的弱點。雖然至今尚未出現對SHA-2有效的攻擊,但它的算法跟SHA-1基本上仍然相似。 比特幣使用的sha-256進行的數字簽名
算法和變體 | 輸出散列值長度 (bits) | 中繼散列值長度 (bits) | 資料區塊長度 (bits) | 最大輸入消息長度 (bits) |
---|---|---|---|---|
MD5 | 128 | 128 (4 × 32) | 512 | 無限 |
SHA-0 | 160 | 160 (5 × 32) | 512 | 264 − 1 |
SHA-1 | 160 | 160 (5 × 32) | 512 | 264 − 1 |
SHA-2 | SHA-224 SHA-256 | 224 256 | 256 (8 × 32) | 512 |
SHA-384 SHA-512 SHA-512/224 SHA-512/256 | 384 512 224 256 | 512 (8 × 64) | 1024 | 2128 − 1 |
Go語言中使用散列函數
Go語言使用MD5
方式一:
md5.Sum("123")
方式2:
func getMD5_2(str []byte) string {
// 1. 創建一個使用MD5校驗的Hash對象`
myHash := md5.New()
// 2. 通過io操作將數據寫入hash對象中
io.WriteString(myHash, "hello")
//io.WriteString(myHash, ", world")
myHash.Write([]byte(", world"))
// 3. 計算結果
result := myHash.Sum(nil)
fmt.Println(result)
// 4. 將結果轉換為16進制格式字符串
res := fmt.Sprintf("%x", result)
fmt.Println(res)
// --- 這是另外一種格式化切片的方式
res = hex.EncodeToString(result)
fmt.Println(res)
return res
}
Go語言SHA-1、SHA-2的使用
方法一:
sha512.Sum512()
sha256.Sum256()
方法二與md5的使用類似